UNPKG

signify-ts

Version:

Signing at the edge for KERI, ACDC, and KERIA

304 lines (274 loc) 8.31 kB
import { SignifyClient } from './clienting'; import libsodium from 'libsodium-wrappers-sumo'; import { Salter } from '../core/salter'; import { Matter, MtrDex } from '../core/matter'; export function randomPasscode(): string { const raw = libsodium.randombytes_buf(16); const salter = new Salter({ raw: raw }); // https://github.com/WebOfTrust/signify-ts/issues/242 return salter.qb64.substring(2, 23); } export function randomNonce(): string { const seed = libsodium.randombytes_buf(libsodium.crypto_sign_SEEDBYTES); const seedqb64 = new Matter({ raw: seed, code: MtrDex.Ed25519_Seed }); return seedqb64.qb64; } export class Oobis { public client: SignifyClient; /** * Oobis * @param {SignifyClient} client */ constructor(client: SignifyClient) { this.client = client; } /** * Get the OOBI(s) for a managed indentifier for a given role * @param {string} name Name or alias of the identifier * @param {string} role Authorized role * @returns {Promise<any>} A promise to the OOBI(s) */ async get(name: string, role: string = 'agent'): Promise<any> { const path = `/identifiers/${name}/oobis?role=${role}`; const method = 'GET'; const res = await this.client.fetch(path, method, null); return await res.json(); } /** * Resolve an OOBI * @async * @param {string} oobi The OOBI to be resolver * @param {string} [alias] Optional name or alias to link the OOBI resolution to a contact * @returns {Promise<any>} A promise to the long-running operation */ async resolve(oobi: string, alias?: string): Promise<any> { const path = `/oobis`; const data: any = { url: oobi, }; if (alias !== undefined) { data.oobialias = alias; } const method = 'POST'; const res = await this.client.fetch(path, method, data); return await res.json(); } } export interface Operation<T = unknown> { name: string; metadata?: { depends?: Operation; [property: string]: any; }; done?: boolean; error?: any; response?: T; } export interface OperationsDeps { fetch( pathname: string, method: string, body: unknown, headers?: Headers ): Promise<Response>; } export interface AgentConfig { iurls?: string[]; } /** * Operations * @remarks * Operations represent the status and result of long running tasks performed by KERIA agent */ export class Operations { public client: OperationsDeps; /** * Operations * @param {SignifyClient} client */ constructor(client: OperationsDeps) { this.client = client; } /** * Get operation status * @async * @param {string} name Name of the operation * @returns {Promise<Operation>} A promise to the status of the operation */ async get<T = unknown>(name: string): Promise<Operation<T>> { const path = `/operations/${name}`; const data = null; const method = 'GET'; const res = await this.client.fetch(path, method, data); return await res.json(); } /** * List operations * @async * @param {string} type Select operations by type * @returns {Promise<Operation[]>} A list of operations */ async list(type?: string): Promise<Operation<any>[]> { const params = new URLSearchParams(); if (type !== undefined) { params.append('type', type); } const path = `/operations?${params.toString()}`; const data = null; const method = 'GET'; const res = await this.client.fetch(path, method, data); return await res.json(); } /** * Delete operation * @async * @param {string} name Name of the operation */ async delete(name: string): Promise<void> { const path = `/operations/${name}`; const data = null; const method = 'DELETE'; await this.client.fetch(path, method, data); } /** * Poll for operation to become completed. */ async wait<T>( op: Operation<T>, options: { signal?: AbortSignal; minSleep?: number; maxSleep?: number; increaseFactor?: number; } = {} ): Promise<Operation<T>> { const minSleep = options.minSleep ?? 10; const maxSleep = options.maxSleep ?? 10000; const increaseFactor = options.increaseFactor ?? 50; if (op.metadata?.depends?.done === false) { await this.wait(op.metadata.depends, options); } if (op.done === true) { return op; } let retries = 0; // eslint-disable-next-line no-constant-condition while (true) { op = await this.get(op.name); const delay = Math.max( minSleep, Math.min(maxSleep, 2 ** retries * increaseFactor) ); retries++; if (op.done === true) { return op; } await new Promise((resolve) => setTimeout(resolve, delay)); options.signal?.throwIfAborted(); } } } /** * KeyEvents */ export class KeyEvents { public client: SignifyClient; /** * KeyEvents * @param {SignifyClient} client */ constructor(client: SignifyClient) { this.client = client; } /** * Retrieve key events for an identifier * @async * @param {string} pre Identifier prefix * @returns {Promise<any>} A promise to the key events */ async get(pre: string): Promise<any> { const path = `/events?pre=${pre}`; const data = null; const method = 'GET'; const res = await this.client.fetch(path, method, data); return await res.json(); } } /** * KeyStates */ export class KeyStates { public client: SignifyClient; /** * KeyStates * @param {SignifyClient} client */ constructor(client: SignifyClient) { this.client = client; } /** * Retriene the key state for an identifier * @async * @param {string} pre Identifier prefix * @returns {Promise<any>} A promise to the key states */ async get(pre: string): Promise<any> { const path = `/states?pre=${pre}`; const data = null; const method = 'GET'; const res = await this.client.fetch(path, method, data); return await res.json(); } /** * Retrieve the key state for a list of identifiers * @async * @param {Array<string>} pres List of identifier prefixes * @returns {Promise<any>} A promise to the key states */ async list(pres: string[]): Promise<any> { const path = `/states?${pres.map((pre) => `pre=${pre}`).join('&')}`; const data = null; const method = 'GET'; const res = await this.client.fetch(path, method, data); return await res.json(); } /** * Query the key state of an identifier for a given sequence number or anchor * @async * @param {string} pre Identifier prefix * @param {number} [sn] Optional sequence number * @param {any} [anchor] Optional anchor * @returns {Promise<any>} A promise to the long-running operation */ async query(pre: string, sn?: string, anchor?: any): Promise<any> { const path = `/queries`; const data: any = { pre: pre, }; if (sn !== undefined) { data.sn = sn; } if (anchor !== undefined) { data.anchor = anchor; } const method = 'POST'; const res = await this.client.fetch(path, method, data); return await res.json(); } } export class Config { public client: SignifyClient; /** * Config * @param {SignifyClient} client */ constructor(client: SignifyClient) { this.client = client; } async get(): Promise<AgentConfig> { const path = `/config`; const method = 'GET'; const res = await this.client.fetch(path, method, null); return await res.json(); } }