selfstore 1.8.32 → 1.8.34
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/dist/advanced.d.ts +9 -9
- package/dist/advanced.js +5 -5
- package/dist/backups.d.ts +4 -4
- package/dist/backups.js +3 -3
- package/dist/{cache-BEv-Har2.d.ts → cache-D8Z4u5Jz.d.ts} +0 -2
- package/dist/{chunk-GSZSZGSD.js → chunk-A2RRJLIF.js} +3 -3
- package/dist/{chunk-GSZSZGSD.js.map → chunk-A2RRJLIF.js.map} +1 -1
- package/dist/chunk-DJ6YPMBK.js +10 -0
- package/dist/chunk-DJ6YPMBK.js.map +1 -0
- package/dist/{chunk-7U5XMKVP.js → chunk-E4S77JSN.js} +34 -6
- package/dist/chunk-E4S77JSN.js.map +1 -0
- package/dist/{chunk-TB3CKC6Z.js → chunk-HQSK7HK3.js} +38 -16
- package/dist/chunk-HQSK7HK3.js.map +1 -0
- package/dist/{chunk-25U6AKIX.js → chunk-IUVOVVEA.js} +26 -15
- package/dist/chunk-IUVOVVEA.js.map +1 -0
- package/dist/{chunk-5DAPYC2K.js → chunk-MDEEAQSU.js} +3 -3
- package/dist/{chunk-5DAPYC2K.js.map → chunk-MDEEAQSU.js.map} +1 -1
- package/dist/{chunk-JDDWWQEB.js → chunk-TNYL6FNW.js} +6 -6
- package/dist/{chunk-JDDWWQEB.js.map → chunk-TNYL6FNW.js.map} +1 -1
- package/dist/{chunk-HRYIQSTH.js → chunk-VRWAV3GI.js} +5 -5
- package/dist/{chunk-HRYIQSTH.js.map → chunk-VRWAV3GI.js.map} +1 -1
- package/dist/{chunk-Q3NO477P.js → chunk-XAONTUEC.js} +3 -3
- package/dist/{chunk-Q3NO477P.js.map → chunk-XAONTUEC.js.map} +1 -1
- package/dist/{connect-CDazV36v.d.ts → connect-B9f58dFZ.d.ts} +4 -4
- package/dist/{drive-CwlKlowN.d.ts → drive-D5YLXmp_.d.ts} +2 -2
- package/dist/flows.d.ts +4 -4
- package/dist/flows.js +4 -4
- package/dist/groups.d.ts +2 -2
- package/dist/index.d.ts +9 -9
- package/dist/index.js +45 -43
- package/dist/index.js.map +1 -1
- package/dist/{local-DytMg5GC.d.ts → local-CmS0xFkK.d.ts} +2 -2
- package/dist/{local-S3WUZSDX.js → local-D72LJOKX.js} +4 -4
- package/dist/{local-S3WUZSDX.js.map → local-D72LJOKX.js.map} +1 -1
- package/dist/{manager-CnlIs-hY.d.ts → manager-DCV_7B6M.d.ts} +2 -2
- package/dist/{manager-drive-T3RXUWAY.js → manager-drive-TEYNJVUU.js} +5 -5
- package/dist/{manager-drive-T3RXUWAY.js.map → manager-drive-TEYNJVUU.js.map} +1 -1
- package/dist/proof.d.ts +10 -6
- package/dist/proof.js +22 -3
- package/dist/proof.js.map +1 -1
- package/dist/{s3-ORDHS7G3.js → s3-KZPMSI4J.js} +3 -3
- package/dist/s3-KZPMSI4J.js.map +1 -0
- package/dist/{s3-Bexn9kzT.d.ts → s3-mHLrEywJ.d.ts} +2 -2
- package/dist/{simple-cLzoTGhN.d.ts → simple-Bnh2j78j.d.ts} +6 -6
- package/dist/{store-DSPbCCtM.d.ts → store-DSvZwwr1.d.ts} +11 -3
- package/dist/sync.js +1 -1
- package/dist/{webdav-PXKELPA4.js → webdav-5YKO47EE.js} +3 -3
- package/dist/{webdav-PXKELPA4.js.map → webdav-5YKO47EE.js.map} +1 -1
- package/dist/widgets.d.ts +5 -5
- package/dist/widgets.js +5 -5
- package/package.json +1 -1
- package/dist/chunk-25U6AKIX.js.map +0 -1
- package/dist/chunk-7U5XMKVP.js.map +0 -1
- package/dist/chunk-SJ3PKQPR.js +0 -10
- package/dist/chunk-SJ3PKQPR.js.map +0 -1
- package/dist/chunk-TB3CKC6Z.js.map +0 -1
- package/dist/s3-ORDHS7G3.js.map +0 -1
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\"?, \"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"]}
|
|
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\"?, \"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\", \"instant\"?, \"racine\", \"depots\", \"ots\",\n// \"bloc\", \"horodatage\", \"fichiers\"}]}; a tour covers the\n// first `depots` lines of the deposits file as it\n// stood at its `instant`\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\tinstant?: 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/**\n * Whether a tour can cover a line deposited at `depositedAt`: a tour folded the\n * file before the deposit cannot, whatever its size. A journal that publishes\n * no `instant` leaves the question open.\n */\nfunction mayCover(tour: Tour, depositedAt: string): boolean {\n\tif (tour.instant === undefined) return true;\n\tconst folded = Date.parse(tour.instant);\n\tconst deposited = Date.parse(depositedAt);\n\treturn Number.isNaN(folded) || Number.isNaN(deposited) || folded > deposited;\n}\n\n/**\n * Whether reading the deposits file can complete the receipt: only once a tour\n * folded after the deposit is anchored in Bitcoin. Until then the first tour\n * covering the line is either absent or not anchored, and the receipt stays\n * as it is without the file (which grows with every deposit of every user).\n */\nfunction worthReading(tours: readonly Tour[], depositedAt: string): boolean {\n\treturn tours.some((t) => t.depots > 0 && t.ots === 'bitcoin' && mayCover(t, depositedAt));\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 *\n * `complete` reads the tour list first and the deposits file only when a tour\n * folded after the deposit is anchored: the file lists every deposit of every\n * user and grows without end, the tour list stays small.\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\t// The deposits file, read once per state of the tour list: a line covered by\n\t// a known tour was already in the copy read after that tour was listed, so a\n\t// round that completes many receipts reads the file once, not once each.\n\tlet deposits: { key: string; text: string } | undefined;\n\tconst depositsFile = async (tours: readonly Tour[]): Promise<string> => {\n\t\tconst last = tours.at(-1);\n\t\tconst key = last === undefined ? '' : `${last.id}:${last.depots}`;\n\t\tif (deposits?.key !== key) {\n\t\t\tdeposits = { key, text: await (await get('/empreintes/depots.jsonl')).text() };\n\t\t}\n\t\treturn deposits.text;\n\t};\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 { tours } = (await (await get('/tours.json')).json()) as { tours: Tour[] };\n\t\t\tif (!worthReading(tours, receipt.depositedAt)) return receipt;\n\t\t\tconst rank = rankOf(await depositsFile(tours), id, receipt.hash);\n\t\t\tif (rank === 0) return receipt;\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,12 +1,12 @@
|
|
|
1
1
|
export { connect, fromSession } from './chunk-IDW3WQKF.js';
|
|
2
2
|
import './chunk-FJGWTBAL.js';
|
|
3
3
|
import './chunk-LF3CC2P3.js';
|
|
4
|
-
import './chunk-
|
|
4
|
+
import './chunk-E4S77JSN.js';
|
|
5
5
|
import './chunk-QBCU7OOP.js';
|
|
6
6
|
import './chunk-F4ZZEJ5H.js';
|
|
7
7
|
import './chunk-H2T4S3KM.js';
|
|
8
8
|
import './chunk-QSLHEE2L.js';
|
|
9
9
|
import './chunk-WXI2NAPA.js';
|
|
10
10
|
import './chunk-CSYEIXNY.js';
|
|
11
|
-
//# sourceMappingURL=s3-
|
|
12
|
-
//# sourceMappingURL=s3-
|
|
11
|
+
//# sourceMappingURL=s3-KZPMSI4J.js.map
|
|
12
|
+
//# sourceMappingURL=s3-KZPMSI4J.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"s3-KZPMSI4J.js"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { B as BackupTarget, P as PeerSource } from './store-
|
|
2
|
-
import { K as KV } from './cache-
|
|
1
|
+
import { B as BackupTarget, P as PeerSource } from './store-DSvZwwr1.js';
|
|
2
|
+
import { K as KV } from './cache-D8Z4u5Jz.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* WebDAV backup target: the store re-writes one .selfstore file on a WebDAV
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { a as Snapshot, b as PasswordPolicy, c as SnapshotFile, B as BackupTarget, d as StatusDescriptor, S as StoreError, e as LocalStoreState, L as LocalStore } from './store-
|
|
2
|
-
import { L as LocalCache, K as KV } from './cache-
|
|
1
|
+
import { a as Snapshot, b as PasswordPolicy, c as SnapshotFile, B as BackupTarget, d as StatusDescriptor, S as StoreError, e as LocalStoreState, L as LocalStore } from './store-DSvZwwr1.js';
|
|
2
|
+
import { L as LocalCache, K as KV } from './cache-D8Z4u5Jz.js';
|
|
3
3
|
import { SyncConfig } from './sync.js';
|
|
4
|
-
import { R as ResumeOffer, C as ConnectTargets } from './connect-
|
|
5
|
-
import { f as BackupsManager } from './manager-
|
|
6
|
-
import { a as DriveAuth } from './drive-
|
|
7
|
-
import { W as WebdavConfig, S as S3Config } from './s3-
|
|
4
|
+
import { R as ResumeOffer, C as ConnectTargets } from './connect-B9f58dFZ.js';
|
|
5
|
+
import { f as BackupsManager } from './manager-DCV_7B6M.js';
|
|
6
|
+
import { a as DriveAuth } from './drive-D5YLXmp_.js';
|
|
7
|
+
import { W as WebdavConfig, S as S3Config } from './s3-mHLrEywJ.js';
|
|
8
8
|
|
|
9
9
|
/** What a file body may be handed in as. */
|
|
10
10
|
type FileBytes = Uint8Array | ArrayBuffer | Blob;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { G as GroupIdentity, S as SignedManifest, L as LocalCache } from './cache-
|
|
1
|
+
import { G as GroupIdentity, S as SignedManifest, L as LocalCache } from './cache-D8Z4u5Jz.js';
|
|
2
2
|
import { CollectionChanges, Conflict, SyncConfig } from './sync.js';
|
|
3
3
|
|
|
4
4
|
/** A binary attachment (image, PDF, any bytes). */
|
|
@@ -87,8 +87,8 @@ interface RecipientStanza {
|
|
|
87
87
|
* (sig.bin) covers the exact meta.json and data.enc bytes.
|
|
88
88
|
*/
|
|
89
89
|
interface Header {
|
|
90
|
-
/** Format generation:
|
|
91
|
-
* Absent means
|
|
90
|
+
/** Format generation: 1 = plain ZIP, 2 = group, 3 = password envelope.
|
|
91
|
+
* Absent means 1. */
|
|
92
92
|
format?: number;
|
|
93
93
|
app: string;
|
|
94
94
|
/** Writing app's release version, informational. */
|
|
@@ -107,6 +107,11 @@ interface Header {
|
|
|
107
107
|
author?: string;
|
|
108
108
|
/** Group mode: one data-key envelope per recipient. */
|
|
109
109
|
recipients?: RecipientStanza[];
|
|
110
|
+
/** Group mode: the manifest's group id this copy was published for, under
|
|
111
|
+
* the author's signature. A reader that knows its group refuses another
|
|
112
|
+
* group's copy, however well signed. Absent on copies written before it
|
|
113
|
+
* existed. */
|
|
114
|
+
group?: string;
|
|
110
115
|
/** Password envelope only: the data key wrapped once per password.
|
|
111
116
|
* Present iff format === 4. */
|
|
112
117
|
keys?: KeySlot[];
|
|
@@ -127,6 +132,9 @@ interface EncodeOptions {
|
|
|
127
132
|
pub: string;
|
|
128
133
|
priv: string;
|
|
129
134
|
};
|
|
135
|
+
/** The manifest's group id, written into the signed header so the
|
|
136
|
+
* copy cannot be served to another group. */
|
|
137
|
+
id?: string;
|
|
130
138
|
};
|
|
131
139
|
/** README text shipped inside an encrypted backup, for whoever opens the
|
|
132
140
|
* ZIP by hand. Defaults to a neutral note; apps should brand it. */
|
package/dist/sync.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { changes, createMeta, createNode, detectConflicts, merge, stamp } from './chunk-
|
|
1
|
+
export { changes, createMeta, createNode, detectConflicts, merge, stamp } from './chunk-A2RRJLIF.js';
|
|
2
2
|
import './chunk-FJGWTBAL.js';
|
|
3
3
|
import './chunk-CSYEIXNY.js';
|
|
4
4
|
//# sourceMappingURL=sync.js.map
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
export { connect, fromSession, peer } from './chunk-GHSHIDF3.js';
|
|
2
2
|
import './chunk-LF3CC2P3.js';
|
|
3
|
-
import './chunk-
|
|
3
|
+
import './chunk-E4S77JSN.js';
|
|
4
4
|
import './chunk-QBCU7OOP.js';
|
|
5
5
|
import './chunk-F4ZZEJ5H.js';
|
|
6
6
|
import './chunk-H2T4S3KM.js';
|
|
7
7
|
import './chunk-WXI2NAPA.js';
|
|
8
8
|
import './chunk-CSYEIXNY.js';
|
|
9
|
-
//# sourceMappingURL=webdav-
|
|
10
|
-
//# sourceMappingURL=webdav-
|
|
9
|
+
//# sourceMappingURL=webdav-5YKO47EE.js.map
|
|
10
|
+
//# sourceMappingURL=webdav-5YKO47EE.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"webdav-
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"webdav-5YKO47EE.js"}
|
package/dist/widgets.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { S as StoreLike } from './connect-
|
|
1
|
+
import { S as StoreLike } from './connect-B9f58dFZ.js';
|
|
2
2
|
import { FlowHost, ConnectTargets, ConnectFlowOptions, ConnectKind, ConnectFlow } from './flows.js';
|
|
3
3
|
import { ShareEngine, ShareLevel, ShareFlow, JoinEngine, JoinFlow, ReplicaFlow } from './flows.js';
|
|
4
4
|
import { BackupsManager } from './backups.js';
|
|
5
|
-
import './store-
|
|
6
|
-
import './cache-
|
|
5
|
+
import './store-DSvZwwr1.js';
|
|
6
|
+
import './cache-D8Z4u5Jz.js';
|
|
7
7
|
import './sync.js';
|
|
8
|
-
import './drive-
|
|
9
|
-
import './s3-
|
|
8
|
+
import './drive-D5YLXmp_.js';
|
|
9
|
+
import './s3-mHLrEywJ.js';
|
|
10
10
|
import './machine-Dhbx3Eut.js';
|
|
11
11
|
|
|
12
12
|
/** Flat key -> string map; widgets merge a partial override over EN defaults. */
|
package/dist/widgets.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { saveToDisk, datedName } from './chunk-
|
|
2
|
-
import { connectFlow, shareFlow, joinFlow } from './chunk-
|
|
3
|
-
import './chunk-
|
|
1
|
+
import { saveToDisk, datedName } from './chunk-XAONTUEC.js';
|
|
2
|
+
import { connectFlow, shareFlow, joinFlow } from './chunk-VRWAV3GI.js';
|
|
3
|
+
import './chunk-TNYL6FNW.js';
|
|
4
4
|
import { isOpenSupported } from './chunk-HVHQLPP6.js';
|
|
5
5
|
import './chunk-2BNTCXQN.js';
|
|
6
|
-
import './chunk-
|
|
6
|
+
import './chunk-IUVOVVEA.js';
|
|
7
7
|
import './chunk-LF3CC2P3.js';
|
|
8
|
-
import './chunk-
|
|
8
|
+
import './chunk-E4S77JSN.js';
|
|
9
9
|
import './chunk-F4ZZEJ5H.js';
|
|
10
10
|
import './chunk-H2T4S3KM.js';
|
|
11
11
|
import './chunk-WXI2NAPA.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "selfstore",
|
|
3
|
-
"version": "1.8.
|
|
3
|
+
"version": "1.8.34",
|
|
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",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/persistence/targets/drive.ts"],"names":["token"],"mappings":"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","file":"chunk-25U6AKIX.js","sourcesContent":["/**\n * Google Drive backup target. Does the Drive REST file operations (find-or-create,\n * upload, download) for a single backup file. It only ships bytes; the store\n * decides whether they are encrypted. How an access token is obtained (a browser\n * OAuth flow, a backend broker, ...) is injected via DriveAuth, so this target\n * stays free of any specific auth strategy or backend.\n *\n * Beyond the standard connect/fromSession lifecycle, this module exposes\n * shared-file primitives (preview, adopt, findOrCreateOwnFile) for apps whose\n * users point several devices - or several people - at one Drive-hosted backup\n * file: preview it read-only, then adopt it as this device's backup.\n */\n\nimport type { BackupTarget } from '../target';\nimport type { KV } from '../cache';\nimport { boundedSignal, lifeLine } from './abort';\nimport { AuthExpiredError, SelfstoreError, isAuthExpired } from '../../selfstore';\n\n/** KV key holding the connected backup's Drive file id. Public because app-level\n * flows that operate on the same file (e.g. sharing it) need to read it. */\nexport const FILE_ID_KEY = 'driveFileId';\nconst DRIVE_UPLOAD = 'https://www.googleapis.com/upload/drive/v3/files';\nconst DRIVE_FILES = 'https://www.googleapis.com/drive/v3/files';\nconst DRIVE_ABOUT = 'https://www.googleapis.com/drive/v3/about';\n/** Just enough of a permission to find the link grants and delete them. */\nconst PERMISSION_FIELDS = encodeURIComponent('permissions(id,type)');\n\n/** A hung request must not spin forever behind a dead connection - the very\n * \"long moment trying to connect\" a stuck backup shows. A deadline turns the\n * hang into an ordinary error (transient: the store retries), never a gate.\n * Data transfers get more room than metadata pokes. AbortSignal.timeout is\n * minted per fetch (a fired signal cannot be reused across driveFetch's retry). */\nconst DATA_DEADLINE_MS = 30_000;\nconst META_DEADLINE_MS = 15_000;\n\n/** How the target gets access. Injected, so the auth strategy lives in the app.\n * Error protocol: a genuine loss of access (the session is gone, re-consent\n * needed) must throw AuthExpiredError - or any error with code 'AUTH_EXPIRED' -\n * while a transient offline/cold-start failure throws a plain error, so the\n * store retries it instead of raising the reconnect gate. */\nexport interface DriveAuth {\n\t/** A fresh access token, or throw if access must be re-established. Pass\n\t * `{ forceRefresh: true }` to bypass any cached token and mint a new one:\n\t * the target calls this after a 401 to tell a merely STALE token (a refresh\n\t * fixes it, no gate) from a genuinely lost session (the refresh 401s too).\n\t * An implementation that cannot force a refresh may ignore the flag; the\n\t * target then retries with the same token, no worse than before.\n\t * `signal` fires when the target's in-flight work is cut (the user is\n\t * detaching): an implementation that runs its own retry loop should abort\n\t * it then (pass the signal to its fetches, stop retrying); ignoring the\n\t * signal only means the loop runs to its own deadline first. */\n\ttoken(opts?: { forceRefresh?: boolean; signal?: AbortSignal }): Promise<string>;\n\t/** Re-establish access with a user gesture; resolves to whether it worked. */\n\treconnect(): Promise<boolean>;\n\t/** Forget the connection, locally and server-side. */\n\tforget(): Promise<void>;\n}\n\n/** Run a Drive request; if Google answers 401 the access token may just be\n * STALE (rejected before its nominal expiry - rotation, an early revoke), so\n * force a fresh token and try once more. Only a SECOND 401 means the session\n * is genuinely gone. This is what stops a stale-token blip - common when a\n * flow makes many Drive calls, e.g. group-mode republishing every converge -\n * from raising the blocking reconnect gate over a still-valid connection. */\nasync function driveFetch(\n\tauth: DriveAuth,\n\trun: (token: string) => Promise<Response>,\n\tsignal?: AbortSignal\n): Promise<Response> {\n\tconst r = await run(await auth.token({ signal }));\n\tif (r.status !== 401) return r;\n\treturn run(await auth.token({ forceRefresh: true, signal }));\n}\n\nexport interface DriveOptions {\n\tauth: DriveAuth;\n\tkv: KV;\n\t/** Name of the backup file created in the user's Drive. */\n\tfileName: string;\n}\n\nasync function findExistingFile(token: string, fileNames: string[]): Promise<string | null> {\n\tfor (const name of fileNames) {\n\t\t// 'me' in owners: a shared backup carries the same name but lives on someone\n\t\t// else's Drive - only an OWNED file may be (re)connected as the personal\n\t\t// backup, or a fresh connect could silently re-adopt theirs.\n\t\t// Escape the name for Drive's query grammar (backslash then single-quote):\n\t\t// a name carrying a quote must not break out of the `name='...'` clause and\n\t\t// alter the filter (encodeURIComponent handles transport, not query syntax).\n\t\tconst safe = name.replace(/\\\\/g, '\\\\\\\\').replace(/'/g, \"\\\\'\");\n\t\tconst q = encodeURIComponent(`name='${safe}' and trashed=false and 'me' in owners`);\n\t\tconst r = await fetch(`${DRIVE_FILES}?q=${q}&fields=files(id)&pageSize=1`, {\n\t\t\theaders: { Authorization: `Bearer ${token}` },\n\t\t\tsignal: AbortSignal.timeout(META_DEADLINE_MS)\n\t\t});\n\t\tif (!r.ok) continue;\n\t\tconst data: { files?: { id: string }[] } = await r.json();\n\t\tconst id = data.files?.[0]?.id;\n\t\tif (id) return id;\n\t}\n\treturn null;\n}\n\n/** Classify a non-OK Drive write we could not otherwise handle (the 401 case is\n * the caller's). A 404 - the bound file is gone (deleted, trashed, id no longer\n * valid) - or a 403 that is not a rate limit (permission withdrawn, storage\n * full) is PERMANENT: retrying writes the same doomed request forever (the\n * silent \"momentarily unreachable\" trap), so the store must raise its gate and\n * let the user reconnect to a fresh file or free space. A 403 rate limit and\n * everything else (5xx, network) stay transient. The body carries Drive's\n * `reason` (e.g. userRateLimitExceeded vs storageQuotaExceeded); absent, a bare\n * 403 is treated as permanent (the safer default - a real rate limit names\n * itself). */\nfunction isPermanentDriveWrite(status: number, body: string): boolean {\n\tif (status === 404) return true;\n\tif (status === 403) return !/ratelimit|dailylimit/i.test(body);\n\treturn false;\n}\n\nasync function createFile(token: string, fileName: string): Promise<string> {\n\tconst boundary = 'SLFS_BOUNDARY';\n\tconst meta = JSON.stringify({ name: fileName, mimeType: 'application/octet-stream' });\n\tconst body = [\n\t\t`--${boundary}\\r\\nContent-Type: application/json; charset=UTF-8\\r\\n\\r\\n`,\n\t\tmeta,\n\t\t`\\r\\n--${boundary}\\r\\nContent-Type: application/octet-stream\\r\\n\\r\\n\\r\\n--${boundary}--`\n\t].join('');\n\tconst r = await fetch(`${DRIVE_UPLOAD}?uploadType=multipart`, {\n\t\tmethod: 'POST',\n\t\theaders: {\n\t\t\tAuthorization: `Bearer ${token}`,\n\t\t\t'Content-Type': `multipart/related; boundary=${boundary}`\n\t\t},\n\t\tbody,\n\t\tsignal: AbortSignal.timeout(META_DEADLINE_MS)\n\t});\n\tif (!r.ok) throw new SelfstoreError('TARGET_WRITE_FAILED', `Drive create failed: ${r.status}`);\n\tconst data: { id: string } = await r.json();\n\treturn data.id;\n}\n\nfunction makeTarget(opts: DriveOptions, fixedId?: string): BackupTarget {\n\tconst { auth, kv } = opts;\n\t// A target is BOUND to one file for its whole life: the id is the fixed one,\n\t// or the remembered id CAPTURED on first use - never re-read per operation.\n\t// The old lazy per-call read let a backup SWITCH re-point the remembered id\n\t// while the OUTGOING target was still attached: its final courtesy flush\n\t// then wrote the old store (data and sync bookkeeping) into the file being\n\t// opened, silently merging two \"isolated\" backups.\n\tlet captured: string | undefined = fixedId;\n\tconst fileIdOf = async (): Promise<string | undefined> =>\n\t\t(captured ??= await kv.get<string>(FILE_ID_KEY));\n\t// The instance's LIFE line: abortInFlight() (a user detach) cuts every\n\t// suspended request now instead of at its deadline. Requests mint their\n\t// signal per call, so work started AFTER a cut lives normally.\n\tconst life = lifeLine();\n\tconst bounded = (ms: number): AbortSignal => boundedSignal(ms, life.current());\n\treturn {\n\t\tkind: 'drive',\n\t\tlabel: 'Google Drive',\n\t\tabortInFlight: life.cut,\n\t\tasync save(blob: Blob): Promise<string | null> {\n\t\t\tconst fileId = await fileIdOf();\n\t\t\tif (!fileId) throw new SelfstoreError('NOT_CONNECTED', 'Drive not connected.');\n\t\t\t// fields=version: the response reports the file's new version, so the\n\t\t\t// store records exactly OUR write (no marker race with other replicas).\n\t\t\tconst r = await driveFetch(\n\t\t\t\tauth,\n\t\t\t\t(token) =>\n\t\t\t\t\tfetch(`${DRIVE_UPLOAD}/${fileId}?uploadType=media&fields=version`, {\n\t\t\t\t\t\tmethod: 'PATCH',\n\t\t\t\t\t\theaders: {\n\t\t\t\t\t\t\tAuthorization: `Bearer ${token}`,\n\t\t\t\t\t\t\t'Content-Type': 'application/octet-stream'\n\t\t\t\t\t\t},\n\t\t\t\t\t\tbody: blob,\n\t\t\t\t\t\tsignal: bounded(DATA_DEADLINE_MS)\n\t\t\t\t\t}),\n\t\t\t\tlife.current()\n\t\t\t);\n\t\t\tif (!r.ok) {\n\t\t\t\t// A 401 that survives a forced token refresh (driveFetch) is a genuine\n\t\t\t\t// loss of access, not a stale-token blip. A 404 (the bound file is\n\t\t\t\t// gone) or a non-rate-limit 403 (permission withdrawn, storage full) is\n\t\t\t\t// PERMANENT: gate so the user reconnects to a fresh file, never loop it\n\t\t\t\t// as transient. Everything else (5xx, network) stays transient.\n\t\t\t\tif (r.status === 401) throw new AuthExpiredError('Drive rejected the token (401).');\n\t\t\t\tconst body = await r.text().catch(() => '');\n\t\t\t\tif (isPermanentDriveWrite(r.status, body)) {\n\t\t\t\t\tthrow new SelfstoreError(\n\t\t\t\t\t\t'TARGET_GONE',\n\t\t\t\t\t\t`Drive backup unwritable (${r.status}): the file is gone or access was withdrawn.`\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tthrow new SelfstoreError('TARGET_WRITE_FAILED', `Drive upload failed: ${r.status}`);\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst data: { version?: string | number } = await r.json();\n\t\t\t\treturn data.version != null ? String(data.version) : null;\n\t\t\t} catch {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t},\n\t\tasync load(): Promise<Blob | null> {\n\t\t\tconst fileId = await fileIdOf();\n\t\t\tif (!fileId) return null;\n\t\t\tconst r = await driveFetch(\n\t\t\t\tauth,\n\t\t\t\t(token) =>\n\t\t\t\t\tfetch(`${DRIVE_FILES}/${fileId}?alt=media`, {\n\t\t\t\t\t\theaders: { Authorization: `Bearer ${token}` },\n\t\t\t\t\t\tsignal: bounded(DATA_DEADLINE_MS)\n\t\t\t\t\t}),\n\t\t\t\tlife.current()\n\t\t\t);\n\t\t\t// A failed read must never pass for an empty file: null tells the store\n\t\t\t// \"nothing there\", and a fresh connect would then overwrite the backup\n\t\t\t// this download merely failed to fetch. Only a 404 - the file is\n\t\t\t// genuinely gone - reads as empty; a 401 that survived driveFetch's\n\t\t\t// forced refresh is a real loss of access; anything else is a typed\n\t\t\t// transient failure (the sync legs retry it, connect flows surface it).\n\t\t\tif (r.status === 404) return null;\n\t\t\tif (r.status === 401) throw new AuthExpiredError('Drive rejected the token (401).');\n\t\t\tif (!r.ok) {\n\t\t\t\tthrow new SelfstoreError('TARGET_UNAVAILABLE', `Drive download failed: ${r.status}`);\n\t\t\t}\n\t\t\treturn r.blob();\n\t\t},\n\t\tasync stat(): Promise<string | null> {\n\t\t\ttry {\n\t\t\t\tconst fileId = await fileIdOf();\n\t\t\t\tif (!fileId) return null;\n\t\t\t\tconst r = await driveFetch(\n\t\t\t\t\tauth,\n\t\t\t\t\t(token) =>\n\t\t\t\t\t\tfetch(`${DRIVE_FILES}/${fileId}?fields=version`, {\n\t\t\t\t\t\t\theaders: { Authorization: `Bearer ${token}` },\n\t\t\t\t\t\t\tsignal: bounded(META_DEADLINE_MS)\n\t\t\t\t\t\t}),\n\t\t\t\t\tlife.current()\n\t\t\t\t);\n\t\t\t\tif (!r.ok) return null;\n\t\t\t\tconst data: { version?: string | number } = await r.json();\n\t\t\t\treturn data.version != null ? String(data.version) : null;\n\t\t\t} catch {\n\t\t\t\treturn null; // offline or token lapse: \"cannot tell\", never throws\n\t\t\t}\n\t\t},\n\t\tasync isReady(): Promise<boolean> {\n\t\t\ttry {\n\t\t\t\tawait auth.token({ signal: life.current() });\n\t\t\t\treturn true;\n\t\t\t} catch (e) {\n\t\t\t\t// A transient token failure means \"not writable right now\", not a lost\n\t\t\t\t// session: report false so the store retries. Only a genuine auth loss\n\t\t\t\t// propagates, so the boot path can raise the reconnect gate.\n\t\t\t\tif (isAuthExpired(e)) throw e;\n\t\t\t\treturn false;\n\t\t\t}\n\t\t},\n\t\tasync reconnect(): Promise<boolean> {\n\t\t\treturn auth.reconnect();\n\t\t},\n\t\tasync disconnect(): Promise<void> {\n\t\t\tawait auth.forget();\n\t\t\t// Delete the remembered id only while it still points at this target's\n\t\t\t// file: after a backup switch the key already belongs to the new\n\t\t\t// target, and a late disconnect of the old one must not orphan it.\n\t\t\tconst current = await kv.get<string>(FILE_ID_KEY);\n\t\t\tconst own = await fileIdOf();\n\t\t\tif (!current || !own || current === own) await kv.del(FILE_ID_KEY);\n\t\t}\n\t};\n}\n\n/** First-time connect: authorize (a user gesture), then find-or-create the file.\n * Returns the target, or null if the user cancelled the consent. */\nexport async function connect(opts: DriveOptions): Promise<BackupTarget | null> {\n\tif (!(await opts.auth.reconnect())) return null;\n\tconst token = await opts.auth.token();\n\tlet fileId = await opts.kv.get<string>(FILE_ID_KEY);\n\tif (!fileId) {\n\t\tfileId =\n\t\t\t(await findExistingFile(token, [opts.fileName])) ?? (await createFile(token, opts.fileName));\n\t\tawait opts.kv.set(FILE_ID_KEY, fileId);\n\t}\n\treturn makeTarget(opts);\n}\n\n/** Rebuild the target from a past session's saved connection (no UI), or null. */\nexport async function fromSession(opts: DriveOptions): Promise<BackupTarget | null> {\n\treturn (await opts.kv.get<string>(FILE_ID_KEY)) ? makeTarget(opts) : null;\n}\n\n/** A read-only-intent preview of one specific (typically shared) file, before\n * adopting it. Writes NOTHING to the KV: until the user confirms, the device's\n * own backup wiring must stay untouched. */\nexport function preview(opts: DriveOptions, fileId: string): BackupTarget {\n\treturn makeTarget(opts, fileId);\n}\n\n/** Adopt a specific (typically shared) file as this device's backup. Persists\n * the file id, so next sessions restore it like any Drive backup. */\nexport async function adopt(opts: DriveOptions, fileId: string): Promise<BackupTarget> {\n\tawait opts.kv.set(FILE_ID_KEY, fileId);\n\treturn makeTarget(opts);\n}\n\n/** Find (or create) the user's own backup file, ignoring the currently adopted\n * id (which may point at someone else's shared file). Reuses the live session\n * when possible and only falls back to the consent popup. Adopts NOTHING: the\n * caller decides whether to load the file or start it blank. Null when the\n * consent is refused. */\nexport async function findOrCreateOwnFile(\n\topts: DriveOptions\n): Promise<{ fileId: string; created: boolean } | null> {\n\tlet token: string;\n\ttry {\n\t\ttoken = await opts.auth.token();\n\t} catch {\n\t\tif (!(await opts.auth.reconnect())) return null;\n\t\ttoken = await opts.auth.token();\n\t}\n\tconst existing = await findExistingFile(token, [opts.fileName]);\n\tif (existing) return { fileId: existing, created: false };\n\treturn { fileId: await createFile(token, opts.fileName), created: true };\n}\n\n/** Who a destination is held by, as far as it will say. */\nexport interface DriveAccount {\n\t/** The account's address, when Drive reports one. */\n\temail: string | null;\n\t/** Its display name, when Drive reports one. */\n\tname: string | null;\n}\n\n/** Which Google account the current session belongs to.\n *\n * A destination named \"Google Drive\" is not an address: several accounts look\n * alike, and a user who connected the wrong one has no way to tell from a\n * brand name alone. This is the one call that lets a surface say WHICH.\n *\n * Cheap (one metadata poke, allowed by the `drive.file` scope) but not free:\n * the answer only changes when the session does, so a caller should ask on\n * connect and on reconnect - not on every render. A destination that will not\n * say answers nulls rather than throwing; a genuinely lost session throws\n * AuthExpiredError like every other call here. */\nexport async function account(opts: { auth: DriveAuth }): Promise<DriveAccount> {\n\tconst fields = encodeURIComponent('user(emailAddress,displayName)');\n\tconst r = await driveFetch(opts.auth, (token) =>\n\t\tfetch(`${DRIVE_ABOUT}?fields=${fields}`, {\n\t\t\theaders: { Authorization: `Bearer ${token}` },\n\t\t\tsignal: AbortSignal.timeout(META_DEADLINE_MS)\n\t\t})\n\t);\n\tif (r.status === 401) throw new AuthExpiredError('Drive rejected the token (401).');\n\tif (!r.ok) throw new SelfstoreError('TARGET_UNAVAILABLE', `Drive about failed: ${r.status}`);\n\tconst data: { user?: { emailAddress?: string; displayName?: string } } = await r.json();\n\treturn {\n\t\temail: data.user?.emailAddress ?? null,\n\t\tname: data.user?.displayName ?? null\n\t};\n}\n\n/** One row of `listBackups()`: what Drive reports about a file the app can\n * see. Whether the backup is encrypted is not here on purpose - that lives\n * inside the file (inspect it, or remember it app-side); a listing must stay\n * one cheap metadata call, never N downloads. */\nexport interface DriveBackupInfo {\n\tid: string;\n\tname: string;\n\t/** RFC 3339 timestamp of the last write, as Drive reports it. */\n\tmodifiedTime: string | null;\n\t/** Size in bytes, when Drive reports one. */\n\tsize: number | null;\n}\n\n/** List the files this app can see on the user's own Drive (the drive.file\n * scope already narrows visibility to files the app created or was handed).\n * `nameContains` narrows server-side; selfstore ships no naming convention -\n * the app applies its own exact rules on what comes back (its backups, its\n * internal files). Newest first. */\nexport async function listBackups(opts: {\n\tauth: DriveAuth;\n\tnameContains?: string;\n}): Promise<DriveBackupInfo[]> {\n\tconst clauses = ['trashed=false', \"'me' in owners\"];\n\tif (opts.nameContains) {\n\t\tconst safe = opts.nameContains.replace(/\\\\/g, '\\\\\\\\').replace(/'/g, \"\\\\'\");\n\t\tclauses.push(`name contains '${safe}'`);\n\t}\n\tconst q = encodeURIComponent(clauses.join(' and '));\n\tconst fields = encodeURIComponent('files(id,name,modifiedTime,size)');\n\tconst r = await driveFetch(opts.auth, (token) =>\n\t\tfetch(`${DRIVE_FILES}?q=${q}&fields=${fields}&pageSize=100&orderBy=modifiedTime%20desc`, {\n\t\t\theaders: { Authorization: `Bearer ${token}` },\n\t\t\tsignal: AbortSignal.timeout(META_DEADLINE_MS)\n\t\t})\n\t);\n\tif (r.status === 401) throw new AuthExpiredError('Drive rejected the token (401).');\n\tif (!r.ok) throw new SelfstoreError('TARGET_UNAVAILABLE', `Drive list failed: ${r.status}`);\n\tconst data: {\n\t\tfiles?: { id: string; name: string; modifiedTime?: string; size?: string | number }[];\n\t} = await r.json();\n\treturn (data.files ?? []).map((f) => ({\n\t\tid: f.id,\n\t\tname: f.name,\n\t\tmodifiedTime: f.modifiedTime ?? null,\n\t\tsize: f.size != null ? Number(f.size) : null\n\t}));\n}\n\n/** Create a brand-new empty backup file with this exact name and answer its\n * id. Refuses when a non-trashed owned file already carries the name: Drive\n * happily stores duplicate names, and a duplicate would poison every\n * find-by-name reconnect that follows. Adopts nothing - the caller decides\n * to attach it (typically with `wipe: true` so it starts blank). */\nexport async function createBackup(opts: {\n\tauth: DriveAuth;\n\tfileName: string;\n}): Promise<{ fileId: string }> {\n\tconst token = await opts.auth.token();\n\tconst existing = await findExistingFile(token, [opts.fileName]);\n\tif (existing) {\n\t\tthrow new SelfstoreError(\n\t\t\t'TARGET_WRITE_FAILED',\n\t\t\t`A file named \"${opts.fileName}\" already exists on Drive.`\n\t\t);\n\t}\n\treturn { fileId: await createFile(token, opts.fileName) };\n}\n\n/** Delete a backup file from Drive, for good (not the trash: the file's data\n * must actually be gone, not lingering). A 404 is success - deleting what is\n * already gone is not an error. The caller owns the guard against deleting\n * the currently attached file. */\nexport async function deleteBackup(opts: { auth: DriveAuth; fileId: string }): Promise<void> {\n\tconst r = await driveFetch(opts.auth, (token) =>\n\t\tfetch(`${DRIVE_FILES}/${opts.fileId}`, {\n\t\t\tmethod: 'DELETE',\n\t\t\theaders: { Authorization: `Bearer ${token}` },\n\t\t\tsignal: AbortSignal.timeout(META_DEADLINE_MS)\n\t\t})\n\t);\n\tif (r.status === 401) throw new AuthExpiredError('Drive rejected the token (401).');\n\tif (r.status === 404) return;\n\tif (!r.ok) throw new SelfstoreError('TARGET_WRITE_FAILED', `Drive delete failed: ${r.status}`);\n}\n\n/** Rename a backup file (metadata only - the id, the content and every open\n * target bound to it are untouched). Refuses when another owned file already\n * carries the new name, for the same reason createBackup does: a duplicate\n * poisons find-by-name. A 404 means the file is gone, not a success here. */\nexport async function renameBackup(opts: {\n\tauth: DriveAuth;\n\tfileId: string;\n\tfileName: string;\n}): Promise<void> {\n\tconst token = await opts.auth.token();\n\tconst existing = await findExistingFile(token, [opts.fileName]);\n\tif (existing && existing !== opts.fileId) {\n\t\tthrow new SelfstoreError(\n\t\t\t'TARGET_WRITE_FAILED',\n\t\t\t`A file named \"${opts.fileName}\" already exists on Drive.`\n\t\t);\n\t}\n\tif (existing === opts.fileId) return; // already this name: nothing to do\n\tconst r = await driveFetch(opts.auth, (token) =>\n\t\tfetch(`${DRIVE_FILES}/${opts.fileId}?fields=id`, {\n\t\t\tmethod: 'PATCH',\n\t\t\theaders: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },\n\t\t\tbody: JSON.stringify({ name: opts.fileName }),\n\t\t\tsignal: AbortSignal.timeout(META_DEADLINE_MS)\n\t\t})\n\t);\n\tif (r.status === 401) throw new AuthExpiredError('Drive rejected the token (401).');\n\tif (!r.ok) throw new SelfstoreError('TARGET_WRITE_FAILED', `Drive rename failed: ${r.status}`);\n}\n\n// --- Companion files: the Drive side of sharing ------------------------------\n//\n// Everything above operates on the user's OWN backup. Sharing needs a second\n// kind of file: a companion the app creates NEXT TO the backup, publishes on a\n// link, and tears down on its own schedule - a member's published copy, an\n// invitation others read before they join.\n//\n// These four calls plus `secondary()` are that whole Drive side. They are here\n// rather than in a consumer because every app that shares over Drive was\n// writing them again, and getting the error protocol wrong on the way: a bare\n// `throw new Error('Drive share failed: 403')` carries no code, so the store\n// cannot tell a lost session from a bad moment, and the app cannot word it.\n//\n// What is deliberately NOT here: reading another account's file. The\n// `drive.file` scope only sees files this app created or the user picked, so a\n// member cannot fetch a link-shared copy from another Drive without either the\n// Google Picker (a user gesture per file, plus a third-party script) or a relay\n// the app hosts. Both are the app's decision, and one of them is a server -\n// this library will not pick either for you. `attachPeer` takes whatever\n// `load()` you can provide.\n\n/** Create an EMPTY companion file in the user's Drive and answer its id.\n *\n * Unlike `createBackup`, it does not refuse a duplicate name: several members\n * of several groups can legitimately hold identically named copies, and the id\n * is the handle everywhere. The caller remembers the id; nothing here does. */\nexport async function createCompanion(opts: {\n\tauth: DriveAuth;\n\tfileName: string;\n}): Promise<{ fileId: string }> {\n\treturn { fileId: await createFile(await opts.auth.token(), opts.fileName) };\n}\n\n/** Make a file readable by ANYONE holding its link - the capability-link model:\n * the file carries ciphertext only, the key travels in the link's fragment, so\n * the LINK is the capability and the recipient needs no Google account.\n *\n * Idempotent from the caller's side: Drive accepts a second identical grant.\n * Publish an ENCRYPTED file, always - this hands the bytes to whoever has the\n * URL, including whoever it gets forwarded to. */\nexport async function share(opts: { auth: DriveAuth; fileId: string }): Promise<void> {\n\tconst r = await driveFetch(opts.auth, (token) =>\n\t\tfetch(`${DRIVE_FILES}/${opts.fileId}/permissions?fields=id`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },\n\t\t\tbody: JSON.stringify({ role: 'reader', type: 'anyone' }),\n\t\t\tsignal: AbortSignal.timeout(META_DEADLINE_MS)\n\t\t})\n\t);\n\tif (r.status === 401) throw new AuthExpiredError('Drive rejected the token (401).');\n\tif (!r.ok) throw new SelfstoreError('TARGET_WRITE_FAILED', `Drive share failed: ${r.status}`);\n}\n\n/** Undo `share`: drop every link-reader grant, so the file is private again.\n * Named grants (people invited individually) are left alone - this revokes the\n * capability, not the invitations.\n *\n * Call it BEFORE any plaintext rewrite of a file that was shared: a decrypted\n * copy must never stay link-readable for even one save. A file already private\n * is success, not an error. */\nexport async function unshare(opts: { auth: DriveAuth; fileId: string }): Promise<void> {\n\tconst list = await driveFetch(opts.auth, (token) =>\n\t\tfetch(`${DRIVE_FILES}/${opts.fileId}/permissions?fields=${PERMISSION_FIELDS}`, {\n\t\t\theaders: { Authorization: `Bearer ${token}` },\n\t\t\tsignal: AbortSignal.timeout(META_DEADLINE_MS)\n\t\t})\n\t);\n\tif (list.status === 401) throw new AuthExpiredError('Drive rejected the token (401).');\n\tif (list.status === 404) return; // gone is private enough\n\tif (!list.ok) {\n\t\tthrow new SelfstoreError('TARGET_UNAVAILABLE', `Drive permissions failed: ${list.status}`);\n\t}\n\tconst data: { permissions?: { id: string; type: string }[] } = await list.json();\n\tfor (const p of data.permissions ?? []) {\n\t\tif (p.type !== 'anyone') continue;\n\t\tconst r = await driveFetch(opts.auth, (token) =>\n\t\t\tfetch(`${DRIVE_FILES}/${opts.fileId}/permissions/${p.id}`, {\n\t\t\t\tmethod: 'DELETE',\n\t\t\t\theaders: { Authorization: `Bearer ${token}` },\n\t\t\t\tsignal: AbortSignal.timeout(META_DEADLINE_MS)\n\t\t\t})\n\t\t);\n\t\tif (r.status === 401) throw new AuthExpiredError('Drive rejected the token (401).');\n\t\tif (!r.ok && r.status !== 404) {\n\t\t\tthrow new SelfstoreError('TARGET_WRITE_FAILED', `Drive revoke failed: ${r.status}`);\n\t\t}\n\t}\n}\n\n/** Which account OWNS a file - not which one this session belongs to (that is\n * `account()`). Used to label a copy that lives on somebody else's Drive: a\n * member's published copy is \"Google Drive\" for everyone, and only the owner's\n * address says whose.\n *\n * Best-effort by design: a file that will not say answers nulls rather than\n * throwing, because a missing label must never break a sync round. A genuinely\n * lost session still throws, like every other call here. */\nexport async function owner(opts: { auth: DriveAuth; fileId: string }): Promise<DriveAccount> {\n\tconst fields = encodeURIComponent('owners(displayName,emailAddress)');\n\tconst r = await driveFetch(opts.auth, (token) =>\n\t\tfetch(`${DRIVE_FILES}/${opts.fileId}?fields=${fields}`, {\n\t\t\theaders: { Authorization: `Bearer ${token}` },\n\t\t\tsignal: AbortSignal.timeout(META_DEADLINE_MS)\n\t\t})\n\t);\n\tif (r.status === 401) throw new AuthExpiredError('Drive rejected the token (401).');\n\tif (!r.ok) return { email: null, name: null };\n\tconst data: { owners?: { displayName?: string; emailAddress?: string }[] } = await r.json();\n\tconst first = data.owners?.[0];\n\treturn { email: first?.emailAddress ?? null, name: first?.displayName ?? null };\n}\n\n/** A read-WRITE target over one companion file, for a store mirror or replica.\n *\n * `preview()` also binds a target to a given id, and its save() works - but its\n * name says read-only and its `disconnect()` belongs to the primary\n * connection: it calls `auth.forget()` and may drop the remembered backup id,\n * which is right when the user is leaving Drive and catastrophic when they are\n * only dropping a shared copy. This one detaches nothing but itself, and\n * carries its own `kind` so a store that persists it never mistakes it for the\n * primary destination.\n *\n * Deleting the file is `deleteBackup({ auth, fileId })`; making it private\n * again is `unshare`. Do both, in that order, when a member leaves. */\nexport function secondary(opts: { auth: DriveAuth; kv: KV }, fileId: string): BackupTarget {\n\t// No fileName: a target bound to an id never searches or creates by name, so\n\t// asking for one would be a required argument that is read nowhere - and the\n\t// first caller would have to invent a value to satisfy it.\n\treturn {\n\t\t...makeTarget({ ...opts, fileName: '' }, fileId),\n\t\tkind: 'drive-companion',\n\t\tlabel: 'Google Drive (shared copy)',\n\t\t// The companion's life is its own: leaving a share must not forget the\n\t\t// Drive session the user's real backup still rides on.\n\t\tdisconnect: async (): Promise<void> => {}\n\t};\n}\n"]}
|