Skip to content

Calling the GOSQAS backend

Harry Pierson edited this page Dec 5, 2023 · 5 revisions

The new GOSQAS backend is implemented with Azure Functions. This wiki page describes how to interact with this backend via TypeScript.

Note, there is a test deployment of this backend, but any provenance data published to this endpoint will be destroyed prior to release of GOSQAS 2.0.

The base URL of the test deployment is https://gosqasbe.azurewebsites.net/api.

Device Key

All data stored in the GOSQAS backend is encrypted with an AES-CBC key (128-, 192- and 256-bit key lengths are all supported). The device key is passed as a URL parameter to all the endpoints listed below. The device key is Base-58 encoded for use as a URL parameter.

Here is some example code for generating and encoding a 128-bit device key in Typescript using the WebCrypto API (also available in NodeJS) and the @urlpack/base58 package.

import {encode as base58encode } from '@urlpack/base58'

export async function makeDeviceKey(): Promise<Uint8Array> {
  const key = await crypto.subtle.generateKey({
    name: "AES-CBC",
    length: 128
  }, true, ['encrypt', 'decrypt']);
  const buffer = await crypto.subtle.exportKey("raw", key);
  return new Uint8Array(buffer).slice();
}

function encodeDeviceKey(key: Uint8Array): string { 
  return base58encode(key); 
}

Provenance Records

GOSQAS will store any valid JSON as provenance record. GOSQAS accepts JSON5 encoded records, but converts all provided data to standard JSON before encrypting and storing.

Provenance Attachments

GOSQAS can optionally store multiple attachments for each provenance record. Attachments are encrypted and stored separately from the provenance record itself.

Note, GOSQAS stores the content type of the encrypted attachment as a metadata field, which is stored in the clear.

Timestamps

GOSQAS automatically timestamps all provenance records and attachments when they are submitted to the system.

Endpoints

getProvenance

Relative URL: /api/provenance/{deviceKey} HTTP Verb: GET

This endpoint retrieves the decrypted provenance records for a given device. As described above, the device key is a base58 encoded AES-CBC key. The endpoint returns an array of JSON encoded objects with the following structure:

{
    record: any, // whatever you passed to postProvenance
    attachments?: string[], // array of attachment IDs, may be empty or undefined
    timestamp: number // UTC epoch milliseconds when the record was submitted to GOSQAS
}

Sample TS code to invoke getProvenance via fetch:

// method takes the base58 encoded device key
async function getProvenance(deviceKey: string) {
    const response = await fetch(`${baseUrl}/provenance/${deviceKey}`, {
        method: "GET",
    });
    return await response.json() as { record: any, attachments?: string[], timestamp: number }[];
}

getAttachment

Relative URL: /attachment/{deviceKey}/{attachmentID} HTTP Verb: GET

This endpoint retrieves a single provenance attachment for a given device. In addition to the device key URL parameter, this endpoint requires an attachmentID parameter. This value is returned in the attachments array of a provenance record described above. The attachment is returned unencrypted as a blob with the content type that was specified when the record was created.

Sample TS code to invoke getAttachment via fetch:

async function getAttachment(deviceKey: string, attachmentID: string) {
    const response = await fetch(`${baseUrl}/attachment/${deviceKey}/${attachmentID}`, {
        method: "GET",
    });
    return await response.blob();
}

postProvenance

Relative URL: /api/provenance/{deviceKey} HTTP Verb: POST

This endpoint accepts a single provenance record for a given device, encrypts it and then stores it for future retrieval. The provenance record is encoded as multipart/form-data to enable submission of binary attachments. The FormData submitted to this endpoint must have the following structure:

  • provenanceRecord: a single form field containing a JSON (or JSON5) stringified object
  • attachment: zero or more binary Blobs

This endpoint will encrypt the provided record and all the attachments using the key provided. It returns the records string identifier as well as an optional array of strings containing the identifier for each attachment provided.

Sample TS code to invoke getAttachment via fetch:

async function postProvenance(deviceKey: string, record: any, attachments: readonly Blob[]) {
    const formData = new FormData();
    formData.append("provenanceRecord", JSON.stringify(record));
    for (const blob of attachments) {
        formData.append("attachment", blob);
    }
    const response = await fetch(`${baseUrl}/provenance/${deviceKey}`, {
        method: "POST",
        body: formData,
    });
    return await response.json() as { record: string, attachments?: string[] };
}