selfstore 1.8.31 → 1.8.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/dist/proof.d.ts +8 -1
- package/dist/proof.js +6 -1
- package/dist/proof.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -173,7 +173,9 @@ The deposit answers at once with the journal's own receipt
|
|
|
173
173
|
later `completeProof()` finds the first tour covering the line and, once that
|
|
174
174
|
tour is in Bitcoin, adds `tour`, `root`, `block`, the `.ots` proof and, when
|
|
175
175
|
the journal stamped that root under RFC 3161, the `.tsr` (both base64). The
|
|
176
|
-
protocol it speaks is at the top of `src/proof/journal.ts`.
|
|
176
|
+
protocol it speaks is at the top of `src/proof/journal.ts`. A journal that
|
|
177
|
+
issues typed receipts takes the type as an option of the notary
|
|
178
|
+
(`digestJournalNotary({ url, type: 'affichage' })`), sent with every deposit.
|
|
177
179
|
|
|
178
180
|
```ts
|
|
179
181
|
const notary = digestJournalNotary({ url: 'https://journal.example' });
|
package/dist/proof.d.ts
CHANGED
|
@@ -174,12 +174,19 @@ interface JournalOptions {
|
|
|
174
174
|
url: string;
|
|
175
175
|
/** Receipt `notary` field. Defaults to 'digest-journal'. */
|
|
176
176
|
name?: string;
|
|
177
|
+
/**
|
|
178
|
+
* The journal's deposit type, sent as `type` with every deposit (a journal
|
|
179
|
+
* that issues typed receipts, such as a permit display, keys them on it).
|
|
180
|
+
* None by default: the deposit is the journal's ordinary one.
|
|
181
|
+
*/
|
|
182
|
+
type?: string;
|
|
177
183
|
/** Injected for tests and relays; defaults to the global fetch. */
|
|
178
184
|
fetch?: typeof fetch;
|
|
179
185
|
}
|
|
180
186
|
/**
|
|
181
187
|
* A notary over a public digest journal (the protocol is at the top of this
|
|
182
|
-
* file). The label is sent as the journal's `libelle`: keep it a TYPE
|
|
188
|
+
* file). The label is sent as the journal's `libelle`: keep it a TYPE, unless
|
|
189
|
+
* the journal's `type` (an option of the notary) says what the label is.
|
|
183
190
|
*
|
|
184
191
|
* On deposit the receipt is incomplete; its evidence holds the journal's
|
|
185
192
|
* address, the receipt `id`, the public `line` and the journal's own `receipt`
|
package/dist/proof.js
CHANGED
|
@@ -345,6 +345,7 @@ function rankOf(deposits, id, hash) {
|
|
|
345
345
|
function digestJournalNotary(options) {
|
|
346
346
|
const name = options.name ?? "digest-journal";
|
|
347
347
|
const base = options.url.replace(/\/+$/, "");
|
|
348
|
+
const typed = options.type === void 0 ? {} : { type: options.type };
|
|
348
349
|
const send = options.fetch ?? globalThis.fetch;
|
|
349
350
|
const get = (path) => reach(send, `${base}${path}`, void 0, "the journal");
|
|
350
351
|
const bytesOf = async (path) => toBase64(new Uint8Array(await (await get(path)).arrayBuffer()));
|
|
@@ -357,7 +358,11 @@ function digestJournalNotary(options) {
|
|
|
357
358
|
{
|
|
358
359
|
method: "POST",
|
|
359
360
|
headers: { "content-type": "application/json" },
|
|
360
|
-
body: JSON.stringify({
|
|
361
|
+
body: JSON.stringify({
|
|
362
|
+
sha256: hash,
|
|
363
|
+
...label === void 0 ? {} : { libelle: label },
|
|
364
|
+
...typed
|
|
365
|
+
})
|
|
361
366
|
},
|
|
362
367
|
"the journal"
|
|
363
368
|
);
|
package/dist/proof.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/proof/proof.ts","../src/proof/der.ts","../src/proof/reach.ts","../src/proof/rfc3161.ts","../src/proof/journal.ts"],"names":["refused","hex"],"mappings":"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","file":"proof.js","sourcesContent":["// Proof of existence for the user's own documents: the bytes never leave the\n// device, only their SHA-256 does. A notary dates that digest; the receipt it\n// hands back is kept next to the file, in the user's own storage, and anyone\n// holding the file and the receipt can check the two still belong together.\n\nimport { sha256Hex } from '../selfstore/digest';\nimport { isSelfstoreError, SelfstoreError } from '../selfstore/errors';\nimport { toBytes, type FileBytes } from '../simple/bytes';\nimport type { SimpleRecord } from '../simple/simple';\n\n/**\n * What a notary hands back for one digest. `evidence` is the notary's own\n * material (a timestamp token, an inclusion path, a download address), as\n * strings - base64 for bytes - so a receipt is plain JSON and survives every\n * destination a store can write to.\n */\nexport interface Receipt {\n\t/** The notary that issued it (`Notary.name`). */\n\treadonly notary: string;\n\t/** Lowercase hex SHA-256 of the document. */\n\treadonly hash: string;\n\t/** The label sent with the deposit, if any. */\n\treadonly label?: string;\n\t/** ISO 8601 instant the notary vouches for (its clock, not the device's). */\n\treadonly depositedAt: string;\n\t/** False while the notary still has something to add (an anchor, a seal). */\n\treadonly complete: boolean;\n\treadonly evidence: Readonly<Record<string, string>>;\n}\n\n/**\n * Anyone who dates a digest. `deposit` must never see more than the digest and\n * the label; `complete` is called later - the next day, the next launch - and\n * returns the same receipt with whatever the notary could not give at once.\n * A notary that is final on deposit returns its argument unchanged.\n */\nexport interface Notary {\n\treadonly name: string;\n\tdeposit(hash: string, label?: string): Promise<Receipt>;\n\tcomplete(receipt: Receipt): Promise<Receipt>;\n}\n\n/** A receipt as `prove()` keeps it: the notary's, plus what the device measured. */\nexport interface Proof extends Receipt {\n\treadonly kind: 'selfstore-proof';\n\treadonly version: 1;\n\treadonly algorithm: 'SHA-256';\n\t/** Size of the document in bytes. */\n\treadonly size: number;\n\t/** The store file the proof belongs to, when there is one. */\n\treadonly file?: string;\n}\n\n/** Where proofs are kept: the simple store fits as is. */\nexport interface ProofShelf {\n\tput(collection: string, record: SimpleRecord): Promise<void>;\n}\n\n/** The collection `prove()` and `completeProof()` write to. */\nexport const PROOFS = 'proofs';\n\nexport interface ProveOptions {\n\tnotary: Notary;\n\t/** Sent to the notary with the digest. A TYPE ('invoice', 'inventory'),\n\t * never a name or a piece of the content: it leaves the device. */\n\tlabel?: string;\n\t/** Keep the proof in this store, under `PROOFS`, keyed by `file` or by hash. */\n\tstore?: ProofShelf;\n\t/** Id of the store file the document is (as `putFile` returned it). */\n\tfile?: string;\n}\n\n/** The result of `verify()`. */\nexport interface ProofCheck {\n\t/** The bytes hash to the receipt's digest (and size, when it carries one). */\n\treadonly matches: boolean;\n\t/** What the bytes hash to now. */\n\treadonly hash: string;\n\t/** Whether the notary had finished with this receipt. */\n\treadonly complete: boolean;\n}\n\nconst HEX_DIGEST = /^[0-9a-f]{64}$/;\n\nfunction refused(message: string): SelfstoreError {\n\treturn new SelfstoreError('NOTARY_REFUSED', message);\n}\n\n/** A notary that answers for another digest, or for another notary, is not believed. */\nfunction checkAnswer(answer: Receipt, hash: string, notary: Notary): void {\n\tif (typeof answer?.hash !== 'string' || answer.hash.toLowerCase() !== hash) {\n\t\tthrow refused(`${notary.name} answered for another digest`);\n\t}\n\tif (answer.notary !== notary.name) {\n\t\tthrow refused(`receipt names ${String(answer.notary)}, not ${notary.name}`);\n\t}\n\tif (Number.isNaN(Date.parse(answer.depositedAt))) {\n\t\tthrow refused(`${notary.name} gave no readable deposit time`);\n\t}\n}\n\nasync function shelve(proof: Proof, store: ProofShelf | undefined): Promise<void> {\n\tif (store) await store.put(PROOFS, { ...proof, id: proof.file ?? proof.hash });\n}\n\n/**\n * Hash `blob` on the device, deposit the digest with `options.notary`, and\n * return the proof - kept in `options.store` too when one is given. Only the\n * digest and the label leave the device.\n *\n * Throws NOTARY_UNAVAILABLE when the notary cannot be reached (retry later)\n * and NOTARY_REFUSED when it refuses or answers for something else.\n */\nexport async function prove(blob: FileBytes, options: ProveOptions): Promise<Proof> {\n\tconst bytes = await toBytes(blob);\n\tconst hash = await sha256Hex(bytes);\n\tconst answer = await options.notary.deposit(hash, options.label);\n\tcheckAnswer(answer, hash, options.notary);\n\tconst proof: Proof = {\n\t\t...answer,\n\t\thash,\n\t\tkind: 'selfstore-proof',\n\t\tversion: 1,\n\t\talgorithm: 'SHA-256',\n\t\tsize: bytes.length,\n\t\t...(options.file === undefined ? {} : { file: options.file })\n\t};\n\tawait shelve(proof, options.store);\n\treturn proof;\n}\n\n/**\n * Ask the notary for what it could not give on deposit. A complete proof is\n * returned as is, without a call. The fields the device measured are kept;\n * the notary may only add to its own.\n */\nexport async function completeProof(\n\tproof: Proof,\n\toptions: { notary: Notary; store?: ProofShelf }\n): Promise<Proof> {\n\tif (proof.complete) return proof;\n\tconst answer = await options.notary.complete(proof);\n\tcheckAnswer(answer, proof.hash, options.notary);\n\tconst completed: Proof = {\n\t\t...answer,\n\t\thash: proof.hash,\n\t\tkind: proof.kind,\n\t\tversion: proof.version,\n\t\talgorithm: proof.algorithm,\n\t\tsize: proof.size,\n\t\t...(proof.file === undefined ? {} : { file: proof.file })\n\t};\n\tawait shelve(completed, options.store);\n\treturn completed;\n}\n\n/**\n * Hash `blob` again and compare it with the receipt. This proves the bytes are\n * the ones the receipt names; that the receipt itself is genuine is what the\n * notary's evidence is for, checked with the notary's own verifier.\n *\n * Throws BAD_FORMAT on a receipt that carries no SHA-256 digest at all - a\n * damaged receipt is not a document that changed.\n */\nexport async function verify(\n\tblob: FileBytes,\n\treceipt: Pick<Receipt, 'hash' | 'complete'> & { size?: number }\n): Promise<ProofCheck> {\n\tconst expected = typeof receipt?.hash === 'string' ? receipt.hash.toLowerCase() : '';\n\tif (!HEX_DIGEST.test(expected)) {\n\t\tthrow new SelfstoreError('BAD_FORMAT', 'the receipt carries no SHA-256 digest');\n\t}\n\tconst bytes = await toBytes(blob);\n\tconst hash = await sha256Hex(bytes);\n\tconst sizeAgrees = receipt.size === undefined || receipt.size === bytes.length;\n\treturn { matches: hash === expected && sizeAgrees, hash, complete: receipt.complete === true };\n}\n\n/** Where proofs are read back from: the simple store fits as is. */\nexport interface ProofLibrary extends ProofShelf {\n\tall(collection: string): readonly SimpleRecord[];\n}\n\nfunction isProof(record: SimpleRecord): boolean {\n\treturn (\n\t\trecord.kind === 'selfstore-proof' &&\n\t\ttypeof record.hash === 'string' &&\n\t\tHEX_DIGEST.test(record.hash) &&\n\t\ttypeof record.notary === 'string' &&\n\t\ttypeof record.complete === 'boolean'\n\t);\n}\n\n/**\n * Every proof kept in `store`, oldest deposit first. Records that are not\n * proofs - another app's, a damaged one - are skipped rather than trusted.\n */\nexport function proofsIn(store: Pick<ProofLibrary, 'all'>): Proof[] {\n\treturn store\n\t\t.all(PROOFS)\n\t\t.filter(isProof)\n\t\t.map((record) => {\n\t\t\tconst { id: _id, ...proof } = record;\n\t\t\treturn proof as unknown as Proof;\n\t\t})\n\t\t.sort((a, b) => Date.parse(a.depositedAt) - Date.parse(b.depositedAt));\n}\n\n/** What `completePending()` did, proof by proof. */\nexport interface PendingRound {\n\t/** Finished this round, and written back to the store. */\n\treadonly completed: readonly Proof[];\n\t/** Still waiting: the notary has nothing to add yet, could not be reached,\n\t * or is not among the notaries given. Ask again on a later launch. */\n\treadonly pending: readonly Proof[];\n\t/** The notary answered for something else; kept as it was, not overwritten. */\n\treadonly refused: readonly Proof[];\n}\n\nfunction isCode(error: unknown, code: string): boolean {\n\treturn isSelfstoreError(error) && error.code === code;\n}\n\n/**\n * Ask each notary to finish the incomplete proofs it issued - the call an app\n * makes at launch, since a notary that anchors its digests finishes a receipt\n * hours after the deposit. A notary that cannot be reached is not asked again\n * this round; a proof whose notary is not in `notaries` waits. Only a proof\n * that came back complete is written to the store.\n */\nexport async function completePending(options: {\n\tstore: ProofLibrary;\n\tnotaries: readonly Notary[];\n}): Promise<PendingRound> {\n\tconst byName = new Map(options.notaries.map((notary) => [notary.name, notary]));\n\tconst unreachable = new Set<string>();\n\tconst completed: Proof[] = [];\n\tconst pending: Proof[] = [];\n\tconst refused: Proof[] = [];\n\tfor (const proof of proofsIn(options.store)) {\n\t\tif (proof.complete) continue;\n\t\tconst notary = byName.get(proof.notary);\n\t\tif (notary === undefined || unreachable.has(notary.name)) {\n\t\t\tpending.push(proof);\n\t\t\tcontinue;\n\t\t}\n\t\ttry {\n\t\t\tconst answer = await completeProof(proof, { notary });\n\t\t\tif (answer.complete) {\n\t\t\t\tawait shelve(answer, options.store);\n\t\t\t\tcompleted.push(answer);\n\t\t\t} else {\n\t\t\t\tpending.push(proof);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tif (isCode(error, 'NOTARY_UNAVAILABLE')) {\n\t\t\t\tunreachable.add(notary.name);\n\t\t\t\tpending.push(proof);\n\t\t\t} else if (isCode(error, 'NOTARY_REFUSED')) {\n\t\t\t\trefused.push(proof);\n\t\t\t} else {\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\t}\n\treturn { completed, pending, refused };\n}\n","// The few DER shapes an RFC 3161 exchange needs, and no more. A timestamp\n// request is five fields and the reply is read along one path, so a general\n// ASN.1 library would be a fourth runtime dependency for two functions.\n\n/** One decoded TLV: `start` and `end` bound its CONTENT. */\nexport interface DerNode {\n\treadonly tag: number;\n\treadonly start: number;\n\treadonly end: number;\n}\n\nexport class DerError extends Error {}\n\nfunction encodeLength(length: number): Uint8Array {\n\tif (length < 0x80) return Uint8Array.of(length);\n\tconst bytes: number[] = [];\n\tfor (let rest = length; rest > 0; rest = Math.floor(rest / 256)) bytes.unshift(rest % 256);\n\treturn Uint8Array.of(0x80 | bytes.length, ...bytes);\n}\n\n/** Encode one TLV around already-encoded content. */\nexport function tlv(tag: number, ...parts: Uint8Array[]): Uint8Array {\n\tconst length = parts.reduce((sum, part) => sum + part.length, 0);\n\tconst head = encodeLength(length);\n\tconst out = new Uint8Array(1 + head.length + length);\n\tout[0] = tag;\n\tout.set(head, 1);\n\tlet at = 1 + head.length;\n\tfor (const part of parts) {\n\t\tout.set(part, at);\n\t\tat += part.length;\n\t}\n\treturn out;\n}\n\n/** Read the TLV that starts at `offset`. Indefinite lengths are BER, not DER: refused. */\nexport function readNode(bytes: Uint8Array, offset: number, limit = bytes.length): DerNode {\n\tif (offset + 2 > limit) throw new DerError('truncated header');\n\tconst tag = bytes[offset];\n\tconst first = bytes[offset + 1];\n\tlet start = offset + 2;\n\tlet length = first;\n\tif (first & 0x80) {\n\t\tconst count = first & 0x7f;\n\t\tif (count === 0 || count > 4) throw new DerError('unsupported length');\n\t\tif (start + count > limit) throw new DerError('truncated length');\n\t\tlength = 0;\n\t\tfor (let i = 0; i < count; i++) length = length * 256 + bytes[start + i];\n\t\tstart += count;\n\t}\n\tconst end = start + length;\n\tif (end > limit) throw new DerError('content runs past its parent');\n\treturn { tag, start, end };\n}\n\n/** The direct children of a constructed node. */\nexport function childrenOf(bytes: Uint8Array, node: DerNode): DerNode[] {\n\tconst out: DerNode[] = [];\n\tfor (let at = node.start; at < node.end;) {\n\t\tconst child = readNode(bytes, at, node.end);\n\t\tout.push(child);\n\t\tat = child.end;\n\t}\n\treturn out;\n}\n\n/** The node's content, or a refusal when its tag is not the one expected. */\nexport function expectTag(node: DerNode | undefined, tag: number): DerNode {\n\tif (node?.tag !== tag) throw new DerError(`expected tag 0x${tag.toString(16)}`);\n\treturn node;\n}\n\nexport function contentOf(bytes: Uint8Array, node: DerNode): Uint8Array {\n\treturn bytes.subarray(node.start, node.end);\n}\n","// One way to call a notary over HTTP, so every adapter maps the same failures\n// to the same codes: unreachable, overloaded or rate-limited is worth a retry,\n// any other refusal is not.\n\nimport { SelfstoreError } from '../selfstore/errors';\n\n/** Fetch `url`, throwing NOTARY_UNAVAILABLE or NOTARY_REFUSED instead of returning a failure. */\nexport async function reach(\n\tsend: typeof fetch,\n\turl: string,\n\tinit: RequestInit | undefined,\n\twho: string\n): Promise<Response> {\n\tlet response: Response;\n\ttry {\n\t\tresponse = await send(url, init);\n\t} catch (e) {\n\t\tthrow new SelfstoreError(\n\t\t\t'NOTARY_UNAVAILABLE',\n\t\t\t`${who} could not be reached: ${(e as Error).message}`\n\t\t);\n\t}\n\tif (!response.ok) {\n\t\tconst code =\n\t\t\tresponse.status >= 500 || response.status === 429 ? 'NOTARY_UNAVAILABLE' : 'NOTARY_REFUSED';\n\t\tthrow new SelfstoreError(code, `${who} answered ${response.status}`);\n\t}\n\treturn response;\n}\n","// A notary over any RFC 3161 time-stamping authority. The authority signs the\n// digest and the time in one token, so the receipt is complete on deposit: the\n// token (the `.tsr` file) is the evidence, and `openssl ts -verify` checks it\n// against the authority's certificate without this library.\n\nimport { fromBase64, toBase64 } from '../selfstore/base64';\nimport { hex } from '../selfstore/digest';\nimport { SelfstoreError } from '../selfstore/errors';\nimport { childrenOf, contentOf, DerError, expectTag, readNode, tlv, type DerNode } from './der';\nimport type { Notary, Receipt } from './proof';\nimport { reach } from './reach';\n\nconst SEQUENCE = 0x30;\nconst INTEGER = 0x02;\nconst OCTET_STRING = 0x04;\nconst OID = 0x06;\nconst GENERALIZED_TIME = 0x18;\nconst EXPLICIT_0 = 0xa0;\n\n/** id-sha256, 2.16.840.1.101.3.4.2.1, with its NULL parameters. */\nconst SHA256_ALGORITHM = tlv(\n\tSEQUENCE,\n\ttlv(OID, Uint8Array.of(0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01)),\n\tUint8Array.of(0x05, 0x00)\n);\n\nexport interface Rfc3161Options {\n\t/** The authority's endpoint. In a browser it must answer CORS, or sit\n\t * behind a relay of yours that does: most public authorities do not. */\n\turl: string;\n\t/** Receipt `notary` field. Defaults to 'rfc3161'. */\n\tname?: string;\n\t/** Injected for tests and relays; defaults to the global fetch. */\n\tfetch?: typeof fetch;\n}\n\n/** What a timestamp token says, read without checking its signature. */\nexport interface TimestampToken {\n\t/** Lowercase hex of the digest the authority stamped. */\n\treadonly hash: string;\n\t/** ISO 8601 instant the authority signed. */\n\treadonly time: string;\n\t/** The nonce echoed back, as lowercase hex, when there is one. */\n\treadonly nonce?: string;\n}\n\nfunction hexToBytes(hex: string): Uint8Array {\n\treturn Uint8Array.from(hex.match(/../g) ?? [], (pair) => Number.parseInt(pair, 16));\n}\n\n/** Leading zero bytes are DER's sign padding, not part of the value. */\nfunction integerHex(bytes: Uint8Array): string {\n\tlet at = 0;\n\twhile (at < bytes.length - 1 && bytes[at] === 0) at++;\n\treturn hex(bytes.subarray(at));\n}\n\n/** Eight random bytes, positive and minimal as a DER INTEGER. */\nfunction newNonce(): Uint8Array {\n\tconst nonce = crypto.getRandomValues(new Uint8Array(8));\n\tnonce[0] = (nonce[0] & 0x3f) | 0x40;\n\treturn nonce;\n}\n\n/** A TimeStampReq (RFC 3161 section 2.4.1) for a SHA-256 digest, asking for the certificate. */\nexport function timestampRequest(hash: string, nonce: Uint8Array): Uint8Array {\n\treturn tlv(\n\t\tSEQUENCE,\n\t\ttlv(INTEGER, Uint8Array.of(1)),\n\t\ttlv(SEQUENCE, SHA256_ALGORITHM, tlv(OCTET_STRING, hexToBytes(hash))),\n\t\ttlv(INTEGER, nonce),\n\t\tUint8Array.of(0x01, 0x01, 0xff)\n\t);\n}\n\n/** YYYYMMDDHHMMSS[.fff]Z to ISO 8601. */\nfunction generalizedTime(text: string): string {\n\tconst parts = /^(\\d{4})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\.\\d+)?Z$/.exec(text);\n\tif (parts === null) throw new DerError(`unreadable time ${text}`);\n\tconst [, y, mo, d, h, mi, s, fraction] = parts;\n\treturn new Date(`${y}-${mo}-${d}T${h}:${mi}:${s}${fraction ?? ''}Z`).toISOString();\n}\n\n/** TimeStampResp: the status, or the token when it was granted. */\nfunction tokenOf(bytes: Uint8Array): DerNode {\n\tconst [statusInfo, token] = childrenOf(bytes, expectTag(readNode(bytes, 0), SEQUENCE));\n\tconst status = expectTag(childrenOf(bytes, expectTag(statusInfo, SEQUENCE))[0], INTEGER);\n\tconst code = Number.parseInt(integerHex(contentOf(bytes, status)), 16);\n\t// 0 granted, 1 granted with modifications; anything else is a refusal.\n\tif (code > 1) {\n\t\tthrow new SelfstoreError(\n\t\t\t'NOTARY_REFUSED',\n\t\t\t`the authority refused the request (status ${code})`\n\t\t);\n\t}\n\treturn expectTag(token, SEQUENCE);\n}\n\n/** ContentInfo > SignedData > EncapsulatedContentInfo > TSTInfo. */\nfunction tstInfoOf(bytes: Uint8Array, token: DerNode): DerNode {\n\tconst signedData = expectTag(\n\t\tchildrenOf(bytes, expectTag(childrenOf(bytes, token)[1], EXPLICIT_0))[0],\n\t\tSEQUENCE\n\t);\n\tconst encapsulated = expectTag(childrenOf(bytes, signedData)[2], SEQUENCE);\n\tconst wrapper = expectTag(childrenOf(bytes, encapsulated)[1], EXPLICIT_0);\n\tconst octets = expectTag(childrenOf(bytes, wrapper)[0], OCTET_STRING);\n\treturn expectTag(readNode(bytes, octets.start, octets.end), SEQUENCE);\n}\n\n/**\n * Read the digest, the time and the nonce out of a TimeStampResp (the `.tsr`\n * file). It does NOT check the authority's signature - that is what\n * `openssl ts -verify` is for; it is what tells a token for another document\n * apart before anything is kept. Throws NOTARY_REFUSED on a refusal or on\n * anything that is not a timestamp reply.\n */\nexport function readTimestampReply(bytes: Uint8Array): TimestampToken {\n\ttry {\n\t\tconst tstInfo = tstInfoOf(bytes, tokenOf(bytes));\n\t\t// version, policy, messageImprint, serialNumber, genTime, then optional\n\t\t// accuracy, ordering and nonce - the nonce is the only INTEGER among them.\n\t\tconst [, , imprint, , time, ...rest] = childrenOf(bytes, tstInfo);\n\t\tconst digest = expectTag(childrenOf(bytes, expectTag(imprint, SEQUENCE))[1], OCTET_STRING);\n\t\tconst nonce = rest.find((node) => node.tag === INTEGER);\n\t\tconst genTime = new TextDecoder().decode(contentOf(bytes, expectTag(time, GENERALIZED_TIME)));\n\t\treturn {\n\t\t\thash: hex(contentOf(bytes, digest)),\n\t\t\ttime: generalizedTime(genTime),\n\t\t\t...(nonce ? { nonce: integerHex(contentOf(bytes, nonce)) } : {})\n\t\t};\n\t} catch (e) {\n\t\tif (e instanceof SelfstoreError) throw e;\n\t\tthrow new SelfstoreError('NOTARY_REFUSED', `not a timestamp reply: ${(e as Error).message}`);\n\t}\n}\n\nasync function post(options: Rfc3161Options, body: Uint8Array): Promise<Uint8Array> {\n\tconst response = await reach(\n\t\toptions.fetch ?? globalThis.fetch,\n\t\toptions.url,\n\t\t{\n\t\t\tmethod: 'POST',\n\t\t\theaders: { 'content-type': 'application/timestamp-query' },\n\t\t\tbody: body as BodyInit\n\t\t},\n\t\t'the authority'\n\t);\n\treturn new Uint8Array(await response.arrayBuffer());\n}\n\n/**\n * A notary over an RFC 3161 time-stamping authority. The receipt is complete\n * on deposit; its evidence is the reply, base64 under `tsr`, and the\n * authority's address under `tsa`. The label is never sent: RFC 3161 has no\n * field for it, so it stays on the receipt.\n */\nexport function rfc3161Notary(options: Rfc3161Options): Notary {\n\tconst name = options.name ?? 'rfc3161';\n\treturn {\n\t\tname,\n\t\tasync deposit(hash: string, label?: string): Promise<Receipt> {\n\t\t\tconst nonce = newNonce();\n\t\t\tconst reply = await post(options, timestampRequest(hash, nonce));\n\t\t\tconst token = readTimestampReply(reply);\n\t\t\tif (token.hash !== hash) {\n\t\t\t\tthrow new SelfstoreError('NOTARY_REFUSED', 'the authority stamped another digest');\n\t\t\t}\n\t\t\tif (token.nonce !== integerHex(nonce)) {\n\t\t\t\tthrow new SelfstoreError('NOTARY_REFUSED', 'the reply does not answer this request');\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tnotary: name,\n\t\t\t\thash,\n\t\t\t\t...(label === undefined ? {} : { label }),\n\t\t\t\tdepositedAt: token.time,\n\t\t\t\tcomplete: true,\n\t\t\t\tevidence: { tsr: toBase64(reply), tsa: options.url }\n\t\t\t};\n\t\t},\n\t\tcomplete(receipt: Receipt): Promise<Receipt> {\n\t\t\treturn Promise.resolve(receipt);\n\t\t}\n\t};\n}\n\n/** The `.tsr` bytes of an RFC 3161 receipt, to offer as a download. */\nexport function timestampReplyOf(receipt: Pick<Receipt, 'evidence'>): Uint8Array | undefined {\n\tconst tsr = receipt.evidence.tsr;\n\treturn tsr === undefined ? undefined : fromBase64(tsr);\n}\n","// A notary over a public digest journal: a service that takes a SHA-256 with\n// no account, writes it as one line of a public deposits file, and folds that\n// file into a Merkle tree it anchors in Bitcoin (OpenTimestamps) and often\n// stamps under RFC 3161 too. The deposit answers at once with the journal's\n// own receipt; the anchor comes hours later, so `complete` is what fetches it.\n//\n// The protocol, relative to the journal's base URL:\n// POST /api/depots {\"sha256\", \"libelle\"?} -> 201\n// {\"id\", \"jour\", \"place\", \"ligne\", \"recu\": {\"sha256\", \"depose\", ...}}\n// GET /empreintes/depots.jsonl one JSON line per deposit, in order, with \"recu\" = id\n// GET /tours.json {\"tours\": [{\"id\", \"racine\", \"depots\", \"ots\", \"bloc\",\n// \"horodatage\", \"fichiers\"}]}; a tour covers the\n// first `depots` lines of the deposits file\n// GET /empreintes/<tour>.racine.ots, /empreintes/<tour>.racine.tsr\n\nimport { toBase64 } from '../selfstore/base64';\nimport { SelfstoreError } from '../selfstore/errors';\nimport type { Notary, Receipt } from './proof';\nimport { reach } from './reach';\n\nexport interface JournalOptions {\n\t/** The journal's base URL, e.g. 'https://journal.example'. */\n\turl: string;\n\t/** Receipt `notary` field. Defaults to 'digest-journal'. */\n\tname?: string;\n\t/** Injected for tests and relays; defaults to the global fetch. */\n\tfetch?: typeof fetch;\n}\n\ninterface Deposit {\n\tid: string;\n\tligne: string;\n\trecu: { sha256: string; depose: string };\n}\n\ninterface Tour {\n\tid: string;\n\tracine: string;\n\tdepots: number;\n\tots: string;\n\tbloc: number | null;\n\thorodatage: string | null;\n\tfichiers?: string[];\n}\n\nconst HEX_ID = /^[0-9a-f]{64}$/;\n\nfunction refused(message: string): SelfstoreError {\n\treturn new SelfstoreError('NOTARY_REFUSED', message);\n}\n\nfunction readDeposit(body: unknown): Deposit {\n\tconst d = body as Partial<Deposit> | null;\n\tif (\n\t\ttypeof d?.id !== 'string' ||\n\t\t!HEX_ID.test(d.id) ||\n\t\ttypeof d.ligne !== 'string' ||\n\t\ttypeof d.recu?.sha256 !== 'string' ||\n\t\ttypeof d.recu.depose !== 'string'\n\t) {\n\t\tthrow refused('the journal answered without a receipt');\n\t}\n\treturn d as Deposit;\n}\n\nfunction parseLine(text: string): { recu?: string; sha256?: string } {\n\ttry {\n\t\treturn JSON.parse(text) as { recu?: string; sha256?: string };\n\t} catch {\n\t\tthrow refused('the journal published an unreadable deposits file');\n\t}\n}\n\n/** 1-based rank of the deposit line whose receipt id is `id`, or 0. */\nfunction rankOf(deposits: string, id: string, hash: string): number {\n\tconst lines = deposits.split('\\n').filter(Boolean);\n\tfor (const [index, text] of lines.entries()) {\n\t\tconst line = parseLine(text);\n\t\tif (line.recu !== id) continue;\n\t\tif (line.sha256 !== hash) throw refused('the journal lists this receipt for another digest');\n\t\treturn index + 1;\n\t}\n\treturn 0;\n}\n\n/**\n * A notary over a public digest journal (the protocol is at the top of this\n * file). The label is sent as the journal's `libelle`: keep it a TYPE.\n *\n * On deposit the receipt is incomplete; its evidence holds the journal's\n * address, the receipt `id`, the public `line` and the journal's own `receipt`\n * as JSON - the file its verifier reads. `complete` finds the first tour that\n * covers the line and, once that tour is anchored in Bitcoin, completes the\n * receipt with `tour`, `root`, `block`, the `.ots` proof and, when the journal\n * stamped that root, the `.tsr` token (both base64). Checking the Merkle path\n * from the line to the root is the journal's verifier's job.\n */\nexport function digestJournalNotary(options: JournalOptions): Notary {\n\tconst name = options.name ?? 'digest-journal';\n\tconst base = options.url.replace(/\\/+$/, '');\n\tconst send = options.fetch ?? globalThis.fetch;\n\tconst get = (path: string): Promise<Response> =>\n\t\treach(send, `${base}${path}`, undefined, 'the journal');\n\tconst bytesOf = async (path: string): Promise<string> =>\n\t\ttoBase64(new Uint8Array(await (await get(path)).arrayBuffer()));\n\n\treturn {\n\t\tname,\n\t\tasync deposit(hash: string, label?: string): Promise<Receipt> {\n\t\t\tconst response = await reach(\n\t\t\t\tsend,\n\t\t\t\t`${base}/api/depots`,\n\t\t\t\t{\n\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\theaders: { 'content-type': 'application/json' },\n\t\t\t\t\tbody: JSON.stringify({ sha256: hash, ...(label === undefined ? {} : { libelle: label }) })\n\t\t\t\t},\n\t\t\t\t'the journal'\n\t\t\t);\n\t\t\tconst deposit = readDeposit(await response.json().catch(() => null));\n\t\t\treturn {\n\t\t\t\tnotary: name,\n\t\t\t\thash: deposit.recu.sha256,\n\t\t\t\t...(label === undefined ? {} : { label }),\n\t\t\t\tdepositedAt: deposit.recu.depose,\n\t\t\t\tcomplete: false,\n\t\t\t\tevidence: {\n\t\t\t\t\tjournal: base,\n\t\t\t\t\tid: deposit.id,\n\t\t\t\t\tline: deposit.ligne,\n\t\t\t\t\treceipt: JSON.stringify(deposit.recu)\n\t\t\t\t}\n\t\t\t};\n\t\t},\n\t\tasync complete(receipt: Receipt): Promise<Receipt> {\n\t\t\tconst id = receipt.evidence.id;\n\t\t\tif (id === undefined) throw refused('the receipt carries no journal id');\n\t\t\tconst rank = rankOf(await (await get('/empreintes/depots.jsonl')).text(), id, receipt.hash);\n\t\t\tif (rank === 0) return receipt;\n\t\t\tconst { tours } = (await (await get('/tours.json')).json()) as { tours: Tour[] };\n\t\t\tconst tour = tours.find((t) => t.depots >= rank);\n\t\t\tif (tour?.ots !== 'bitcoin') return receipt;\n\t\t\tconst stamped = tour.horodatage !== null && tour.fichiers?.includes(`${tour.id}.racine.tsr`);\n\t\t\treturn {\n\t\t\t\t...receipt,\n\t\t\t\tcomplete: true,\n\t\t\t\tevidence: {\n\t\t\t\t\t...receipt.evidence,\n\t\t\t\t\ttour: tour.id,\n\t\t\t\t\troot: tour.racine,\n\t\t\t\t\t...(tour.bloc === null ? {} : { block: String(tour.bloc) }),\n\t\t\t\t\tots: await bytesOf(`/empreintes/${tour.id}.racine.ots`),\n\t\t\t\t\t...(stamped ? { tsr: await bytesOf(`/empreintes/${tour.id}.racine.tsr`) } : {})\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t};\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/proof/proof.ts","../src/proof/der.ts","../src/proof/reach.ts","../src/proof/rfc3161.ts","../src/proof/journal.ts"],"names":["refused","hex"],"mappings":";;;;;;AA2DO,IAAM,MAAA,GAAS;AAuBtB,IAAM,UAAA,GAAa,gBAAA;AAEnB,SAAS,QAAQ,OAAA,EAAiC;AACjD,EAAA,OAAO,IAAI,cAAA,CAAe,gBAAA,EAAkB,OAAO,CAAA;AACpD;AAGA,SAAS,WAAA,CAAY,MAAA,EAAiB,IAAA,EAAc,MAAA,EAAsB;AACzE,EAAA,IAAI,OAAO,QAAQ,IAAA,KAAS,QAAA,IAAY,OAAO,IAAA,CAAK,WAAA,OAAkB,IAAA,EAAM;AAC3E,IAAA,MAAM,OAAA,CAAQ,CAAA,EAAG,MAAA,CAAO,IAAI,CAAA,4BAAA,CAA8B,CAAA;AAAA,EAC3D;AACA,EAAA,IAAI,MAAA,CAAO,MAAA,KAAW,MAAA,CAAO,IAAA,EAAM;AAClC,IAAA,MAAM,OAAA,CAAQ,iBAAiB,MAAA,CAAO,MAAA,CAAO,MAAM,CAAC,CAAA,MAAA,EAAS,MAAA,CAAO,IAAI,CAAA,CAAE,CAAA;AAAA,EAC3E;AACA,EAAA,IAAI,OAAO,KAAA,CAAM,IAAA,CAAK,MAAM,MAAA,CAAO,WAAW,CAAC,CAAA,EAAG;AACjD,IAAA,MAAM,OAAA,CAAQ,CAAA,EAAG,MAAA,CAAO,IAAI,CAAA,8BAAA,CAAgC,CAAA;AAAA,EAC7D;AACD;AAEA,eAAe,MAAA,CAAO,OAAc,KAAA,EAA8C;AACjF,EAAA,IAAI,KAAA,EAAO,MAAM,KAAA,CAAM,GAAA,CAAI,MAAA,EAAQ,EAAE,GAAG,KAAA,EAAO,EAAA,EAAI,KAAA,CAAM,IAAA,IAAQ,KAAA,CAAM,MAAM,CAAA;AAC9E;AAUA,eAAsB,KAAA,CAAM,MAAiB,OAAA,EAAuC;AACnF,EAAA,MAAM,KAAA,GAAQ,MAAM,OAAA,CAAQ,IAAI,CAAA;AAChC,EAAA,MAAM,IAAA,GAAO,MAAM,SAAA,CAAU,KAAK,CAAA;AAClC,EAAA,MAAM,SAAS,MAAM,OAAA,CAAQ,OAAO,OAAA,CAAQ,IAAA,EAAM,QAAQ,KAAK,CAAA;AAC/D,EAAA,WAAA,CAAY,MAAA,EAAQ,IAAA,EAAM,OAAA,CAAQ,MAAM,CAAA;AACxC,EAAA,MAAM,KAAA,GAAe;AAAA,IACpB,GAAG,MAAA;AAAA,IACH,IAAA;AAAA,IACA,IAAA,EAAM,iBAAA;AAAA,IACN,OAAA,EAAS,CAAA;AAAA,IACT,SAAA,EAAW,SAAA;AAAA,IACX,MAAM,KAAA,CAAM,MAAA;AAAA,IACZ,GAAI,QAAQ,IAAA,KAAS,MAAA,GAAY,EAAC,GAAI,EAAE,IAAA,EAAM,OAAA,CAAQ,IAAA;AAAK,GAC5D;AACA,EAAA,MAAM,MAAA,CAAO,KAAA,EAAO,OAAA,CAAQ,KAAK,CAAA;AACjC,EAAA,OAAO,KAAA;AACR;AAOA,eAAsB,aAAA,CACrB,OACA,OAAA,EACiB;AACjB,EAAA,IAAI,KAAA,CAAM,UAAU,OAAO,KAAA;AAC3B,EAAA,MAAM,MAAA,GAAS,MAAM,OAAA,CAAQ,MAAA,CAAO,SAAS,KAAK,CAAA;AAClD,EAAA,WAAA,CAAY,MAAA,EAAQ,KAAA,CAAM,IAAA,EAAM,OAAA,CAAQ,MAAM,CAAA;AAC9C,EAAA,MAAM,SAAA,GAAmB;AAAA,IACxB,GAAG,MAAA;AAAA,IACH,MAAM,KAAA,CAAM,IAAA;AAAA,IACZ,MAAM,KAAA,CAAM,IAAA;AAAA,IACZ,SAAS,KAAA,CAAM,OAAA;AAAA,IACf,WAAW,KAAA,CAAM,SAAA;AAAA,IACjB,MAAM,KAAA,CAAM,IAAA;AAAA,IACZ,GAAI,MAAM,IAAA,KAAS,MAAA,GAAY,EAAC,GAAI,EAAE,IAAA,EAAM,KAAA,CAAM,IAAA;AAAK,GACxD;AACA,EAAA,MAAM,MAAA,CAAO,SAAA,EAAW,OAAA,CAAQ,KAAK,CAAA;AACrC,EAAA,OAAO,SAAA;AACR;AAUA,eAAsB,MAAA,CACrB,MACA,OAAA,EACsB;AACtB,EAAA,MAAM,QAAA,GAAW,OAAO,OAAA,EAAS,IAAA,KAAS,WAAW,OAAA,CAAQ,IAAA,CAAK,aAAY,GAAI,EAAA;AAClF,EAAA,IAAI,CAAC,UAAA,CAAW,IAAA,CAAK,QAAQ,CAAA,EAAG;AAC/B,IAAA,MAAM,IAAI,cAAA,CAAe,YAAA,EAAc,uCAAuC,CAAA;AAAA,EAC/E;AACA,EAAA,MAAM,KAAA,GAAQ,MAAM,OAAA,CAAQ,IAAI,CAAA;AAChC,EAAA,MAAM,IAAA,GAAO,MAAM,SAAA,CAAU,KAAK,CAAA;AAClC,EAAA,MAAM,aAAa,OAAA,CAAQ,IAAA,KAAS,MAAA,IAAa,OAAA,CAAQ,SAAS,KAAA,CAAM,MAAA;AACxE,EAAA,OAAO,EAAE,SAAS,IAAA,KAAS,QAAA,IAAY,YAAY,IAAA,EAAM,QAAA,EAAU,OAAA,CAAQ,QAAA,KAAa,IAAA,EAAK;AAC9F;AAOA,SAAS,QAAQ,MAAA,EAA+B;AAC/C,EAAA,OACC,OAAO,IAAA,KAAS,iBAAA,IAChB,OAAO,MAAA,CAAO,IAAA,KAAS,YACvB,UAAA,CAAW,IAAA,CAAK,MAAA,CAAO,IAAI,KAC3B,OAAO,MAAA,CAAO,WAAW,QAAA,IACzB,OAAO,OAAO,QAAA,KAAa,SAAA;AAE7B;AAMO,SAAS,SAAS,KAAA,EAA2C;AACnE,EAAA,OAAO,KAAA,CACL,IAAI,MAAM,CAAA,CACV,OAAO,OAAO,CAAA,CACd,GAAA,CAAI,CAAC,MAAA,KAAW;AAChB,IAAA,MAAM,EAAE,EAAA,EAAI,GAAA,EAAK,GAAG,OAAM,GAAI,MAAA;AAC9B,IAAA,OAAO,KAAA;AAAA,EACR,CAAC,CAAA,CACA,IAAA,CAAK,CAAC,GAAG,CAAA,KAAM,IAAA,CAAK,KAAA,CAAM,CAAA,CAAE,WAAW,CAAA,GAAI,IAAA,CAAK,KAAA,CAAM,CAAA,CAAE,WAAW,CAAC,CAAA;AACvE;AAaA,SAAS,MAAA,CAAO,OAAgB,IAAA,EAAuB;AACtD,EAAA,OAAO,gBAAA,CAAiB,KAAK,CAAA,IAAK,KAAA,CAAM,IAAA,KAAS,IAAA;AAClD;AASA,eAAsB,gBAAgB,OAAA,EAGZ;AACzB,EAAA,MAAM,MAAA,GAAS,IAAI,GAAA,CAAI,OAAA,CAAQ,QAAA,CAAS,GAAA,CAAI,CAAC,MAAA,KAAW,CAAC,MAAA,CAAO,IAAA,EAAM,MAAM,CAAC,CAAC,CAAA;AAC9E,EAAA,MAAM,WAAA,uBAAkB,GAAA,EAAY;AACpC,EAAA,MAAM,YAAqB,EAAC;AAC5B,EAAA,MAAM,UAAmB,EAAC;AAC1B,EAAA,MAAMA,WAAmB,EAAC;AAC1B,EAAA,KAAA,MAAW,KAAA,IAAS,QAAA,CAAS,OAAA,CAAQ,KAAK,CAAA,EAAG;AAC5C,IAAA,IAAI,MAAM,QAAA,EAAU;AACpB,IAAA,MAAM,MAAA,GAAS,MAAA,CAAO,GAAA,CAAI,KAAA,CAAM,MAAM,CAAA;AACtC,IAAA,IAAI,WAAW,MAAA,IAAa,WAAA,CAAY,GAAA,CAAI,MAAA,CAAO,IAAI,CAAA,EAAG;AACzD,MAAA,OAAA,CAAQ,KAAK,KAAK,CAAA;AAClB,MAAA;AAAA,IACD;AACA,IAAA,IAAI;AACH,MAAA,MAAM,SAAS,MAAM,aAAA,CAAc,KAAA,EAAO,EAAE,QAAQ,CAAA;AACpD,MAAA,IAAI,OAAO,QAAA,EAAU;AACpB,QAAA,MAAM,MAAA,CAAO,MAAA,EAAQ,OAAA,CAAQ,KAAK,CAAA;AAClC,QAAA,SAAA,CAAU,KAAK,MAAM,CAAA;AAAA,MACtB,CAAA,MAAO;AACN,QAAA,OAAA,CAAQ,KAAK,KAAK,CAAA;AAAA,MACnB;AAAA,IACD,SAAS,KAAA,EAAO;AACf,MAAA,IAAI,MAAA,CAAO,KAAA,EAAO,oBAAoB,CAAA,EAAG;AACxC,QAAA,WAAA,CAAY,GAAA,CAAI,OAAO,IAAI,CAAA;AAC3B,QAAA,OAAA,CAAQ,KAAK,KAAK,CAAA;AAAA,MACnB,CAAA,MAAA,IAAW,MAAA,CAAO,KAAA,EAAO,gBAAgB,CAAA,EAAG;AAC3C,QAAAA,QAAAA,CAAQ,KAAK,KAAK,CAAA;AAAA,MACnB,CAAA,MAAO;AACN,QAAA,MAAM,KAAA;AAAA,MACP;AAAA,IACD;AAAA,EACD;AACA,EAAA,OAAO,EAAE,SAAA,EAAW,OAAA,EAAS,OAAA,EAAAA,QAAAA,EAAQ;AACtC;;;AC/PO,IAAM,QAAA,GAAN,cAAuB,KAAA,CAAM;AAAC,CAAA;AAErC,SAAS,aAAa,MAAA,EAA4B;AACjD,EAAA,IAAI,MAAA,GAAS,GAAA,EAAM,OAAO,UAAA,CAAW,GAAG,MAAM,CAAA;AAC9C,EAAA,MAAM,QAAkB,EAAC;AACzB,EAAA,KAAA,IAAS,IAAA,GAAO,MAAA,EAAQ,IAAA,GAAO,CAAA,EAAG,IAAA,GAAO,IAAA,CAAK,KAAA,CAAM,IAAA,GAAO,GAAG,CAAA,EAAG,KAAA,CAAM,OAAA,CAAQ,OAAO,GAAG,CAAA;AACzF,EAAA,OAAO,WAAW,EAAA,CAAG,GAAA,GAAO,KAAA,CAAM,MAAA,EAAQ,GAAG,KAAK,CAAA;AACnD;AAGO,SAAS,GAAA,CAAI,QAAgB,KAAA,EAAiC;AACpE,EAAA,MAAM,MAAA,GAAS,MAAM,MAAA,CAAO,CAAC,KAAK,IAAA,KAAS,GAAA,GAAM,IAAA,CAAK,MAAA,EAAQ,CAAC,CAAA;AAC/D,EAAA,MAAM,IAAA,GAAO,aAAa,MAAM,CAAA;AAChC,EAAA,MAAM,MAAM,IAAI,UAAA,CAAW,CAAA,GAAI,IAAA,CAAK,SAAS,MAAM,CAAA;AACnD,EAAA,GAAA,CAAI,CAAC,CAAA,GAAI,GAAA;AACT,EAAA,GAAA,CAAI,GAAA,CAAI,MAAM,CAAC,CAAA;AACf,EAAA,IAAI,EAAA,GAAK,IAAI,IAAA,CAAK,MAAA;AAClB,EAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACzB,IAAA,GAAA,CAAI,GAAA,CAAI,MAAM,EAAE,CAAA;AAChB,IAAA,EAAA,IAAM,IAAA,CAAK,MAAA;AAAA,EACZ;AACA,EAAA,OAAO,GAAA;AACR;AAGO,SAAS,QAAA,CAAS,KAAA,EAAmB,MAAA,EAAgB,KAAA,GAAQ,MAAM,MAAA,EAAiB;AAC1F,EAAA,IAAI,SAAS,CAAA,GAAI,KAAA,EAAO,MAAM,IAAI,SAAS,kBAAkB,CAAA;AAC7D,EAAA,MAAM,GAAA,GAAM,MAAM,MAAM,CAAA;AACxB,EAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,MAAA,GAAS,CAAC,CAAA;AAC9B,EAAA,IAAI,QAAQ,MAAA,GAAS,CAAA;AACrB,EAAA,IAAI,MAAA,GAAS,KAAA;AACb,EAAA,IAAI,QAAQ,GAAA,EAAM;AACjB,IAAA,MAAM,QAAQ,KAAA,GAAQ,GAAA;AACtB,IAAA,IAAI,UAAU,CAAA,IAAK,KAAA,GAAQ,GAAG,MAAM,IAAI,SAAS,oBAAoB,CAAA;AACrE,IAAA,IAAI,QAAQ,KAAA,GAAQ,KAAA,EAAO,MAAM,IAAI,SAAS,kBAAkB,CAAA;AAChE,IAAA,MAAA,GAAS,CAAA;AACT,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,KAAA,EAAO,CAAA,EAAA,WAAc,MAAA,GAAS,GAAA,GAAM,KAAA,CAAM,KAAA,GAAQ,CAAC,CAAA;AACvE,IAAA,KAAA,IAAS,KAAA;AAAA,EACV;AACA,EAAA,MAAM,MAAM,KAAA,GAAQ,MAAA;AACpB,EAAA,IAAI,GAAA,GAAM,KAAA,EAAO,MAAM,IAAI,SAAS,8BAA8B,CAAA;AAClE,EAAA,OAAO,EAAE,GAAA,EAAK,KAAA,EAAO,GAAA,EAAI;AAC1B;AAGO,SAAS,UAAA,CAAW,OAAmB,IAAA,EAA0B;AACvE,EAAA,MAAM,MAAiB,EAAC;AACxB,EAAA,KAAA,IAAS,EAAA,GAAK,IAAA,CAAK,KAAA,EAAO,EAAA,GAAK,KAAK,GAAA,IAAM;AACzC,IAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,KAAA,EAAO,EAAA,EAAI,KAAK,GAAG,CAAA;AAC1C,IAAA,GAAA,CAAI,KAAK,KAAK,CAAA;AACd,IAAA,EAAA,GAAK,KAAA,CAAM,GAAA;AAAA,EACZ;AACA,EAAA,OAAO,GAAA;AACR;AAGO,SAAS,SAAA,CAAU,MAA2B,GAAA,EAAsB;AAC1E,EAAA,IAAI,IAAA,EAAM,GAAA,KAAQ,GAAA,EAAK,MAAM,IAAI,QAAA,CAAS,CAAA,eAAA,EAAkB,GAAA,CAAI,QAAA,CAAS,EAAE,CAAC,CAAA,CAAE,CAAA;AAC9E,EAAA,OAAO,IAAA;AACR;AAEO,SAAS,SAAA,CAAU,OAAmB,IAAA,EAA2B;AACvE,EAAA,OAAO,KAAA,CAAM,QAAA,CAAS,IAAA,CAAK,KAAA,EAAO,KAAK,GAAG,CAAA;AAC3C;;;ACnEA,eAAsB,KAAA,CACrB,IAAA,EACA,GAAA,EACA,IAAA,EACA,GAAA,EACoB;AACpB,EAAA,IAAI,QAAA;AACJ,EAAA,IAAI;AACH,IAAA,QAAA,GAAW,MAAM,IAAA,CAAK,GAAA,EAAK,IAAI,CAAA;AAAA,EAChC,SAAS,CAAA,EAAG;AACX,IAAA,MAAM,IAAI,cAAA;AAAA,MACT,oBAAA;AAAA,MACA,CAAA,EAAG,GAAG,CAAA,uBAAA,EAA2B,CAAA,CAAY,OAAO,CAAA;AAAA,KACrD;AAAA,EACD;AACA,EAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AACjB,IAAA,MAAM,OACL,QAAA,CAAS,MAAA,IAAU,OAAO,QAAA,CAAS,MAAA,KAAW,MAAM,oBAAA,GAAuB,gBAAA;AAC5E,IAAA,MAAM,IAAI,eAAe,IAAA,EAAM,CAAA,EAAG,GAAG,CAAA,UAAA,EAAa,QAAA,CAAS,MAAM,CAAA,CAAE,CAAA;AAAA,EACpE;AACA,EAAA,OAAO,QAAA;AACR;;;AChBA,IAAM,QAAA,GAAW,EAAA;AACjB,IAAM,OAAA,GAAU,CAAA;AAChB,IAAM,YAAA,GAAe,CAAA;AACrB,IAAM,GAAA,GAAM,CAAA;AACZ,IAAM,gBAAA,GAAmB,EAAA;AACzB,IAAM,UAAA,GAAa,GAAA;AAGnB,IAAM,gBAAA,GAAmB,GAAA;AAAA,EACxB,QAAA;AAAA,EACA,GAAA,CAAI,GAAA,EAAK,UAAA,CAAW,EAAA,CAAG,EAAA,EAAM,GAAA,EAAM,EAAA,EAAM,CAAA,EAAM,GAAA,EAAM,CAAA,EAAM,CAAA,EAAM,CAAA,EAAM,CAAI,CAAC,CAAA;AAAA,EAC5E,UAAA,CAAW,EAAA,CAAG,CAAA,EAAM,CAAI;AACzB,CAAA;AAsBA,SAAS,WAAWC,IAAAA,EAAyB;AAC5C,EAAA,OAAO,UAAA,CAAW,IAAA,CAAKA,IAAAA,CAAI,KAAA,CAAM,KAAK,CAAA,IAAK,EAAC,EAAG,CAAC,IAAA,KAAS,MAAA,CAAO,QAAA,CAAS,IAAA,EAAM,EAAE,CAAC,CAAA;AACnF;AAGA,SAAS,WAAW,KAAA,EAA2B;AAC9C,EAAA,IAAI,EAAA,GAAK,CAAA;AACT,EAAA,OAAO,KAAK,KAAA,CAAM,MAAA,GAAS,KAAK,KAAA,CAAM,EAAE,MAAM,CAAA,EAAG,EAAA,EAAA;AACjD,EAAA,OAAO,GAAA,CAAI,KAAA,CAAM,QAAA,CAAS,EAAE,CAAC,CAAA;AAC9B;AAGA,SAAS,QAAA,GAAuB;AAC/B,EAAA,MAAM,QAAQ,MAAA,CAAO,eAAA,CAAgB,IAAI,UAAA,CAAW,CAAC,CAAC,CAAA;AACtD,EAAA,KAAA,CAAM,CAAC,CAAA,GAAK,KAAA,CAAM,CAAC,IAAI,EAAA,GAAQ,EAAA;AAC/B,EAAA,OAAO,KAAA;AACR;AAGO,SAAS,gBAAA,CAAiB,MAAc,KAAA,EAA+B;AAC7E,EAAA,OAAO,GAAA;AAAA,IACN,QAAA;AAAA,IACA,GAAA,CAAI,OAAA,EAAS,UAAA,CAAW,EAAA,CAAG,CAAC,CAAC,CAAA;AAAA,IAC7B,GAAA,CAAI,UAAU,gBAAA,EAAkB,GAAA,CAAI,cAAc,UAAA,CAAW,IAAI,CAAC,CAAC,CAAA;AAAA,IACnE,GAAA,CAAI,SAAS,KAAK,CAAA;AAAA,IAClB,UAAA,CAAW,EAAA,CAAG,CAAA,EAAM,CAAA,EAAM,GAAI;AAAA,GAC/B;AACD;AAGA,SAAS,gBAAgB,IAAA,EAAsB;AAC9C,EAAA,MAAM,KAAA,GAAQ,uDAAA,CAAwD,IAAA,CAAK,IAAI,CAAA;AAC/E,EAAA,IAAI,UAAU,IAAA,EAAM,MAAM,IAAI,QAAA,CAAS,CAAA,gBAAA,EAAmB,IAAI,CAAA,CAAE,CAAA;AAChE,EAAA,MAAM,GAAG,CAAA,EAAG,EAAA,EAAI,GAAG,CAAA,EAAG,EAAA,EAAI,CAAA,EAAG,QAAQ,CAAA,GAAI,KAAA;AACzC,EAAA,OAAA,qBAAW,IAAA,CAAK,CAAA,EAAG,CAAC,CAAA,CAAA,EAAI,EAAE,IAAI,CAAC,CAAA,CAAA,EAAI,CAAC,CAAA,CAAA,EAAI,EAAE,IAAI,CAAC,CAAA,EAAG,YAAY,EAAE,CAAA,CAAA,CAAG,GAAE,WAAA,EAAY;AAClF;AAGA,SAAS,QAAQ,KAAA,EAA4B;AAC5C,EAAA,MAAM,CAAC,UAAA,EAAY,KAAK,CAAA,GAAI,UAAA,CAAW,KAAA,EAAO,SAAA,CAAU,QAAA,CAAS,KAAA,EAAO,CAAC,CAAA,EAAG,QAAQ,CAAC,CAAA;AACrF,EAAA,MAAM,MAAA,GAAS,SAAA,CAAU,UAAA,CAAW,KAAA,EAAO,SAAA,CAAU,UAAA,EAAY,QAAQ,CAAC,CAAA,CAAE,CAAC,CAAA,EAAG,OAAO,CAAA;AACvF,EAAA,MAAM,IAAA,GAAO,OAAO,QAAA,CAAS,UAAA,CAAW,UAAU,KAAA,EAAO,MAAM,CAAC,CAAA,EAAG,EAAE,CAAA;AAErE,EAAA,IAAI,OAAO,CAAA,EAAG;AACb,IAAA,MAAM,IAAI,cAAA;AAAA,MACT,gBAAA;AAAA,MACA,6CAA6C,IAAI,CAAA,CAAA;AAAA,KAClD;AAAA,EACD;AACA,EAAA,OAAO,SAAA,CAAU,OAAO,QAAQ,CAAA;AACjC;AAGA,SAAS,SAAA,CAAU,OAAmB,KAAA,EAAyB;AAC9D,EAAA,MAAM,UAAA,GAAa,SAAA;AAAA,IAClB,UAAA,CAAW,KAAA,EAAO,SAAA,CAAU,UAAA,CAAW,KAAA,EAAO,KAAK,CAAA,CAAE,CAAC,CAAA,EAAG,UAAU,CAAC,CAAA,CAAE,CAAC,CAAA;AAAA,IACvE;AAAA,GACD;AACA,EAAA,MAAM,YAAA,GAAe,UAAU,UAAA,CAAW,KAAA,EAAO,UAAU,CAAA,CAAE,CAAC,GAAG,QAAQ,CAAA;AACzE,EAAA,MAAM,OAAA,GAAU,UAAU,UAAA,CAAW,KAAA,EAAO,YAAY,CAAA,CAAE,CAAC,GAAG,UAAU,CAAA;AACxE,EAAA,MAAM,MAAA,GAAS,UAAU,UAAA,CAAW,KAAA,EAAO,OAAO,CAAA,CAAE,CAAC,GAAG,YAAY,CAAA;AACpE,EAAA,OAAO,SAAA,CAAU,SAAS,KAAA,EAAO,MAAA,CAAO,OAAO,MAAA,CAAO,GAAG,GAAG,QAAQ,CAAA;AACrE;AASO,SAAS,mBAAmB,KAAA,EAAmC;AACrE,EAAA,IAAI;AACH,IAAA,MAAM,OAAA,GAAU,SAAA,CAAU,KAAA,EAAO,OAAA,CAAQ,KAAK,CAAC,CAAA;AAG/C,IAAA,MAAM,KAAK,OAAA,IAAW,IAAA,EAAM,GAAG,IAAI,CAAA,GAAI,UAAA,CAAW,KAAA,EAAO,OAAO,CAAA;AAChE,IAAA,MAAM,MAAA,GAAS,SAAA,CAAU,UAAA,CAAW,KAAA,EAAO,SAAA,CAAU,OAAA,EAAS,QAAQ,CAAC,CAAA,CAAE,CAAC,CAAA,EAAG,YAAY,CAAA;AACzF,IAAA,MAAM,QAAQ,IAAA,CAAK,IAAA,CAAK,CAAC,IAAA,KAAS,IAAA,CAAK,QAAQ,OAAO,CAAA;AACtD,IAAA,MAAM,OAAA,GAAU,IAAI,WAAA,EAAY,CAAE,MAAA,CAAO,SAAA,CAAU,KAAA,EAAO,SAAA,CAAU,IAAA,EAAM,gBAAgB,CAAC,CAAC,CAAA;AAC5F,IAAA,OAAO;AAAA,MACN,IAAA,EAAM,GAAA,CAAI,SAAA,CAAU,KAAA,EAAO,MAAM,CAAC,CAAA;AAAA,MAClC,IAAA,EAAM,gBAAgB,OAAO,CAAA;AAAA,MAC7B,GAAI,KAAA,GAAQ,EAAE,KAAA,EAAO,UAAA,CAAW,SAAA,CAAU,KAAA,EAAO,KAAK,CAAC,CAAA,EAAE,GAAI;AAAC,KAC/D;AAAA,EACD,SAAS,CAAA,EAAG;AACX,IAAA,IAAI,CAAA,YAAa,gBAAgB,MAAM,CAAA;AACvC,IAAA,MAAM,IAAI,cAAA,CAAe,gBAAA,EAAkB,CAAA,uBAAA,EAA2B,CAAA,CAAY,OAAO,CAAA,CAAE,CAAA;AAAA,EAC5F;AACD;AAEA,eAAe,IAAA,CAAK,SAAyB,IAAA,EAAuC;AACnF,EAAA,MAAM,WAAW,MAAM,KAAA;AAAA,IACtB,OAAA,CAAQ,SAAS,UAAA,CAAW,KAAA;AAAA,IAC5B,OAAA,CAAQ,GAAA;AAAA,IACR;AAAA,MACC,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA,EAAS,EAAE,cAAA,EAAgB,6BAAA,EAA8B;AAAA,MACzD;AAAA,KACD;AAAA,IACA;AAAA,GACD;AACA,EAAA,OAAO,IAAI,UAAA,CAAW,MAAM,QAAA,CAAS,aAAa,CAAA;AACnD;AAQO,SAAS,cAAc,OAAA,EAAiC;AAC9D,EAAA,MAAM,IAAA,GAAO,QAAQ,IAAA,IAAQ,SAAA;AAC7B,EAAA,OAAO;AAAA,IACN,IAAA;AAAA,IACA,MAAM,OAAA,CAAQ,IAAA,EAAc,KAAA,EAAkC;AAC7D,MAAA,MAAM,QAAQ,QAAA,EAAS;AACvB,MAAA,MAAM,QAAQ,MAAM,IAAA,CAAK,SAAS,gBAAA,CAAiB,IAAA,EAAM,KAAK,CAAC,CAAA;AAC/D,MAAA,MAAM,KAAA,GAAQ,mBAAmB,KAAK,CAAA;AACtC,MAAA,IAAI,KAAA,CAAM,SAAS,IAAA,EAAM;AACxB,QAAA,MAAM,IAAI,cAAA,CAAe,gBAAA,EAAkB,sCAAsC,CAAA;AAAA,MAClF;AACA,MAAA,IAAI,KAAA,CAAM,KAAA,KAAU,UAAA,CAAW,KAAK,CAAA,EAAG;AACtC,QAAA,MAAM,IAAI,cAAA,CAAe,gBAAA,EAAkB,wCAAwC,CAAA;AAAA,MACpF;AACA,MAAA,OAAO;AAAA,QACN,MAAA,EAAQ,IAAA;AAAA,QACR,IAAA;AAAA,QACA,GAAI,KAAA,KAAU,MAAA,GAAY,EAAC,GAAI,EAAE,KAAA,EAAM;AAAA,QACvC,aAAa,KAAA,CAAM,IAAA;AAAA,QACnB,QAAA,EAAU,IAAA;AAAA,QACV,QAAA,EAAU,EAAE,GAAA,EAAK,QAAA,CAAS,KAAK,CAAA,EAAG,GAAA,EAAK,QAAQ,GAAA;AAAI,OACpD;AAAA,IACD,CAAA;AAAA,IACA,SAAS,OAAA,EAAoC;AAC5C,MAAA,OAAO,OAAA,CAAQ,QAAQ,OAAO,CAAA;AAAA,IAC/B;AAAA,GACD;AACD;AAGO,SAAS,iBAAiB,OAAA,EAA4D;AAC5F,EAAA,MAAM,GAAA,GAAM,QAAQ,QAAA,CAAS,GAAA;AAC7B,EAAA,OAAO,GAAA,KAAQ,MAAA,GAAY,MAAA,GAAY,UAAA,CAAW,GAAG,CAAA;AACtD;;;AC3IA,IAAM,MAAA,GAAS,gBAAA;AAEf,SAASD,SAAQ,OAAA,EAAiC;AACjD,EAAA,OAAO,IAAI,cAAA,CAAe,gBAAA,EAAkB,OAAO,CAAA;AACpD;AAEA,SAAS,YAAY,IAAA,EAAwB;AAC5C,EAAA,MAAM,CAAA,GAAI,IAAA;AACV,EAAA,IACC,OAAO,GAAG,EAAA,KAAO,QAAA,IACjB,CAAC,MAAA,CAAO,IAAA,CAAK,CAAA,CAAE,EAAE,CAAA,IACjB,OAAO,EAAE,KAAA,KAAU,QAAA,IACnB,OAAO,CAAA,CAAE,IAAA,EAAM,MAAA,KAAW,YAC1B,OAAO,CAAA,CAAE,IAAA,CAAK,MAAA,KAAW,QAAA,EACxB;AACD,IAAA,MAAMA,SAAQ,wCAAwC,CAAA;AAAA,EACvD;AACA,EAAA,OAAO,CAAA;AACR;AAEA,SAAS,UAAU,IAAA,EAAkD;AACpE,EAAA,IAAI;AACH,IAAA,OAAO,IAAA,CAAK,MAAM,IAAI,CAAA;AAAA,EACvB,CAAA,CAAA,MAAQ;AACP,IAAA,MAAMA,SAAQ,mDAAmD,CAAA;AAAA,EAClE;AACD;AAGA,SAAS,MAAA,CAAO,QAAA,EAAkB,EAAA,EAAY,IAAA,EAAsB;AACnE,EAAA,MAAM,QAAQ,QAAA,CAAS,KAAA,CAAM,IAAI,CAAA,CAAE,OAAO,OAAO,CAAA;AACjD,EAAA,KAAA,MAAW,CAAC,KAAA,EAAO,IAAI,CAAA,IAAK,KAAA,CAAM,SAAQ,EAAG;AAC5C,IAAA,MAAM,IAAA,GAAO,UAAU,IAAI,CAAA;AAC3B,IAAA,IAAI,IAAA,CAAK,SAAS,EAAA,EAAI;AACtB,IAAA,IAAI,IAAA,CAAK,MAAA,KAAW,IAAA,EAAM,MAAMA,SAAQ,mDAAmD,CAAA;AAC3F,IAAA,OAAO,KAAA,GAAQ,CAAA;AAAA,EAChB;AACA,EAAA,OAAO,CAAA;AACR;AAeO,SAAS,oBAAoB,OAAA,EAAiC;AACpE,EAAA,MAAM,IAAA,GAAO,QAAQ,IAAA,IAAQ,gBAAA;AAC7B,EAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,GAAA,CAAI,OAAA,CAAQ,QAAQ,EAAE,CAAA;AAC3C,EAAA,MAAM,KAAA,GAAQ,QAAQ,IAAA,KAAS,MAAA,GAAY,EAAC,GAAI,EAAE,IAAA,EAAM,OAAA,CAAQ,IAAA,EAAK;AACrE,EAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,KAAA,IAAS,UAAA,CAAW,KAAA;AACzC,EAAA,MAAM,GAAA,GAAM,CAAC,IAAA,KACZ,KAAA,CAAM,IAAA,EAAM,CAAA,EAAG,IAAI,CAAA,EAAG,IAAI,CAAA,CAAA,EAAI,MAAA,EAAW,aAAa,CAAA;AACvD,EAAA,MAAM,OAAA,GAAU,OAAO,IAAA,KACtB,QAAA,CAAS,IAAI,UAAA,CAAW,MAAA,CAAO,MAAM,GAAA,CAAI,IAAI,CAAA,EAAG,WAAA,EAAa,CAAC,CAAA;AAE/D,EAAA,OAAO;AAAA,IACN,IAAA;AAAA,IACA,MAAM,OAAA,CAAQ,IAAA,EAAc,KAAA,EAAkC;AAC7D,MAAA,MAAM,WAAW,MAAM,KAAA;AAAA,QACtB,IAAA;AAAA,QACA,GAAG,IAAI,CAAA,WAAA,CAAA;AAAA,QACP;AAAA,UACC,MAAA,EAAQ,MAAA;AAAA,UACR,OAAA,EAAS,EAAE,cAAA,EAAgB,kBAAA,EAAmB;AAAA,UAC9C,IAAA,EAAM,KAAK,SAAA,CAAU;AAAA,YACpB,MAAA,EAAQ,IAAA;AAAA,YACR,GAAI,KAAA,KAAU,MAAA,GAAY,EAAC,GAAI,EAAE,SAAS,KAAA,EAAM;AAAA,YAChD,GAAG;AAAA,WACH;AAAA,SACF;AAAA,QACA;AAAA,OACD;AACA,MAAA,MAAM,OAAA,GAAU,YAAY,MAAM,QAAA,CAAS,MAAK,CAAE,KAAA,CAAM,MAAM,IAAI,CAAC,CAAA;AACnE,MAAA,OAAO;AAAA,QACN,MAAA,EAAQ,IAAA;AAAA,QACR,IAAA,EAAM,QAAQ,IAAA,CAAK,MAAA;AAAA,QACnB,GAAI,KAAA,KAAU,MAAA,GAAY,EAAC,GAAI,EAAE,KAAA,EAAM;AAAA,QACvC,WAAA,EAAa,QAAQ,IAAA,CAAK,MAAA;AAAA,QAC1B,QAAA,EAAU,KAAA;AAAA,QACV,QAAA,EAAU;AAAA,UACT,OAAA,EAAS,IAAA;AAAA,UACT,IAAI,OAAA,CAAQ,EAAA;AAAA,UACZ,MAAM,OAAA,CAAQ,KAAA;AAAA,UACd,OAAA,EAAS,IAAA,CAAK,SAAA,CAAU,OAAA,CAAQ,IAAI;AAAA;AACrC,OACD;AAAA,IACD,CAAA;AAAA,IACA,MAAM,SAAS,OAAA,EAAoC;AAClD,MAAA,MAAM,EAAA,GAAK,QAAQ,QAAA,CAAS,EAAA;AAC5B,MAAA,IAAI,EAAA,KAAO,MAAA,EAAW,MAAMA,QAAAA,CAAQ,mCAAmC,CAAA;AACvE,MAAA,MAAM,IAAA,GAAO,MAAA,CAAO,MAAA,CAAO,MAAM,GAAA,CAAI,0BAA0B,CAAA,EAAG,IAAA,EAAK,EAAG,EAAA,EAAI,OAAA,CAAQ,IAAI,CAAA;AAC1F,MAAA,IAAI,IAAA,KAAS,GAAG,OAAO,OAAA;AACvB,MAAA,MAAM,EAAE,OAAM,GAAK,MAAA,CAAO,MAAM,GAAA,CAAI,aAAa,GAAG,IAAA,EAAK;AACzD,MAAA,MAAM,OAAO,KAAA,CAAM,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,UAAU,IAAI,CAAA;AAC/C,MAAA,IAAI,IAAA,EAAM,GAAA,KAAQ,SAAA,EAAW,OAAO,OAAA;AACpC,MAAA,MAAM,OAAA,GAAU,IAAA,CAAK,UAAA,KAAe,IAAA,IAAQ,IAAA,CAAK,UAAU,QAAA,CAAS,CAAA,EAAG,IAAA,CAAK,EAAE,CAAA,WAAA,CAAa,CAAA;AAC3F,MAAA,OAAO;AAAA,QACN,GAAG,OAAA;AAAA,QACH,QAAA,EAAU,IAAA;AAAA,QACV,QAAA,EAAU;AAAA,UACT,GAAG,OAAA,CAAQ,QAAA;AAAA,UACX,MAAM,IAAA,CAAK,EAAA;AAAA,UACX,MAAM,IAAA,CAAK,MAAA;AAAA,UACX,GAAI,IAAA,CAAK,IAAA,KAAS,IAAA,GAAO,EAAC,GAAI,EAAE,KAAA,EAAO,MAAA,CAAO,IAAA,CAAK,IAAI,CAAA,EAAE;AAAA,UACzD,KAAK,MAAM,OAAA,CAAQ,CAAA,YAAA,EAAe,IAAA,CAAK,EAAE,CAAA,WAAA,CAAa,CAAA;AAAA,UACtD,GAAI,OAAA,GAAU,EAAE,GAAA,EAAK,MAAM,OAAA,CAAQ,CAAA,YAAA,EAAe,IAAA,CAAK,EAAE,CAAA,WAAA,CAAa,CAAA,EAAE,GAAI;AAAC;AAC9E,OACD;AAAA,IACD;AAAA,GACD;AACD","file":"proof.js","sourcesContent":["// Proof of existence for the user's own documents: the bytes never leave the\n// device, only their SHA-256 does. A notary dates that digest; the receipt it\n// hands back is kept next to the file, in the user's own storage, and anyone\n// holding the file and the receipt can check the two still belong together.\n\nimport { sha256Hex } from '../selfstore/digest';\nimport { isSelfstoreError, SelfstoreError } from '../selfstore/errors';\nimport { toBytes, type FileBytes } from '../simple/bytes';\nimport type { SimpleRecord } from '../simple/simple';\n\n/**\n * What a notary hands back for one digest. `evidence` is the notary's own\n * material (a timestamp token, an inclusion path, a download address), as\n * strings - base64 for bytes - so a receipt is plain JSON and survives every\n * destination a store can write to.\n */\nexport interface Receipt {\n\t/** The notary that issued it (`Notary.name`). */\n\treadonly notary: string;\n\t/** Lowercase hex SHA-256 of the document. */\n\treadonly hash: string;\n\t/** The label sent with the deposit, if any. */\n\treadonly label?: string;\n\t/** ISO 8601 instant the notary vouches for (its clock, not the device's). */\n\treadonly depositedAt: string;\n\t/** False while the notary still has something to add (an anchor, a seal). */\n\treadonly complete: boolean;\n\treadonly evidence: Readonly<Record<string, string>>;\n}\n\n/**\n * Anyone who dates a digest. `deposit` must never see more than the digest and\n * the label; `complete` is called later - the next day, the next launch - and\n * returns the same receipt with whatever the notary could not give at once.\n * A notary that is final on deposit returns its argument unchanged.\n */\nexport interface Notary {\n\treadonly name: string;\n\tdeposit(hash: string, label?: string): Promise<Receipt>;\n\tcomplete(receipt: Receipt): Promise<Receipt>;\n}\n\n/** A receipt as `prove()` keeps it: the notary's, plus what the device measured. */\nexport interface Proof extends Receipt {\n\treadonly kind: 'selfstore-proof';\n\treadonly version: 1;\n\treadonly algorithm: 'SHA-256';\n\t/** Size of the document in bytes. */\n\treadonly size: number;\n\t/** The store file the proof belongs to, when there is one. */\n\treadonly file?: string;\n}\n\n/** Where proofs are kept: the simple store fits as is. */\nexport interface ProofShelf {\n\tput(collection: string, record: SimpleRecord): Promise<void>;\n}\n\n/** The collection `prove()` and `completeProof()` write to. */\nexport const PROOFS = 'proofs';\n\nexport interface ProveOptions {\n\tnotary: Notary;\n\t/** Sent to the notary with the digest. A TYPE ('invoice', 'inventory'),\n\t * never a name or a piece of the content: it leaves the device. */\n\tlabel?: string;\n\t/** Keep the proof in this store, under `PROOFS`, keyed by `file` or by hash. */\n\tstore?: ProofShelf;\n\t/** Id of the store file the document is (as `putFile` returned it). */\n\tfile?: string;\n}\n\n/** The result of `verify()`. */\nexport interface ProofCheck {\n\t/** The bytes hash to the receipt's digest (and size, when it carries one). */\n\treadonly matches: boolean;\n\t/** What the bytes hash to now. */\n\treadonly hash: string;\n\t/** Whether the notary had finished with this receipt. */\n\treadonly complete: boolean;\n}\n\nconst HEX_DIGEST = /^[0-9a-f]{64}$/;\n\nfunction refused(message: string): SelfstoreError {\n\treturn new SelfstoreError('NOTARY_REFUSED', message);\n}\n\n/** A notary that answers for another digest, or for another notary, is not believed. */\nfunction checkAnswer(answer: Receipt, hash: string, notary: Notary): void {\n\tif (typeof answer?.hash !== 'string' || answer.hash.toLowerCase() !== hash) {\n\t\tthrow refused(`${notary.name} answered for another digest`);\n\t}\n\tif (answer.notary !== notary.name) {\n\t\tthrow refused(`receipt names ${String(answer.notary)}, not ${notary.name}`);\n\t}\n\tif (Number.isNaN(Date.parse(answer.depositedAt))) {\n\t\tthrow refused(`${notary.name} gave no readable deposit time`);\n\t}\n}\n\nasync function shelve(proof: Proof, store: ProofShelf | undefined): Promise<void> {\n\tif (store) await store.put(PROOFS, { ...proof, id: proof.file ?? proof.hash });\n}\n\n/**\n * Hash `blob` on the device, deposit the digest with `options.notary`, and\n * return the proof - kept in `options.store` too when one is given. Only the\n * digest and the label leave the device.\n *\n * Throws NOTARY_UNAVAILABLE when the notary cannot be reached (retry later)\n * and NOTARY_REFUSED when it refuses or answers for something else.\n */\nexport async function prove(blob: FileBytes, options: ProveOptions): Promise<Proof> {\n\tconst bytes = await toBytes(blob);\n\tconst hash = await sha256Hex(bytes);\n\tconst answer = await options.notary.deposit(hash, options.label);\n\tcheckAnswer(answer, hash, options.notary);\n\tconst proof: Proof = {\n\t\t...answer,\n\t\thash,\n\t\tkind: 'selfstore-proof',\n\t\tversion: 1,\n\t\talgorithm: 'SHA-256',\n\t\tsize: bytes.length,\n\t\t...(options.file === undefined ? {} : { file: options.file })\n\t};\n\tawait shelve(proof, options.store);\n\treturn proof;\n}\n\n/**\n * Ask the notary for what it could not give on deposit. A complete proof is\n * returned as is, without a call. The fields the device measured are kept;\n * the notary may only add to its own.\n */\nexport async function completeProof(\n\tproof: Proof,\n\toptions: { notary: Notary; store?: ProofShelf }\n): Promise<Proof> {\n\tif (proof.complete) return proof;\n\tconst answer = await options.notary.complete(proof);\n\tcheckAnswer(answer, proof.hash, options.notary);\n\tconst completed: Proof = {\n\t\t...answer,\n\t\thash: proof.hash,\n\t\tkind: proof.kind,\n\t\tversion: proof.version,\n\t\talgorithm: proof.algorithm,\n\t\tsize: proof.size,\n\t\t...(proof.file === undefined ? {} : { file: proof.file })\n\t};\n\tawait shelve(completed, options.store);\n\treturn completed;\n}\n\n/**\n * Hash `blob` again and compare it with the receipt. This proves the bytes are\n * the ones the receipt names; that the receipt itself is genuine is what the\n * notary's evidence is for, checked with the notary's own verifier.\n *\n * Throws BAD_FORMAT on a receipt that carries no SHA-256 digest at all - a\n * damaged receipt is not a document that changed.\n */\nexport async function verify(\n\tblob: FileBytes,\n\treceipt: Pick<Receipt, 'hash' | 'complete'> & { size?: number }\n): Promise<ProofCheck> {\n\tconst expected = typeof receipt?.hash === 'string' ? receipt.hash.toLowerCase() : '';\n\tif (!HEX_DIGEST.test(expected)) {\n\t\tthrow new SelfstoreError('BAD_FORMAT', 'the receipt carries no SHA-256 digest');\n\t}\n\tconst bytes = await toBytes(blob);\n\tconst hash = await sha256Hex(bytes);\n\tconst sizeAgrees = receipt.size === undefined || receipt.size === bytes.length;\n\treturn { matches: hash === expected && sizeAgrees, hash, complete: receipt.complete === true };\n}\n\n/** Where proofs are read back from: the simple store fits as is. */\nexport interface ProofLibrary extends ProofShelf {\n\tall(collection: string): readonly SimpleRecord[];\n}\n\nfunction isProof(record: SimpleRecord): boolean {\n\treturn (\n\t\trecord.kind === 'selfstore-proof' &&\n\t\ttypeof record.hash === 'string' &&\n\t\tHEX_DIGEST.test(record.hash) &&\n\t\ttypeof record.notary === 'string' &&\n\t\ttypeof record.complete === 'boolean'\n\t);\n}\n\n/**\n * Every proof kept in `store`, oldest deposit first. Records that are not\n * proofs - another app's, a damaged one - are skipped rather than trusted.\n */\nexport function proofsIn(store: Pick<ProofLibrary, 'all'>): Proof[] {\n\treturn store\n\t\t.all(PROOFS)\n\t\t.filter(isProof)\n\t\t.map((record) => {\n\t\t\tconst { id: _id, ...proof } = record;\n\t\t\treturn proof as unknown as Proof;\n\t\t})\n\t\t.sort((a, b) => Date.parse(a.depositedAt) - Date.parse(b.depositedAt));\n}\n\n/** What `completePending()` did, proof by proof. */\nexport interface PendingRound {\n\t/** Finished this round, and written back to the store. */\n\treadonly completed: readonly Proof[];\n\t/** Still waiting: the notary has nothing to add yet, could not be reached,\n\t * or is not among the notaries given. Ask again on a later launch. */\n\treadonly pending: readonly Proof[];\n\t/** The notary answered for something else; kept as it was, not overwritten. */\n\treadonly refused: readonly Proof[];\n}\n\nfunction isCode(error: unknown, code: string): boolean {\n\treturn isSelfstoreError(error) && error.code === code;\n}\n\n/**\n * Ask each notary to finish the incomplete proofs it issued - the call an app\n * makes at launch, since a notary that anchors its digests finishes a receipt\n * hours after the deposit. A notary that cannot be reached is not asked again\n * this round; a proof whose notary is not in `notaries` waits. Only a proof\n * that came back complete is written to the store.\n */\nexport async function completePending(options: {\n\tstore: ProofLibrary;\n\tnotaries: readonly Notary[];\n}): Promise<PendingRound> {\n\tconst byName = new Map(options.notaries.map((notary) => [notary.name, notary]));\n\tconst unreachable = new Set<string>();\n\tconst completed: Proof[] = [];\n\tconst pending: Proof[] = [];\n\tconst refused: Proof[] = [];\n\tfor (const proof of proofsIn(options.store)) {\n\t\tif (proof.complete) continue;\n\t\tconst notary = byName.get(proof.notary);\n\t\tif (notary === undefined || unreachable.has(notary.name)) {\n\t\t\tpending.push(proof);\n\t\t\tcontinue;\n\t\t}\n\t\ttry {\n\t\t\tconst answer = await completeProof(proof, { notary });\n\t\t\tif (answer.complete) {\n\t\t\t\tawait shelve(answer, options.store);\n\t\t\t\tcompleted.push(answer);\n\t\t\t} else {\n\t\t\t\tpending.push(proof);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tif (isCode(error, 'NOTARY_UNAVAILABLE')) {\n\t\t\t\tunreachable.add(notary.name);\n\t\t\t\tpending.push(proof);\n\t\t\t} else if (isCode(error, 'NOTARY_REFUSED')) {\n\t\t\t\trefused.push(proof);\n\t\t\t} else {\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\t}\n\treturn { completed, pending, refused };\n}\n","// The few DER shapes an RFC 3161 exchange needs, and no more. A timestamp\n// request is five fields and the reply is read along one path, so a general\n// ASN.1 library would be a fourth runtime dependency for two functions.\n\n/** One decoded TLV: `start` and `end` bound its CONTENT. */\nexport interface DerNode {\n\treadonly tag: number;\n\treadonly start: number;\n\treadonly end: number;\n}\n\nexport class DerError extends Error {}\n\nfunction encodeLength(length: number): Uint8Array {\n\tif (length < 0x80) return Uint8Array.of(length);\n\tconst bytes: number[] = [];\n\tfor (let rest = length; rest > 0; rest = Math.floor(rest / 256)) bytes.unshift(rest % 256);\n\treturn Uint8Array.of(0x80 | bytes.length, ...bytes);\n}\n\n/** Encode one TLV around already-encoded content. */\nexport function tlv(tag: number, ...parts: Uint8Array[]): Uint8Array {\n\tconst length = parts.reduce((sum, part) => sum + part.length, 0);\n\tconst head = encodeLength(length);\n\tconst out = new Uint8Array(1 + head.length + length);\n\tout[0] = tag;\n\tout.set(head, 1);\n\tlet at = 1 + head.length;\n\tfor (const part of parts) {\n\t\tout.set(part, at);\n\t\tat += part.length;\n\t}\n\treturn out;\n}\n\n/** Read the TLV that starts at `offset`. Indefinite lengths are BER, not DER: refused. */\nexport function readNode(bytes: Uint8Array, offset: number, limit = bytes.length): DerNode {\n\tif (offset + 2 > limit) throw new DerError('truncated header');\n\tconst tag = bytes[offset];\n\tconst first = bytes[offset + 1];\n\tlet start = offset + 2;\n\tlet length = first;\n\tif (first & 0x80) {\n\t\tconst count = first & 0x7f;\n\t\tif (count === 0 || count > 4) throw new DerError('unsupported length');\n\t\tif (start + count > limit) throw new DerError('truncated length');\n\t\tlength = 0;\n\t\tfor (let i = 0; i < count; i++) length = length * 256 + bytes[start + i];\n\t\tstart += count;\n\t}\n\tconst end = start + length;\n\tif (end > limit) throw new DerError('content runs past its parent');\n\treturn { tag, start, end };\n}\n\n/** The direct children of a constructed node. */\nexport function childrenOf(bytes: Uint8Array, node: DerNode): DerNode[] {\n\tconst out: DerNode[] = [];\n\tfor (let at = node.start; at < node.end;) {\n\t\tconst child = readNode(bytes, at, node.end);\n\t\tout.push(child);\n\t\tat = child.end;\n\t}\n\treturn out;\n}\n\n/** The node's content, or a refusal when its tag is not the one expected. */\nexport function expectTag(node: DerNode | undefined, tag: number): DerNode {\n\tif (node?.tag !== tag) throw new DerError(`expected tag 0x${tag.toString(16)}`);\n\treturn node;\n}\n\nexport function contentOf(bytes: Uint8Array, node: DerNode): Uint8Array {\n\treturn bytes.subarray(node.start, node.end);\n}\n","// One way to call a notary over HTTP, so every adapter maps the same failures\n// to the same codes: unreachable, overloaded or rate-limited is worth a retry,\n// any other refusal is not.\n\nimport { SelfstoreError } from '../selfstore/errors';\n\n/** Fetch `url`, throwing NOTARY_UNAVAILABLE or NOTARY_REFUSED instead of returning a failure. */\nexport async function reach(\n\tsend: typeof fetch,\n\turl: string,\n\tinit: RequestInit | undefined,\n\twho: string\n): Promise<Response> {\n\tlet response: Response;\n\ttry {\n\t\tresponse = await send(url, init);\n\t} catch (e) {\n\t\tthrow new SelfstoreError(\n\t\t\t'NOTARY_UNAVAILABLE',\n\t\t\t`${who} could not be reached: ${(e as Error).message}`\n\t\t);\n\t}\n\tif (!response.ok) {\n\t\tconst code =\n\t\t\tresponse.status >= 500 || response.status === 429 ? 'NOTARY_UNAVAILABLE' : 'NOTARY_REFUSED';\n\t\tthrow new SelfstoreError(code, `${who} answered ${response.status}`);\n\t}\n\treturn response;\n}\n","// A notary over any RFC 3161 time-stamping authority. The authority signs the\n// digest and the time in one token, so the receipt is complete on deposit: the\n// token (the `.tsr` file) is the evidence, and `openssl ts -verify` checks it\n// against the authority's certificate without this library.\n\nimport { fromBase64, toBase64 } from '../selfstore/base64';\nimport { hex } from '../selfstore/digest';\nimport { SelfstoreError } from '../selfstore/errors';\nimport { childrenOf, contentOf, DerError, expectTag, readNode, tlv, type DerNode } from './der';\nimport type { Notary, Receipt } from './proof';\nimport { reach } from './reach';\n\nconst SEQUENCE = 0x30;\nconst INTEGER = 0x02;\nconst OCTET_STRING = 0x04;\nconst OID = 0x06;\nconst GENERALIZED_TIME = 0x18;\nconst EXPLICIT_0 = 0xa0;\n\n/** id-sha256, 2.16.840.1.101.3.4.2.1, with its NULL parameters. */\nconst SHA256_ALGORITHM = tlv(\n\tSEQUENCE,\n\ttlv(OID, Uint8Array.of(0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01)),\n\tUint8Array.of(0x05, 0x00)\n);\n\nexport interface Rfc3161Options {\n\t/** The authority's endpoint. In a browser it must answer CORS, or sit\n\t * behind a relay of yours that does: most public authorities do not. */\n\turl: string;\n\t/** Receipt `notary` field. Defaults to 'rfc3161'. */\n\tname?: string;\n\t/** Injected for tests and relays; defaults to the global fetch. */\n\tfetch?: typeof fetch;\n}\n\n/** What a timestamp token says, read without checking its signature. */\nexport interface TimestampToken {\n\t/** Lowercase hex of the digest the authority stamped. */\n\treadonly hash: string;\n\t/** ISO 8601 instant the authority signed. */\n\treadonly time: string;\n\t/** The nonce echoed back, as lowercase hex, when there is one. */\n\treadonly nonce?: string;\n}\n\nfunction hexToBytes(hex: string): Uint8Array {\n\treturn Uint8Array.from(hex.match(/../g) ?? [], (pair) => Number.parseInt(pair, 16));\n}\n\n/** Leading zero bytes are DER's sign padding, not part of the value. */\nfunction integerHex(bytes: Uint8Array): string {\n\tlet at = 0;\n\twhile (at < bytes.length - 1 && bytes[at] === 0) at++;\n\treturn hex(bytes.subarray(at));\n}\n\n/** Eight random bytes, positive and minimal as a DER INTEGER. */\nfunction newNonce(): Uint8Array {\n\tconst nonce = crypto.getRandomValues(new Uint8Array(8));\n\tnonce[0] = (nonce[0] & 0x3f) | 0x40;\n\treturn nonce;\n}\n\n/** A TimeStampReq (RFC 3161 section 2.4.1) for a SHA-256 digest, asking for the certificate. */\nexport function timestampRequest(hash: string, nonce: Uint8Array): Uint8Array {\n\treturn tlv(\n\t\tSEQUENCE,\n\t\ttlv(INTEGER, Uint8Array.of(1)),\n\t\ttlv(SEQUENCE, SHA256_ALGORITHM, tlv(OCTET_STRING, hexToBytes(hash))),\n\t\ttlv(INTEGER, nonce),\n\t\tUint8Array.of(0x01, 0x01, 0xff)\n\t);\n}\n\n/** YYYYMMDDHHMMSS[.fff]Z to ISO 8601. */\nfunction generalizedTime(text: string): string {\n\tconst parts = /^(\\d{4})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\.\\d+)?Z$/.exec(text);\n\tif (parts === null) throw new DerError(`unreadable time ${text}`);\n\tconst [, y, mo, d, h, mi, s, fraction] = parts;\n\treturn new Date(`${y}-${mo}-${d}T${h}:${mi}:${s}${fraction ?? ''}Z`).toISOString();\n}\n\n/** TimeStampResp: the status, or the token when it was granted. */\nfunction tokenOf(bytes: Uint8Array): DerNode {\n\tconst [statusInfo, token] = childrenOf(bytes, expectTag(readNode(bytes, 0), SEQUENCE));\n\tconst status = expectTag(childrenOf(bytes, expectTag(statusInfo, SEQUENCE))[0], INTEGER);\n\tconst code = Number.parseInt(integerHex(contentOf(bytes, status)), 16);\n\t// 0 granted, 1 granted with modifications; anything else is a refusal.\n\tif (code > 1) {\n\t\tthrow new SelfstoreError(\n\t\t\t'NOTARY_REFUSED',\n\t\t\t`the authority refused the request (status ${code})`\n\t\t);\n\t}\n\treturn expectTag(token, SEQUENCE);\n}\n\n/** ContentInfo > SignedData > EncapsulatedContentInfo > TSTInfo. */\nfunction tstInfoOf(bytes: Uint8Array, token: DerNode): DerNode {\n\tconst signedData = expectTag(\n\t\tchildrenOf(bytes, expectTag(childrenOf(bytes, token)[1], EXPLICIT_0))[0],\n\t\tSEQUENCE\n\t);\n\tconst encapsulated = expectTag(childrenOf(bytes, signedData)[2], SEQUENCE);\n\tconst wrapper = expectTag(childrenOf(bytes, encapsulated)[1], EXPLICIT_0);\n\tconst octets = expectTag(childrenOf(bytes, wrapper)[0], OCTET_STRING);\n\treturn expectTag(readNode(bytes, octets.start, octets.end), SEQUENCE);\n}\n\n/**\n * Read the digest, the time and the nonce out of a TimeStampResp (the `.tsr`\n * file). It does NOT check the authority's signature - that is what\n * `openssl ts -verify` is for; it is what tells a token for another document\n * apart before anything is kept. Throws NOTARY_REFUSED on a refusal or on\n * anything that is not a timestamp reply.\n */\nexport function readTimestampReply(bytes: Uint8Array): TimestampToken {\n\ttry {\n\t\tconst tstInfo = tstInfoOf(bytes, tokenOf(bytes));\n\t\t// version, policy, messageImprint, serialNumber, genTime, then optional\n\t\t// accuracy, ordering and nonce - the nonce is the only INTEGER among them.\n\t\tconst [, , imprint, , time, ...rest] = childrenOf(bytes, tstInfo);\n\t\tconst digest = expectTag(childrenOf(bytes, expectTag(imprint, SEQUENCE))[1], OCTET_STRING);\n\t\tconst nonce = rest.find((node) => node.tag === INTEGER);\n\t\tconst genTime = new TextDecoder().decode(contentOf(bytes, expectTag(time, GENERALIZED_TIME)));\n\t\treturn {\n\t\t\thash: hex(contentOf(bytes, digest)),\n\t\t\ttime: generalizedTime(genTime),\n\t\t\t...(nonce ? { nonce: integerHex(contentOf(bytes, nonce)) } : {})\n\t\t};\n\t} catch (e) {\n\t\tif (e instanceof SelfstoreError) throw e;\n\t\tthrow new SelfstoreError('NOTARY_REFUSED', `not a timestamp reply: ${(e as Error).message}`);\n\t}\n}\n\nasync function post(options: Rfc3161Options, body: Uint8Array): Promise<Uint8Array> {\n\tconst response = await reach(\n\t\toptions.fetch ?? globalThis.fetch,\n\t\toptions.url,\n\t\t{\n\t\t\tmethod: 'POST',\n\t\t\theaders: { 'content-type': 'application/timestamp-query' },\n\t\t\tbody: body as BodyInit\n\t\t},\n\t\t'the authority'\n\t);\n\treturn new Uint8Array(await response.arrayBuffer());\n}\n\n/**\n * A notary over an RFC 3161 time-stamping authority. The receipt is complete\n * on deposit; its evidence is the reply, base64 under `tsr`, and the\n * authority's address under `tsa`. The label is never sent: RFC 3161 has no\n * field for it, so it stays on the receipt.\n */\nexport function rfc3161Notary(options: Rfc3161Options): Notary {\n\tconst name = options.name ?? 'rfc3161';\n\treturn {\n\t\tname,\n\t\tasync deposit(hash: string, label?: string): Promise<Receipt> {\n\t\t\tconst nonce = newNonce();\n\t\t\tconst reply = await post(options, timestampRequest(hash, nonce));\n\t\t\tconst token = readTimestampReply(reply);\n\t\t\tif (token.hash !== hash) {\n\t\t\t\tthrow new SelfstoreError('NOTARY_REFUSED', 'the authority stamped another digest');\n\t\t\t}\n\t\t\tif (token.nonce !== integerHex(nonce)) {\n\t\t\t\tthrow new SelfstoreError('NOTARY_REFUSED', 'the reply does not answer this request');\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tnotary: name,\n\t\t\t\thash,\n\t\t\t\t...(label === undefined ? {} : { label }),\n\t\t\t\tdepositedAt: token.time,\n\t\t\t\tcomplete: true,\n\t\t\t\tevidence: { tsr: toBase64(reply), tsa: options.url }\n\t\t\t};\n\t\t},\n\t\tcomplete(receipt: Receipt): Promise<Receipt> {\n\t\t\treturn Promise.resolve(receipt);\n\t\t}\n\t};\n}\n\n/** The `.tsr` bytes of an RFC 3161 receipt, to offer as a download. */\nexport function timestampReplyOf(receipt: Pick<Receipt, 'evidence'>): Uint8Array | undefined {\n\tconst tsr = receipt.evidence.tsr;\n\treturn tsr === undefined ? undefined : fromBase64(tsr);\n}\n","// A notary over a public digest journal: a service that takes a SHA-256 with\n// no account, writes it as one line of a public deposits file, and folds that\n// file into a Merkle tree it anchors in Bitcoin (OpenTimestamps) and often\n// stamps under RFC 3161 too. The deposit answers at once with the journal's\n// own receipt; the anchor comes hours later, so `complete` is what fetches it.\n//\n// The protocol, relative to the journal's base URL:\n// POST /api/depots {\"sha256\", \"libelle\"?, \"type\"?} -> 201\n// {\"id\", \"jour\", \"place\", \"ligne\", \"recu\": {\"sha256\", \"depose\", ...}}\n// GET /empreintes/depots.jsonl one JSON line per deposit, in order, with \"recu\" = id\n// GET /tours.json {\"tours\": [{\"id\", \"racine\", \"depots\", \"ots\", \"bloc\",\n// \"horodatage\", \"fichiers\"}]}; a tour covers the\n// first `depots` lines of the deposits file\n// GET /empreintes/<tour>.racine.ots, /empreintes/<tour>.racine.tsr\n\nimport { toBase64 } from '../selfstore/base64';\nimport { SelfstoreError } from '../selfstore/errors';\nimport type { Notary, Receipt } from './proof';\nimport { reach } from './reach';\n\nexport interface JournalOptions {\n\t/** The journal's base URL, e.g. 'https://journal.example'. */\n\turl: string;\n\t/** Receipt `notary` field. Defaults to 'digest-journal'. */\n\tname?: string;\n\t/**\n\t * The journal's deposit type, sent as `type` with every deposit (a journal\n\t * that issues typed receipts, such as a permit display, keys them on it).\n\t * None by default: the deposit is the journal's ordinary one.\n\t */\n\ttype?: string;\n\t/** Injected for tests and relays; defaults to the global fetch. */\n\tfetch?: typeof fetch;\n}\n\ninterface Deposit {\n\tid: string;\n\tligne: string;\n\trecu: { sha256: string; depose: string };\n}\n\ninterface Tour {\n\tid: string;\n\tracine: string;\n\tdepots: number;\n\tots: string;\n\tbloc: number | null;\n\thorodatage: string | null;\n\tfichiers?: string[];\n}\n\nconst HEX_ID = /^[0-9a-f]{64}$/;\n\nfunction refused(message: string): SelfstoreError {\n\treturn new SelfstoreError('NOTARY_REFUSED', message);\n}\n\nfunction readDeposit(body: unknown): Deposit {\n\tconst d = body as Partial<Deposit> | null;\n\tif (\n\t\ttypeof d?.id !== 'string' ||\n\t\t!HEX_ID.test(d.id) ||\n\t\ttypeof d.ligne !== 'string' ||\n\t\ttypeof d.recu?.sha256 !== 'string' ||\n\t\ttypeof d.recu.depose !== 'string'\n\t) {\n\t\tthrow refused('the journal answered without a receipt');\n\t}\n\treturn d as Deposit;\n}\n\nfunction parseLine(text: string): { recu?: string; sha256?: string } {\n\ttry {\n\t\treturn JSON.parse(text) as { recu?: string; sha256?: string };\n\t} catch {\n\t\tthrow refused('the journal published an unreadable deposits file');\n\t}\n}\n\n/** 1-based rank of the deposit line whose receipt id is `id`, or 0. */\nfunction rankOf(deposits: string, id: string, hash: string): number {\n\tconst lines = deposits.split('\\n').filter(Boolean);\n\tfor (const [index, text] of lines.entries()) {\n\t\tconst line = parseLine(text);\n\t\tif (line.recu !== id) continue;\n\t\tif (line.sha256 !== hash) throw refused('the journal lists this receipt for another digest');\n\t\treturn index + 1;\n\t}\n\treturn 0;\n}\n\n/**\n * A notary over a public digest journal (the protocol is at the top of this\n * file). The label is sent as the journal's `libelle`: keep it a TYPE, unless\n * the journal's `type` (an option of the notary) says what the label is.\n *\n * On deposit the receipt is incomplete; its evidence holds the journal's\n * address, the receipt `id`, the public `line` and the journal's own `receipt`\n * as JSON - the file its verifier reads. `complete` finds the first tour that\n * covers the line and, once that tour is anchored in Bitcoin, completes the\n * receipt with `tour`, `root`, `block`, the `.ots` proof and, when the journal\n * stamped that root, the `.tsr` token (both base64). Checking the Merkle path\n * from the line to the root is the journal's verifier's job.\n */\nexport function digestJournalNotary(options: JournalOptions): Notary {\n\tconst name = options.name ?? 'digest-journal';\n\tconst base = options.url.replace(/\\/+$/, '');\n\tconst typed = options.type === undefined ? {} : { type: options.type };\n\tconst send = options.fetch ?? globalThis.fetch;\n\tconst get = (path: string): Promise<Response> =>\n\t\treach(send, `${base}${path}`, undefined, 'the journal');\n\tconst bytesOf = async (path: string): Promise<string> =>\n\t\ttoBase64(new Uint8Array(await (await get(path)).arrayBuffer()));\n\n\treturn {\n\t\tname,\n\t\tasync deposit(hash: string, label?: string): Promise<Receipt> {\n\t\t\tconst response = await reach(\n\t\t\t\tsend,\n\t\t\t\t`${base}/api/depots`,\n\t\t\t\t{\n\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\theaders: { 'content-type': 'application/json' },\n\t\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\t\tsha256: hash,\n\t\t\t\t\t\t...(label === undefined ? {} : { libelle: label }),\n\t\t\t\t\t\t...typed\n\t\t\t\t\t})\n\t\t\t\t},\n\t\t\t\t'the journal'\n\t\t\t);\n\t\t\tconst deposit = readDeposit(await response.json().catch(() => null));\n\t\t\treturn {\n\t\t\t\tnotary: name,\n\t\t\t\thash: deposit.recu.sha256,\n\t\t\t\t...(label === undefined ? {} : { label }),\n\t\t\t\tdepositedAt: deposit.recu.depose,\n\t\t\t\tcomplete: false,\n\t\t\t\tevidence: {\n\t\t\t\t\tjournal: base,\n\t\t\t\t\tid: deposit.id,\n\t\t\t\t\tline: deposit.ligne,\n\t\t\t\t\treceipt: JSON.stringify(deposit.recu)\n\t\t\t\t}\n\t\t\t};\n\t\t},\n\t\tasync complete(receipt: Receipt): Promise<Receipt> {\n\t\t\tconst id = receipt.evidence.id;\n\t\t\tif (id === undefined) throw refused('the receipt carries no journal id');\n\t\t\tconst rank = rankOf(await (await get('/empreintes/depots.jsonl')).text(), id, receipt.hash);\n\t\t\tif (rank === 0) return receipt;\n\t\t\tconst { tours } = (await (await get('/tours.json')).json()) as { tours: Tour[] };\n\t\t\tconst tour = tours.find((t) => t.depots >= rank);\n\t\t\tif (tour?.ots !== 'bitcoin') return receipt;\n\t\t\tconst stamped = tour.horodatage !== null && tour.fichiers?.includes(`${tour.id}.racine.tsr`);\n\t\t\treturn {\n\t\t\t\t...receipt,\n\t\t\t\tcomplete: true,\n\t\t\t\tevidence: {\n\t\t\t\t\t...receipt.evidence,\n\t\t\t\t\ttour: tour.id,\n\t\t\t\t\troot: tour.racine,\n\t\t\t\t\t...(tour.bloc === null ? {} : { block: String(tour.bloc) }),\n\t\t\t\t\tots: await bytesOf(`/empreintes/${tour.id}.racine.ots`),\n\t\t\t\t\t...(stamped ? { tsr: await bytesOf(`/empreintes/${tour.id}.racine.tsr`) } : {})\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t};\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "selfstore",
|
|
3
|
-
"version": "1.8.
|
|
3
|
+
"version": "1.8.32",
|
|
4
4
|
"description": "Local-first storage for browser apps: an IndexedDB working copy, portable encrypted ZIP backups (AES-256-GCM over Argon2id), durable homes (disk, Google Drive, WebDAV) and a serverless multi-device merge.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|