signify-ts
Version:
Signing at the edge for KERI, ACDC, and KERIA
168 lines (140 loc) • 5.11 kB
text/typescript
import { Siger } from '../core/siger';
import { Cigar } from '../core/cigar';
export const FALSY = [false, 0, '?0', 'no', 'false', 'False', 'off'];
export const TRUTHY = [true, 1, '?1', 'yes', 'true', 'True', 'on'];
export class Signage {
constructor(
public readonly markers:
| (Siger | Cigar)[]
| Map<string, string | Siger | Cigar>,
public readonly indexed?: boolean,
public readonly signer?: string,
public readonly ordinal?: string,
public readonly digest?: string,
public readonly kind?: string
) {}
}
export function signature(signages: Signage[]): Headers {
const values: string[] = [];
for (const signage of signages) {
let markers: Array<string | Siger | Cigar>;
let tags: string[];
if (signage.markers instanceof Map) {
markers = Array.from(signage.markers.values());
tags = Array.from(signage.markers.keys());
} else {
markers = signage.markers as Array<Siger | Cigar>;
tags = [];
}
const items = new Array<string>();
const indexed = signage.indexed ?? markers[0] instanceof Siger;
if (indexed) {
items.push('indexed="?1"');
} else {
items.push('indexed="?0"');
}
if (signage.signer != undefined) {
items.push(`signer="${signage.signer}"`);
}
if (signage.ordinal != undefined) {
items.push(`ordinal="${signage.ordinal}"`);
}
if (signage.digest != undefined) {
items.push(`digest="${signage.digest}"`);
}
if (signage.kind != undefined) {
items.push(`kind="${signage.kind}"`);
}
items.push(
...markers.map((marker, idx) => {
let tag: string | undefined = undefined;
let val: string;
if (tags != undefined && tags.length > idx) {
tag = tags[idx];
}
if (marker instanceof Siger) {
if (!indexed) {
throw new Error(
`Indexed signature marker ${marker} when indexed False.`
);
}
tag = tag ?? marker.index.toString();
val = marker.qb64;
} else if (marker instanceof Cigar) {
if (indexed) {
throw new Error(
`Unindexed signature marker ${marker} when indexed True.`
);
}
if (!marker.verfer) {
throw new Error(
`Indexed signature marker is missing verfer`
);
}
tag = tag ?? marker.verfer.qb64;
val = marker.qb64;
} else {
tag = tag ?? idx.toString();
val = marker;
}
return `${tag}="${val}"`;
})
);
values.push(items.join(';'));
}
return new Headers([['Signature', values.join(',')]]);
}
export function designature(value: string) {
const values = value.replace(' ', '').split(',');
const signages = values.map((val) => {
const dict = new Map<string, string>();
val.split(';').forEach((v) => {
const splits = v.split('=', 2);
dict.set(splits[0], splits[1].replaceAll('"', ''));
});
if (!dict.has('indexed')) {
throw new Error(
'Missing indexed field in Signature header signage.'
);
}
const item = dict.get('indexed')!;
const indexed = !FALSY.includes(item);
dict.delete('indexed');
let signer;
if (dict.has('signer')) {
signer = dict.get('signer') as string;
dict.delete('signer');
}
let ordinal;
if (dict.has('ordinal')) {
ordinal = dict.get('ordinal') as string;
dict.delete('ordinal');
}
let digest;
if (dict.has('digest')) {
digest = dict.get('digest') as string;
dict.delete('digest');
}
let kind;
if (dict.has('kind')) {
kind = dict.get('kind') as string;
dict.delete('kind');
} else {
kind = 'CESR';
}
if (kind == 'CESR') {
const markers = new Map<string, Siger | Cigar>();
for (const [key, val] of dict.entries()) {
if (indexed) {
markers.set(key, new Siger({ qb64: val }));
} else {
markers.set(key, new Cigar({ qb64: val }));
}
}
return new Signage(markers, indexed, signer, ordinal, digest, kind);
} else {
return new Signage(dict, indexed, signer, ordinal, digest, kind);
}
});
return signages;
}