@mikeargento/bitgraph 1.10.0 → 1.11.0
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/export.d.ts +88 -0
- package/dist/export.d.ts.map +1 -0
- package/dist/export.js +298 -0
- package/dist/export.js.map +1 -0
- package/dist/fuse.d.ts +136 -2
- package/dist/fuse.d.ts.map +1 -1
- package/dist/fuse.js +349 -2
- package/dist/fuse.js.map +1 -1
- package/dist/index.d.ts +11 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -1
- package/dist/index.js.map +1 -1
- package/dist/recovery-write.d.ts +58 -0
- package/dist/recovery-write.d.ts.map +1 -0
- package/dist/recovery-write.js +265 -0
- package/dist/recovery-write.js.map +1 -0
- package/dist/recovery.d.ts +490 -0
- package/dist/recovery.d.ts.map +1 -0
- package/dist/recovery.js +1124 -0
- package/dist/recovery.js.map +1 -0
- package/package.json +3 -3
- package/src/export.ts +365 -0
- package/src/fuse.ts +470 -3
- package/src/index.ts +28 -3
- package/src/recovery-write.ts +334 -0
- package/src/recovery.ts +1261 -0
|
@@ -0,0 +1,490 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Recovering a BitGraph from the file: bitgraph-recovery/1 (2026-10-03).
|
|
3
|
+
*
|
|
4
|
+
* THE RULE (Mike): anyone holding a file can always get its proof back, and
|
|
5
|
+
* export it again, if the export was lost.
|
|
6
|
+
*
|
|
7
|
+
* RECOVERY IS NOT VERIFICATION. Verification needs nothing of ours: an export
|
|
8
|
+
* and the file check themselves (packages/verify, export.ts). Recovery uses
|
|
9
|
+
* our bucket, and only to answer one question for whoever holds the bytes:
|
|
10
|
+
* which BitGraphs hold these bytes, and where is each one's proof? Each entry
|
|
11
|
+
* hands back exactly what a member's export carries (the root document and
|
|
12
|
+
* the member's evidence) plus a locator for the proof itself, which is then
|
|
13
|
+
* fetched from the public proof routes and verifies with nothing of ours.
|
|
14
|
+
*
|
|
15
|
+
* WHAT IS WRITTEN. For every member of a tree, up to two sealed entries: one
|
|
16
|
+
* under the file's origin digest (the file as dropped) and one under its
|
|
17
|
+
* artifact digest (the committed bytes), so either file in hand finds it. An
|
|
18
|
+
* as-is leaf (placement 0x00) has one digest and earns one entry.
|
|
19
|
+
*
|
|
20
|
+
* FORMATS. Hex is lowercase. digest32 is the RAW 32-byte SHA-256, never its
|
|
21
|
+
* text; proofHash32 is the raw 32 bytes of computeProofHash(proof) (the
|
|
22
|
+
* ledger identity, base64 in the verify package).
|
|
23
|
+
*
|
|
24
|
+
* address = hex SHA-256( UTF-8 "bitgraph-lookup" || digest32 )
|
|
25
|
+
* entryId = hex SHA-256( UTF-8 "bitgraph-lookup-entry" || digest32 || proofHash32 || leafIndex u32 big-endian )
|
|
26
|
+
* saltedId = hex SHA-256( UTF-8 "bitgraph-lookup-entry/salted" || digest32 || proofHash32 || leafIndex u32 big-endian || salt32 )
|
|
27
|
+
* the fallback name when the deterministic key is held by another entry (squatting, below);
|
|
28
|
+
* the salt (32 random bytes) is sealed in the plaintext, so a reader checks the name either way
|
|
29
|
+
* key = SHA-256( UTF-8 "bitgraph-lookup-key" || digest32 ) the AES-256-GCM key
|
|
30
|
+
* objectKey = "recovery/v1/" + address + "/" + entryId
|
|
31
|
+
* envelope = 0x01 || nonce (12 random bytes, fresh per entry) || ciphertext || tag (16)
|
|
32
|
+
* AAD = objectKey as UTF-8
|
|
33
|
+
* plaintext = UTF-8 JSON, written in this key order:
|
|
34
|
+
* { "format": "bitgraph-recovery/1",
|
|
35
|
+
* "proofHash": base64 (44),
|
|
36
|
+
* "leafIndex": n,
|
|
37
|
+
* "rootDocument": hex (168),
|
|
38
|
+
* "member": { "index", "count", "leaf", "path" } TreeMemberEvidence
|
|
39
|
+
* "proof": { "epochId", "counter", "artifactDigestB64" } a locator
|
|
40
|
+
* "salt"?: base64 (44), present exactly when the entry is salted
|
|
41
|
+
* "name"?: string } advisory, at most 512 UTF-8 bytes
|
|
42
|
+
*
|
|
43
|
+
* The four labels differ and every input after a label is fixed length, so
|
|
44
|
+
* the four preimages (47, 51, 89 and 128 bytes) can never be confused with
|
|
45
|
+
* one another. The address is public (it is in the object key); the key is
|
|
46
|
+
* not derivable from it without the digest.
|
|
47
|
+
*
|
|
48
|
+
* SQUATTING, AND THE SALTED FALLBACK. Keys are deterministic and writes are
|
|
49
|
+
* create-only, so whoever knows a file's digest and its proof hash can occupy
|
|
50
|
+
* a member's deterministic key first. They cannot make a wrong proof come
|
|
51
|
+
* back (a reader binds every entry to its proof and verifies the member), but
|
|
52
|
+
* they could deny that one entry. So a writer that finds another member's
|
|
53
|
+
* envelope at its deterministic key writes the same plaintext, plus a fresh
|
|
54
|
+
* 32-byte salt, under the salted name instead; a reader accepts either name
|
|
55
|
+
* when the plaintext derives it, and lists one member once however many
|
|
56
|
+
* names it has. The salt is kept by the writer before the salted write, so a
|
|
57
|
+
* retry lands on the same key. Listing spam under an address stays a
|
|
58
|
+
* rate-limit matter.
|
|
59
|
+
*
|
|
60
|
+
* LOOKING UP MANY FILES AT ONCE. recoverFromDigests asks one request for the
|
|
61
|
+
* first page of many addresses. That tells the server which addresses were
|
|
62
|
+
* asked together, a linkage one-by-one requests only hint at by timing; the
|
|
63
|
+
* route logs counts, never addresses, and the SPEC says so.
|
|
64
|
+
*
|
|
65
|
+
* WHY THE ENTRY ID IS A HASH. The first draft keyed entries
|
|
66
|
+
* "<address>/<proofHash>/<leafIndex>", which let anyone listing the bucket
|
|
67
|
+
* group every entry of one drop by the shared proofHash. The entryId is still
|
|
68
|
+
* deterministic (a rewrite after a crash lands on the same key, so writes stay
|
|
69
|
+
* idempotent) and two members of one tree never collide (the leaf index is in
|
|
70
|
+
* it), but it says nothing about which tree it belongs to without the digest.
|
|
71
|
+
*
|
|
72
|
+
* PRIVACY, AND ITS LIMIT. The server sees object keys and opaque envelopes,
|
|
73
|
+
* never a digest, a proof hash, a leaf or a name. But anyone who KNOWS a
|
|
74
|
+
* file's digest (holding the file, a published digest, or guessing among a
|
|
75
|
+
* few candidate files) can derive the address and key and test whether it was
|
|
76
|
+
* recorded; that is the same ability recovery needs. The promise covers these
|
|
77
|
+
* sealed entries only, not older plain-digest indexes, logs or metadata. (One
|
|
78
|
+
* piece of metadata worth naming: the entries of one drop are written in the
|
|
79
|
+
* same requests and land with near-identical write times, so whoever can list
|
|
80
|
+
* the bucket can group them by time. Today that is only BitGraph.)
|
|
81
|
+
*
|
|
82
|
+
* WHAT A STORED ENTRY IS WORTH. Whoever holds the file can write an entry for
|
|
83
|
+
* it; that is the rule working, not a hole. So an entry is never trusted for
|
|
84
|
+
* holding the right key: it is opened (AES-GCM, AAD the object key), parsed
|
|
85
|
+
* strictly, its entryId recomputed, its leaf checked to name the looked-up
|
|
86
|
+
* digest, its path checked to reach the root inside its own root document,
|
|
87
|
+
* and that document checked to hash to the locator's digest. Then the proof is
|
|
88
|
+
* fetched and bound by proofHash and verifyTreeMember (fetchRecoveredProof).
|
|
89
|
+
* A writer who knows the digest can occupy a key; they cannot make a wrong
|
|
90
|
+
* proof come back as this file's. (The queue reports a member whose key was
|
|
91
|
+
* occupied first as "blocked", and keeps writing its other entry.)
|
|
92
|
+
*
|
|
93
|
+
* CREATE-ONLY. Entries are written with If-None-Match: * and never replaced;
|
|
94
|
+
* see recovery-store-s3.ts for the bucket policy that keeps a delete marker
|
|
95
|
+
* from ever letting a second version in under the same key.
|
|
96
|
+
*
|
|
97
|
+
* SHA-256 here is @noble/hashes (as in packages/verify), AES-GCM is WebCrypto.
|
|
98
|
+
* Both run unchanged in the browser and in node 20+. The hashes are noble's
|
|
99
|
+
* rather than crypto.subtle.digest's because a tree of 100,000 files needs
|
|
100
|
+
* 600,000 small hashes: measured on node 24, 300,000 cost 275 ms through
|
|
101
|
+
* noble and 2,368 ms through subtle (one promise and thread hop each). The
|
|
102
|
+
* bytes are identical; the test suite derives every format again with
|
|
103
|
+
* node:crypto to prove it.
|
|
104
|
+
*/
|
|
105
|
+
import { MerkleTree, type BitGraphProof, type TreeLeaf, type TreeMemberEvidence, type TreeVerifyResult, type ByteSource } from "@mikeargento/bitgraph-verify";
|
|
106
|
+
export declare const RECOVERY_FORMAT: "bitgraph-recovery/1";
|
|
107
|
+
export declare const RECOVERY_PREFIX: "recovery/v1/";
|
|
108
|
+
export declare const ENVELOPE_VERSION = 1;
|
|
109
|
+
export declare const NONCE_BYTES = 12;
|
|
110
|
+
export declare const TAG_BYTES = 16;
|
|
111
|
+
/** Version byte, nonce and tag: 29 bytes around the ciphertext. */
|
|
112
|
+
export declare const ENVELOPE_OVERHEAD: number;
|
|
113
|
+
/**
|
|
114
|
+
* The largest envelope anyone may store. Sized from the response, not the
|
|
115
|
+
* entry: a batch of MAX_BATCH_ENTRIES whose keys all exist comes back with
|
|
116
|
+
* every stored envelope in it, and a Vercel function answers at most 4.5 MB.
|
|
117
|
+
* 500 x 4,096 bytes is 2.7 MB as base64, in both directions. The largest
|
|
118
|
+
* honest plaintext (a 1,000,000-leaf tree's 20-node path, the longest
|
|
119
|
+
* locator, a 512-byte name) is about 3.1 KB; the suite pins that it fits.
|
|
120
|
+
*/
|
|
121
|
+
export declare const MAX_ENVELOPE_BYTES = 4096;
|
|
122
|
+
export declare const MIN_ENVELOPE_BYTES: number;
|
|
123
|
+
export declare const MAX_PLAINTEXT_BYTES: number;
|
|
124
|
+
/** A name longer than this keeps its last 509 bytes behind "…" (a path's tail is the file's own name). */
|
|
125
|
+
export declare const MAX_NAME_BYTES = 512;
|
|
126
|
+
/** Entries per POST. */
|
|
127
|
+
export declare const MAX_BATCH_ENTRIES = 500;
|
|
128
|
+
/** A POST body above this is refused before it is parsed. A full batch of the largest envelopes is about 2.8 MB. */
|
|
129
|
+
export declare const MAX_BODY_BYTES = 4000000;
|
|
130
|
+
/** Entries per page of GET /api/recovery/<address>. */
|
|
131
|
+
export declare const MAX_LIST_LIMIT = 100;
|
|
132
|
+
export declare const ADDRESS_PATTERN: RegExp;
|
|
133
|
+
export declare const ENTRY_ID_PATTERN: RegExp;
|
|
134
|
+
export declare const OBJECT_KEY_PATTERN: RegExp;
|
|
135
|
+
/** "recovery/v1/" + 64 + "/" + 64. */
|
|
136
|
+
export declare const OBJECT_KEY_LENGTH: number;
|
|
137
|
+
/** A salted entry's salt: 32 random bytes, sealed in its plaintext. */
|
|
138
|
+
export declare const SALT_BYTES = 32;
|
|
139
|
+
/** Addresses one lookup request may ask for (POST /api/recovery/lookup). */
|
|
140
|
+
export declare const MAX_LOOKUP_ADDRESSES = 1000;
|
|
141
|
+
/** The most a lookup answer carries (under the hosting platform's 4.5 MB response limit); addresses past it come back `truncated` and are listed one by one. */
|
|
142
|
+
export declare const MAX_LOOKUP_RESPONSE_BYTES = 3500000;
|
|
143
|
+
/** The default time one recovery read may take. */
|
|
144
|
+
export declare const LOOKUP_TIMEOUT_MS = 30000;
|
|
145
|
+
/** The most a lookup request's body may be (1,000 addresses are 70 KB). */
|
|
146
|
+
export declare const MAX_LOOKUP_BODY_BYTES = 131072;
|
|
147
|
+
/** More distinct members than this listed under one address, and the lookup is unknown: each would cost a proof fetch, and nothing honest records one file this often. */
|
|
148
|
+
export declare const MAX_RECOVERED_PER_DIGEST = 200;
|
|
149
|
+
/** A caller handed the queue or the sealer something that must never be written. */
|
|
150
|
+
export declare class RecoveryInputError extends Error {
|
|
151
|
+
constructor(message: string);
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* The recovery entries could not be READ. Never an answer about whether the
|
|
155
|
+
* file was recorded: "we could not check" and "nothing is kept for these
|
|
156
|
+
* bytes" are different claims, and only the second is a finding.
|
|
157
|
+
*/
|
|
158
|
+
export declare class RecoveryUnavailableError extends Error {
|
|
159
|
+
constructor(where: string, cause?: unknown);
|
|
160
|
+
}
|
|
161
|
+
export type FetchLike = (input: string, init?: RequestInit) => Promise<Response>;
|
|
162
|
+
/** hex SHA-256("bitgraph-lookup" || digest32): the public folder a file's entries live in. */
|
|
163
|
+
export declare function recoveryAddress(digest32: Uint8Array): string;
|
|
164
|
+
/** SHA-256("bitgraph-lookup-key" || digest32): the AES-256-GCM key every entry under this digest is sealed with. */
|
|
165
|
+
export declare function recoveryKeyBytes(digest32: Uint8Array): Uint8Array;
|
|
166
|
+
/** hex SHA-256("bitgraph-lookup-entry" || digest32 || proofHash32 || leafIndex u32 BE): one entry's name inside the address. */
|
|
167
|
+
export declare function recoveryEntryId(digest32: Uint8Array, proofHash32: Uint8Array, leafIndex: number): string;
|
|
168
|
+
/** hex SHA-256("bitgraph-lookup-entry/salted" || digest32 || proofHash32 || leafIndex u32 BE || salt32): the entry's fallback name when its deterministic one is held. */
|
|
169
|
+
export declare function recoverySaltedEntryId(digest32: Uint8Array, proofHash32: Uint8Array, leafIndex: number, salt32: Uint8Array): string;
|
|
170
|
+
/** A fresh salt for a salted entry. */
|
|
171
|
+
export declare function newRecoverySalt(): Uint8Array;
|
|
172
|
+
export declare function recoveryObjectKey(address: string, entryId: string): string;
|
|
173
|
+
/** The address and entry id of a well-formed object key; null for anything else. */
|
|
174
|
+
export declare function parseRecoveryObjectKey(key: unknown): {
|
|
175
|
+
address: string;
|
|
176
|
+
entryId: string;
|
|
177
|
+
} | null;
|
|
178
|
+
/**
|
|
179
|
+
* Seal one entry: 0x01 || nonce || AES-256-GCM(plaintext) || tag, with the
|
|
180
|
+
* object key as associated data, so an envelope opens only at the key it was
|
|
181
|
+
* written for. The nonce is 12 random bytes per call. A key encrypts one
|
|
182
|
+
* entry per recording of one file, so random nonces are nowhere near their
|
|
183
|
+
* limit.
|
|
184
|
+
*/
|
|
185
|
+
export declare function sealRecoveryEnvelope(keyBytes: Uint8Array, objectKey: string, plaintext: Uint8Array): Promise<Uint8Array>;
|
|
186
|
+
/** The plaintext, or null when the envelope is not version 1 or does not authenticate under this key at this object key. */
|
|
187
|
+
export declare function openRecoveryEnvelope(keyBytes: Uint8Array, objectKey: string, envelope: Uint8Array): Promise<Uint8Array | null>;
|
|
188
|
+
/** Where the proof is: its position, and the digest the public proof routes find it under. */
|
|
189
|
+
export interface RecoveryLocator {
|
|
190
|
+
epochId: string;
|
|
191
|
+
counter: string;
|
|
192
|
+
/** Standard base64 SHA-256 of the root document: the proof's signed artifact digest. */
|
|
193
|
+
artifactDigestB64: string;
|
|
194
|
+
}
|
|
195
|
+
export interface RecoveryPlaintext {
|
|
196
|
+
format: typeof RECOVERY_FORMAT;
|
|
197
|
+
/** base64 computeProofHash(proof). */
|
|
198
|
+
proofHash: string;
|
|
199
|
+
leafIndex: number;
|
|
200
|
+
/** The 84-byte root document, lowercase hex. */
|
|
201
|
+
rootDocument: string;
|
|
202
|
+
member: TreeMemberEvidence;
|
|
203
|
+
proof: RecoveryLocator;
|
|
204
|
+
/** Present exactly when the entry sits under its salted name: the 32-byte salt, base64. */
|
|
205
|
+
salt?: string;
|
|
206
|
+
/** Advisory, unsigned, like an export's names. */
|
|
207
|
+
name?: string;
|
|
208
|
+
}
|
|
209
|
+
/** The canonical bytes: keys in the documented order, compact JSON, UTF-8. */
|
|
210
|
+
export declare function encodeRecoveryPlaintext(p: RecoveryPlaintext): Uint8Array;
|
|
211
|
+
/**
|
|
212
|
+
* Strict read, and every check that needs nothing but the plaintext: exactly
|
|
213
|
+
* the documented keys, the format, a 32-byte proof hash, a root document that
|
|
214
|
+
* parses, member evidence that parses (verify's own strict reader), the leaf
|
|
215
|
+
* index and the tree size agreeing everywhere, the member's path reaching the
|
|
216
|
+
* root inside this root document, and the locator naming this document's
|
|
217
|
+
* hash. Null on any deviation. It does not say the proof exists or binds
|
|
218
|
+
* this document; fetchRecoveredProof does.
|
|
219
|
+
*/
|
|
220
|
+
export declare function parseRecoveryPlaintext(bytes: Uint8Array): RecoveryPlaintext | null;
|
|
221
|
+
/** The entry id a plaintext derives for digest `d`: the salted name when it carries a salt, else the deterministic one. */
|
|
222
|
+
export declare function recoveryEntryIdOf(digest32: Uint8Array, p: RecoveryPlaintext): string;
|
|
223
|
+
/**
|
|
224
|
+
* The same member of the same recording, field by field: proof hash, leaf
|
|
225
|
+
* index, root document, the whole evidence (leaf and every path node) and the
|
|
226
|
+
* locator. The design's first test was proof hash and leaf index only, and
|
|
227
|
+
* that is not enough: anyone who knows the digest can seal an envelope that
|
|
228
|
+
* carries the right two numbers around a wrong path or a wrong locator, and a
|
|
229
|
+
* client that accepted it would mark the file recoverable while its only
|
|
230
|
+
* entry is useless. The name is left out on purpose: it is advisory and
|
|
231
|
+
* unsigned, and nothing recovered rests on it; so is the salt, which names
|
|
232
|
+
* the entry and says nothing about the member.
|
|
233
|
+
*/
|
|
234
|
+
export declare function sameRecoveryMember(a: RecoveryPlaintext, b: RecoveryPlaintext): boolean;
|
|
235
|
+
/** Keep a long name's tail (a path's tail is the file's own name) inside MAX_NAME_BYTES; undefined for no name. */
|
|
236
|
+
export declare function clampRecoveryName(name: string | null | undefined): string | undefined;
|
|
237
|
+
export interface RecoveryTreeParts {
|
|
238
|
+
/** base64 computeProofHash(proof). */
|
|
239
|
+
proofHash: string;
|
|
240
|
+
locator: RecoveryLocator;
|
|
241
|
+
/** The 84-byte root document. */
|
|
242
|
+
rootDocument: Uint8Array;
|
|
243
|
+
/** The owner's list: every leaf in tree order (count x 65 bytes). */
|
|
244
|
+
leaves: Uint8Array;
|
|
245
|
+
}
|
|
246
|
+
export interface RecoveryTree {
|
|
247
|
+
proofHash: string;
|
|
248
|
+
proofHash32: Uint8Array;
|
|
249
|
+
locator: RecoveryLocator;
|
|
250
|
+
rootDocument: Uint8Array;
|
|
251
|
+
rootDocumentHex: string;
|
|
252
|
+
count: number;
|
|
253
|
+
/** count x 65 bytes, tree order; a private copy. */
|
|
254
|
+
leaves: Uint8Array;
|
|
255
|
+
/** Over the leaf hashes, for every member's path. */
|
|
256
|
+
tree: MerkleTree;
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Everything is checked before anything is sealed, because what is sealed is
|
|
260
|
+
* written create-only under keys nobody can ever reuse: an entry built from a
|
|
261
|
+
* list that does not rebuild the committed root would hold its member's key
|
|
262
|
+
* for ten years and help nobody. The checks are verifyTreeLeaves' own (count,
|
|
263
|
+
* every leaf valid, strictly ascending artifact digests, the rebuilt root
|
|
264
|
+
* equal to the document's; the suite pins the two agreeing), done here so
|
|
265
|
+
* the tree that proves the list is the tree that makes the paths.
|
|
266
|
+
*/
|
|
267
|
+
export declare function recoveryTreeFromParts(parts: RecoveryTreeParts): RecoveryTree;
|
|
268
|
+
/** The proof's own parts: its proof hash, its position and its signed artifact digest. Throws for anything that is not a tree/1 proof with a position. */
|
|
269
|
+
export declare function recoveryProofParts(proof: BitGraphProof): {
|
|
270
|
+
proofHash: string;
|
|
271
|
+
locator: RecoveryLocator;
|
|
272
|
+
};
|
|
273
|
+
export interface RecoveryTreeInput {
|
|
274
|
+
proof: BitGraphProof;
|
|
275
|
+
/** The 84-byte root document; read from proof.metadata when omitted. */
|
|
276
|
+
rootDocument?: Uint8Array | null;
|
|
277
|
+
/** Every leaf in tree order: the 65-byte encodings concatenated, or the leaves themselves. */
|
|
278
|
+
leaves?: Uint8Array | readonly TreeLeaf[];
|
|
279
|
+
/** The same list already encoded (fuse-tree-make's MadeTree carries both); preferred when present. */
|
|
280
|
+
leavesBytes?: Uint8Array;
|
|
281
|
+
}
|
|
282
|
+
/** A tree/1 proof and its owner's list, checked and ready to seal. */
|
|
283
|
+
export declare function recoveryTreeFrom(input: RecoveryTreeInput): RecoveryTree;
|
|
284
|
+
/** The owner's list as bytes, from whichever form the caller holds. */
|
|
285
|
+
export declare function leavesBytesOf(input: {
|
|
286
|
+
leaves?: Uint8Array | readonly TreeLeaf[];
|
|
287
|
+
leavesBytes?: Uint8Array;
|
|
288
|
+
}): Uint8Array;
|
|
289
|
+
/** Leaf `index` of the list, raw. */
|
|
290
|
+
export declare function leafBytesAt(tree: {
|
|
291
|
+
leaves: Uint8Array;
|
|
292
|
+
}, index: number): Uint8Array;
|
|
293
|
+
/**
|
|
294
|
+
* Member `index`'s plaintext and its bytes. A name that would push the
|
|
295
|
+
* plaintext past MAX_PLAINTEXT_BYTES (only possible with hundreds of escaped
|
|
296
|
+
* control characters) is dropped, never the entry.
|
|
297
|
+
*/
|
|
298
|
+
export declare function recoveryPlaintextFor(tree: RecoveryTree, index: number, name?: string | null, salt?: Uint8Array | null): {
|
|
299
|
+
plaintext: RecoveryPlaintext;
|
|
300
|
+
bytes: Uint8Array;
|
|
301
|
+
};
|
|
302
|
+
/** Which of a leaf's digests an entry is filed under. An as-is leaf has one digest and one entry. */
|
|
303
|
+
export type RecoverySide = "origin" | "artifact" | "as-is";
|
|
304
|
+
export interface RecoveryWrite {
|
|
305
|
+
side: RecoverySide;
|
|
306
|
+
/** The digest the entry is sealed under (a private copy). */
|
|
307
|
+
digest: Uint8Array;
|
|
308
|
+
objectKey: string;
|
|
309
|
+
envelope: Uint8Array;
|
|
310
|
+
/** The entry's deterministic key: its own key, or the held key a salted entry stands in for. */
|
|
311
|
+
deterministicKey: string;
|
|
312
|
+
/** True when the entry sits under its salted name. */
|
|
313
|
+
salted: boolean;
|
|
314
|
+
/** The plaintext sealed into this envelope (the salt is in it when salted). */
|
|
315
|
+
plaintext: RecoveryPlaintext;
|
|
316
|
+
}
|
|
317
|
+
/** The sides member `index` is filed under: ["as-is"] for placement 0x00, else ["origin", "artifact"]. */
|
|
318
|
+
export declare function recoverySidesOf(tree: {
|
|
319
|
+
leaves: Uint8Array;
|
|
320
|
+
}, index: number): RecoverySide[];
|
|
321
|
+
/** The digest one side of member `index` is filed under. */
|
|
322
|
+
export declare function recoveryDigestOf(tree: {
|
|
323
|
+
leaves: Uint8Array;
|
|
324
|
+
}, index: number, side: RecoverySide): Uint8Array;
|
|
325
|
+
/** Bit 0 origin kept, bit 1 committed bytes kept, bit 2 origin blocked, bit 3 committed bytes blocked. An as-is member sets both bits of a kind at once. */
|
|
326
|
+
export declare const ORIGIN_KEPT = 1;
|
|
327
|
+
export declare const ARTIFACT_KEPT = 2;
|
|
328
|
+
export declare const ORIGIN_BLOCKED = 4;
|
|
329
|
+
export declare const ARTIFACT_BLOCKED = 8;
|
|
330
|
+
export declare const RECOVERY_SIDE_BITS: Record<RecoverySide, {
|
|
331
|
+
kept: number;
|
|
332
|
+
blocked: number;
|
|
333
|
+
}>;
|
|
334
|
+
export type RecoveryMemberStatus = "pending" | "recoverable" | "blocked";
|
|
335
|
+
export type RecoverySideState = "kept" | "pending" | "blocked";
|
|
336
|
+
/** A member's status from its progress byte alone (so a finished job, whose list is gone, still answers). */
|
|
337
|
+
export declare function recoveryMemberStatus(b: number): RecoveryMemberStatus;
|
|
338
|
+
export declare function recoverySideState(b: number, side: RecoverySide): RecoverySideState;
|
|
339
|
+
export declare const recoverySideResolved: (b: number, side: RecoverySide) => boolean;
|
|
340
|
+
/** The key a member's side has in a writer's salt table: "<leafIndex>:<side>". */
|
|
341
|
+
export declare const recoverySaltKey: (index: number, side: RecoverySide) => string;
|
|
342
|
+
/** A writer's salt table (base64 salts by recoverySaltKey) as the `salts` sealRecoveryMember takes for member `index`; null when it holds none for that member. */
|
|
343
|
+
export declare function recoverySaltsFor(salts: Readonly<Record<string, string>> | null | undefined, index: number): Partial<Record<RecoverySide, Uint8Array>> | null;
|
|
344
|
+
/** The object key one side of member `index` is filed under: deterministic, or salted when a salt is given. */
|
|
345
|
+
export declare function recoveryObjectKeyFor(tree: RecoveryTree, index: number, side: RecoverySide, salt?: Uint8Array | null): string;
|
|
346
|
+
/**
|
|
347
|
+
* Seal member `index`: one envelope per side (or only the sides asked for),
|
|
348
|
+
* each under its own key, nonce and AAD. A side named in `salts` is sealed
|
|
349
|
+
* under its salted name, with the salt in its plaintext; `plaintext` is the
|
|
350
|
+
* unsalted one, the member all of them describe.
|
|
351
|
+
*/
|
|
352
|
+
export declare function sealRecoveryMember(tree: RecoveryTree, index: number, name?: string | null, only?: readonly RecoverySide[], salts?: Partial<Record<RecoverySide, Uint8Array>> | null): Promise<{
|
|
353
|
+
plaintext: RecoveryPlaintext;
|
|
354
|
+
writes: RecoveryWrite[];
|
|
355
|
+
}>;
|
|
356
|
+
/**
|
|
357
|
+
* The 412 path's test: the envelope already stored at `objectKey` holds THIS
|
|
358
|
+
* member (sameRecoveryMember), opened with the digest's key at that key. A
|
|
359
|
+
* stored envelope that does not open, does not parse, or holds anything else
|
|
360
|
+
* is somebody else's entry, and the write is not a success.
|
|
361
|
+
*/
|
|
362
|
+
export declare function existingEntryHoldsMember(digest32: Uint8Array, objectKey: string, envelope: Uint8Array, expected: RecoveryPlaintext): Promise<boolean>;
|
|
363
|
+
/**
|
|
364
|
+
* This member's own entry under its address, if one is already there under
|
|
365
|
+
* any name: the deterministic one, or a salted one from an earlier run whose
|
|
366
|
+
* salt was lost (a job finished and removed, a browser tab's save that
|
|
367
|
+
* failed). Returns the entry's key and, for a salted one, its salt, so the
|
|
368
|
+
* writer counts it kept and reuses the salt instead of leaving a second copy.
|
|
369
|
+
* Null when none is there; raises RecoveryUnavailableError when the address
|
|
370
|
+
* cannot be read (then the writer must not guess).
|
|
371
|
+
*/
|
|
372
|
+
export declare function findOwnRecoveryEntry(digest32: Uint8Array, expected: RecoveryPlaintext, fetchFn?: FetchLike, opts?: RecoveryLookupOptions): Promise<{
|
|
373
|
+
objectKey: string;
|
|
374
|
+
salt: Uint8Array | null;
|
|
375
|
+
} | null>;
|
|
376
|
+
export interface RecoveredEntry {
|
|
377
|
+
objectKey: string;
|
|
378
|
+
entryId: string;
|
|
379
|
+
/** True when the entry sits under its salted name (its deterministic one was held by another entry). */
|
|
380
|
+
salted: boolean;
|
|
381
|
+
/** The salted entry's salt, base64; null under the deterministic name. */
|
|
382
|
+
salt: string | null;
|
|
383
|
+
/** Which of the leaf's digests the looked-up digest is: "as-is" when the leaf has one. */
|
|
384
|
+
matched: RecoverySide;
|
|
385
|
+
/** base64 computeProofHash(proof) of the recording. */
|
|
386
|
+
proofHash: string;
|
|
387
|
+
leafIndex: number;
|
|
388
|
+
/** Hex, 84 bytes: an export's tree.rootDocument. */
|
|
389
|
+
rootDocument: string;
|
|
390
|
+
/** An export's tree.member. */
|
|
391
|
+
member: TreeMemberEvidence;
|
|
392
|
+
proof: RecoveryLocator;
|
|
393
|
+
name: string | null;
|
|
394
|
+
}
|
|
395
|
+
export interface RecoveryLookupOptions {
|
|
396
|
+
/** Origin of the site's routes; "" (same origin) in the browser. */
|
|
397
|
+
baseUrl?: string;
|
|
398
|
+
/** A guard against a server whose pages never end. Default 1,000 (100,000 entries). */
|
|
399
|
+
maxPages?: number;
|
|
400
|
+
/** The most one read may take; a read that outlasts it is a failed read. Default LOOKUP_TIMEOUT_MS. */
|
|
401
|
+
timeoutMs?: number;
|
|
402
|
+
}
|
|
403
|
+
/**
|
|
404
|
+
* Every recording of the file whose SHA-256 is `digest32`, from the sealed
|
|
405
|
+
* entries under its address: one entry per member per recording, so the same
|
|
406
|
+
* file recorded twice comes back twice (and the same member under two names
|
|
407
|
+
* once). An entry that does not authenticate, does not parse, sits under an
|
|
408
|
+
* entry id its own contents do not derive, or names a leaf that is not this
|
|
409
|
+
* digest is skipped: it is not ours to show. The list is in the server's
|
|
410
|
+
* listing order; order the recordings by their proofs' own times once
|
|
411
|
+
* fetched.
|
|
412
|
+
*
|
|
413
|
+
* Raises RecoveryUnavailableError when the entries cannot be read, a route
|
|
414
|
+
* that answers 404 included. An empty array is an answer (nothing is kept
|
|
415
|
+
* for these bytes); a failure never is.
|
|
416
|
+
*/
|
|
417
|
+
export declare function recoverFromDigest(digest32: Uint8Array, fetchFn?: FetchLike, opts?: RecoveryLookupOptions): Promise<RecoveredEntry[]>;
|
|
418
|
+
/** One digest's lookup in a batch: every page read and every entry opened, or why it could not be. A failure is never a verdict. */
|
|
419
|
+
export type RecoveryLookupAnswer = {
|
|
420
|
+
ok: true;
|
|
421
|
+
entries: RecoveredEntry[];
|
|
422
|
+
} | {
|
|
423
|
+
ok: false;
|
|
424
|
+
reason: string;
|
|
425
|
+
};
|
|
426
|
+
/**
|
|
427
|
+
* recoverFromDigest for many files at once: the first page of every address
|
|
428
|
+
* in one request (POST /api/recovery/lookup, at most MAX_LOOKUP_ADDRESSES per
|
|
429
|
+
* request), then the rest of any longer listing page by page. One answer per
|
|
430
|
+
* digest, in order; a digest whose entries could not all be read answers
|
|
431
|
+
* { ok: false }, never an empty list. A site without the route (404) is asked
|
|
432
|
+
* one address at a time instead.
|
|
433
|
+
*
|
|
434
|
+
* Asking many addresses in one request tells the server which files were
|
|
435
|
+
* dropped together, which one-by-one requests only hint at by timing. The
|
|
436
|
+
* route logs counts, never addresses (SPEC section 13).
|
|
437
|
+
*/
|
|
438
|
+
export declare function recoverFromDigests(digests: readonly Uint8Array[], fetchFn?: FetchLike, opts?: RecoveryLookupOptions): Promise<RecoveryLookupAnswer[]>;
|
|
439
|
+
/**
|
|
440
|
+
* The measurement policy a recovery reader judges proofs by (SPEC section
|
|
441
|
+
* 5.6): "published", BitGraph's published images (the default); a list of
|
|
442
|
+
* PCR0 hex strings, the reader's own; "none", the signature and tree alone
|
|
443
|
+
* (tests with the published TEST key). An empty list judges nothing: every
|
|
444
|
+
* candidate is then unresolved, never a negative (see proofTrusted).
|
|
445
|
+
*/
|
|
446
|
+
export type RecoveryTrust = "published" | "none" | readonly string[];
|
|
447
|
+
/**
|
|
448
|
+
* Whether the proof's attestation verified in full (AWS signature, chain,
|
|
449
|
+
* root, validity, PCR0 as the proof names it, bound to this proof's signed
|
|
450
|
+
* body) and attests an image the policy accepts. "undetermined" when the
|
|
451
|
+
* policy is empty: nothing was judged, and a reader must leave the candidate
|
|
452
|
+
* unresolved rather than call it negative.
|
|
453
|
+
*/
|
|
454
|
+
export declare function proofTrusted(proof: BitGraphProof, policy?: RecoveryTrust): "trusted" | "rejected" | "undetermined";
|
|
455
|
+
export interface RecoveredProof {
|
|
456
|
+
proof: BitGraphProof;
|
|
457
|
+
/**
|
|
458
|
+
* verifyTreeMember on the fetched proof with this entry's root document and
|
|
459
|
+
* evidence (and the file, when given): TREE_PATH_VALID, or one of the
|
|
460
|
+
* TREE_MEMBER categories with the file, is a recovered BitGraph. Anything
|
|
461
|
+
* else is a reason, never a verdict about the file.
|
|
462
|
+
*/
|
|
463
|
+
check: TreeVerifyResult;
|
|
464
|
+
}
|
|
465
|
+
/**
|
|
466
|
+
* The proof a recovered entry points at, from the public proof routes by its
|
|
467
|
+
* artifact digest, bound by proof hash (a proof whose computeProofHash is not
|
|
468
|
+
* the entry's is not this recording) and checked with verifyTreeMember.
|
|
469
|
+
* Null when no proof under that digest has this proof hash. Raises
|
|
470
|
+
* RecoveryUnavailableError when the route cannot be read.
|
|
471
|
+
*
|
|
472
|
+
* With the proof and the entry in hand an export is the existing machinery:
|
|
473
|
+
* fuse-tree's buildTreeExport(proof, memberTree(rootDocument, member),
|
|
474
|
+
* await fetchTreeEvidence(proof)).
|
|
475
|
+
*
|
|
476
|
+
* ⚠️ THIS READ NEEDS THE LEDGER'S BY-DIGEST INDEX for the tree's artifact
|
|
477
|
+
* digest, which exists while per-proof writes are on (LEDGER_WRITES). If they
|
|
478
|
+
* are ever switched off, the entry still names the proof exactly: the
|
|
479
|
+
* parent's own key is proofs/<url-safe epochId>/<counter, 12 digits>-<url-safe
|
|
480
|
+
* proofHash>.json, and a read-only route serving that key is all this needs.
|
|
481
|
+
*/
|
|
482
|
+
export declare function fetchRecoveredProof(entry: Pick<RecoveredEntry, "proofHash" | "rootDocument" | "member" | "proof">, fetchFn?: FetchLike, opts?: {
|
|
483
|
+
baseUrl?: string;
|
|
484
|
+
bytes?: Uint8Array;
|
|
485
|
+
source?: ByteSource;
|
|
486
|
+
extraSpecHashes?: readonly string[];
|
|
487
|
+
timeoutMs?: number;
|
|
488
|
+
trust?: RecoveryTrust;
|
|
489
|
+
}): Promise<RecoveredProof | null>;
|
|
490
|
+
//# sourceMappingURL=recovery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recovery.d.ts","sourceRoot":"","sources":["../src/recovery.ts"],"names":[],"mappings":"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"}
|