@interop/was-client 0.17.0 → 0.19.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.
Files changed (94) hide show
  1. package/README.md +88 -0
  2. package/dist/Collection.d.ts +1 -46
  3. package/dist/Collection.d.ts.map +1 -1
  4. package/dist/Collection.js +77 -79
  5. package/dist/Collection.js.map +1 -1
  6. package/dist/Resource.d.ts +1 -51
  7. package/dist/Resource.d.ts.map +1 -1
  8. package/dist/Resource.js +61 -58
  9. package/dist/Resource.js.map +1 -1
  10. package/dist/Space.d.ts +1 -27
  11. package/dist/Space.d.ts.map +1 -1
  12. package/dist/Space.js +65 -65
  13. package/dist/Space.js.map +1 -1
  14. package/dist/WasClient.d.ts +1 -12
  15. package/dist/WasClient.d.ts.map +1 -1
  16. package/dist/WasClient.js +15 -15
  17. package/dist/WasClient.js.map +1 -1
  18. package/dist/codec.d.ts +15 -2
  19. package/dist/codec.d.ts.map +1 -1
  20. package/dist/edv/EdvCodec.d.ts +13 -95
  21. package/dist/edv/EdvCodec.d.ts.map +1 -1
  22. package/dist/edv/EdvCodec.js +221 -52
  23. package/dist/edv/EdvCodec.js.map +1 -1
  24. package/dist/edv/WasTransport.d.ts +1 -53
  25. package/dist/edv/WasTransport.d.ts.map +1 -1
  26. package/dist/edv/WasTransport.js +29 -29
  27. package/dist/edv/WasTransport.js.map +1 -1
  28. package/dist/edv/docCipher.d.ts +111 -0
  29. package/dist/edv/docCipher.d.ts.map +1 -0
  30. package/dist/edv/docCipher.js +236 -0
  31. package/dist/edv/docCipher.js.map +1 -0
  32. package/dist/edv/epochKeys.d.ts.map +1 -1
  33. package/dist/edv/epochKeys.js +46 -16
  34. package/dist/edv/epochKeys.js.map +1 -1
  35. package/dist/edv/epochMac.d.ts +32 -0
  36. package/dist/edv/epochMac.d.ts.map +1 -0
  37. package/dist/edv/epochMac.js +117 -0
  38. package/dist/edv/epochMac.js.map +1 -0
  39. package/dist/edv/index.d.ts +2 -0
  40. package/dist/edv/index.d.ts.map +1 -1
  41. package/dist/edv/index.js +1 -0
  42. package/dist/edv/index.js.map +1 -1
  43. package/dist/edv/recipients.d.ts.map +1 -1
  44. package/dist/edv/recipients.js +26 -3
  45. package/dist/edv/recipients.js.map +1 -1
  46. package/dist/errors.d.ts +22 -0
  47. package/dist/errors.d.ts.map +1 -1
  48. package/dist/errors.js +28 -0
  49. package/dist/errors.js.map +1 -1
  50. package/dist/index.d.ts +1 -1
  51. package/dist/index.d.ts.map +1 -1
  52. package/dist/index.js +1 -1
  53. package/dist/index.js.map +1 -1
  54. package/dist/internal/codec.d.ts +1 -2
  55. package/dist/internal/codec.d.ts.map +1 -1
  56. package/dist/internal/codec.js +10 -10
  57. package/dist/internal/codec.js.map +1 -1
  58. package/dist/internal/features.d.ts +1 -12
  59. package/dist/internal/features.d.ts.map +1 -1
  60. package/dist/internal/features.js +8 -8
  61. package/dist/internal/features.js.map +1 -1
  62. package/dist/internal/pagination.d.ts +1 -1
  63. package/dist/internal/pagination.js +1 -1
  64. package/dist/sync/cid.d.ts +31 -0
  65. package/dist/sync/cid.d.ts.map +1 -0
  66. package/dist/sync/cid.js +55 -0
  67. package/dist/sync/cid.js.map +1 -0
  68. package/dist/sync/envelope.d.ts +20 -0
  69. package/dist/sync/envelope.d.ts.map +1 -0
  70. package/dist/sync/envelope.js +17 -0
  71. package/dist/sync/envelope.js.map +1 -0
  72. package/dist/sync/index.d.ts +29 -0
  73. package/dist/sync/index.d.ts.map +1 -0
  74. package/dist/sync/index.js +28 -0
  75. package/dist/sync/index.js.map +1 -0
  76. package/dist/sync/plaintextCipher.d.ts +16 -0
  77. package/dist/sync/plaintextCipher.d.ts.map +1 -0
  78. package/dist/sync/plaintextCipher.js +36 -0
  79. package/dist/sync/plaintextCipher.js.map +1 -0
  80. package/dist/sync/port.d.ts +78 -0
  81. package/dist/sync/port.d.ts.map +1 -0
  82. package/dist/sync/port.js +204 -0
  83. package/dist/sync/port.js.map +1 -0
  84. package/dist/sync/provisioning.d.ts +41 -0
  85. package/dist/sync/provisioning.d.ts.map +1 -0
  86. package/dist/sync/provisioning.js +44 -0
  87. package/dist/sync/provisioning.js.map +1 -0
  88. package/dist/sync/types.d.ts +166 -0
  89. package/dist/sync/types.d.ts.map +1 -0
  90. package/dist/sync/types.js +2 -0
  91. package/dist/sync/types.js.map +1 -0
  92. package/dist/types.d.ts +2 -2
  93. package/dist/types.d.ts.map +1 -1
  94. package/package.json +13 -5
@@ -0,0 +1,236 @@
1
+ import { KeyUnwrapError } from '../errors.js';
2
+ import { createEdvEncryption } from './EdvCodec.js';
3
+ import { epochKeyIdFor } from './epochCrypto.js';
4
+ // `isEncryptedEnvelope` and the `DocCipher` interface live in the crypto-free
5
+ // `../sync` module; re-exported here so an encrypted-collection consumer that
6
+ // imports this subpath gets both without a second import.
7
+ export { isEncryptedEnvelope } from '../sync/envelope.js';
8
+ /**
9
+ * Thrown by a {@link DocCipher.decrypt} when a stored envelope names a JWE
10
+ * recipient (`kid`) this cipher cannot route: neither the key-agreement key nor
11
+ * -- on an epoch-aware cipher -- any epoch this cipher knows about. It signals
12
+ * that the caller's cached Collection Description may be stale and should be
13
+ * re-read before retrying: an epoch rotation emits no change-feed entry, so a
14
+ * cipher built from a pre-rotation marker meets envelopes stamped with a newer
15
+ * epoch it has never seen. It also fires on a single-key cipher that meets an
16
+ * envelope encrypted to a different key-agreement key entirely.
17
+ */
18
+ export class UnknownEpochError extends Error {
19
+ constructor({ collectionId, kids }) {
20
+ super(`Cannot decrypt a resource in collection "${collectionId}": its ` +
21
+ `envelope names recipient key id(s) [${kids.join(', ')}] that match ` +
22
+ 'neither the key-agreement key nor any known key epoch. The cached ' +
23
+ 'Collection Description may be stale (an epoch rotation emits no ' +
24
+ 'change-feed entry); re-read it and rebuild the cipher.');
25
+ this.name = 'UnknownEpochError';
26
+ }
27
+ }
28
+ /**
29
+ * A wallet's own key-agreement key as a `RecipientPublicKey` -- the "recipient
30
+ * zero" entry a caller passes to `initRecipients` when it first makes a
31
+ * collection multi-recipient (the owner must be a recipient of every epoch, or it
32
+ * could write envelopes it cannot itself read). An `X25519KeyAgreementKey2020`
33
+ * carries a did:key-shaped `id` and a `publicKeyMultibase`, so its `kid`'s
34
+ * fragment resolves through the default did:key recipient resolver.
35
+ *
36
+ * @param options {object}
37
+ * @param options.keyAgreementKey {IKeyAgreementKey}
38
+ * @returns {RecipientPublicKey}
39
+ */
40
+ export function ownerRecipient({ keyAgreementKey }) {
41
+ const { id } = keyAgreementKey;
42
+ const { publicKeyMultibase, type } = keyAgreementKey;
43
+ if (typeof id !== 'string' || typeof publicKeyMultibase !== 'string') {
44
+ throw new Error('Cannot build an owner recipient: the key-agreement key lacks an id or ' +
45
+ 'publicKeyMultibase (a public X25519 key is required to wrap an epoch ' +
46
+ 'key to it).');
47
+ }
48
+ return { id, publicKeyMultibase, type };
49
+ }
50
+ /**
51
+ * Extracts the JWE recipient key ids (`kid`) an EDV envelope names. An epoch
52
+ * envelope carries one kid (the epoch key id); a single-recipient envelope
53
+ * carries the key-agreement key id. Returns `[]` for a malformed envelope, so
54
+ * routing falls through to letting a codec surface its own error.
55
+ */
56
+ function envelopeRecipientKids(envelope) {
57
+ if (envelope === null || typeof envelope !== 'object') {
58
+ return [];
59
+ }
60
+ const jwe = envelope.jwe;
61
+ if (jwe === null || typeof jwe !== 'object') {
62
+ return [];
63
+ }
64
+ const recipients = jwe.recipients;
65
+ if (!Array.isArray(recipients)) {
66
+ return [];
67
+ }
68
+ const kids = [];
69
+ for (const recipient of recipients) {
70
+ const kid = recipient?.header?.kid;
71
+ if (typeof kid === 'string') {
72
+ kids.push(kid);
73
+ }
74
+ }
75
+ return kids;
76
+ }
77
+ /**
78
+ * Builds a {@link DocCipher} for one encrypted collection from a reader's key
79
+ * material (the key-agreement key + resolver). Keys are supplied directly (no
80
+ * keystore lookup).
81
+ *
82
+ * `idDerivation` selects the id model: `'content'` (default) makes every id a
83
+ * hash of the JWE ciphertext -- the stable, replica-independent primary key an
84
+ * immutable content-addressed collection needs; `'random'` mints a stable random
85
+ * id updated in place via `sequence` (the mutable head-document model, driven by
86
+ * `encryptUpdate`).
87
+ *
88
+ * With no `encryption` marker (or a marker with no epochs) the cipher is single-
89
+ * recipient: the key-agreement key encrypts and decrypts directly. With epochs on
90
+ * the marker the cipher becomes multi-recipient: it ALSO builds an epoch codec
91
+ * that encrypts every write under the marker's `currentEpoch` and decrypts any
92
+ * epoch this reader still holds a key for. The single-key codec stays built
93
+ * either way, so a pre-epoch envelope keeps decrypting -- a permanent tolerance,
94
+ * not a migration shim.
95
+ *
96
+ * The reader must be a recipient of every epoch on the marker (the owner is
97
+ * "recipient zero"). If it is a recipient of none, building the epoch codec
98
+ * throws {@link KeyUnwrapError}; this surfaces it with a clearer error rather
99
+ * than silently writing envelopes other recipients cannot read.
100
+ *
101
+ * @param options {object}
102
+ * @param options.keyAgreementKey {IKeyAgreementKey}
103
+ * @param options.keyResolver {IKeyResolver}
104
+ * @param options.collectionId {string} labels errors; the codec is agnostic
105
+ * @param [options.idDerivation] {'content' | 'random'} defaults to `'content'`
106
+ * @param [options.encryption] {CollectionEncryption} the collection's
107
+ * encryption marker; when it carries key epochs, the cipher becomes
108
+ * multi-recipient
109
+ * @returns {Promise<DocCipher>}
110
+ */
111
+ export async function createEdvDocCipher({ keyAgreementKey, keyResolver, collectionId, idDerivation = 'content', encryption }) {
112
+ const provider = createEdvEncryption({
113
+ resolveKeys: async () => null,
114
+ idDerivation
115
+ });
116
+ // The direct (single-key) codec is always built: it decrypts pre-epoch
117
+ // envelopes and is the whole cipher for a single-recipient collection.
118
+ const directCodec = await provider.codecFor({
119
+ spaceId: 'local',
120
+ collectionId,
121
+ scheme: 'edv',
122
+ keys: { keyAgreementKey, keyResolver }
123
+ });
124
+ if (!directCodec) {
125
+ throw new Error(`Could not build the EDV cipher for collection "${collectionId}".`);
126
+ }
127
+ // On a multi-recipient collection, ALSO build the epoch codec: same provider
128
+ // and keys, but with the marker so `codecFor` resolves this reader's per-epoch
129
+ // keys. Writes go under the marker's `currentEpoch`; reads pick the epoch key
130
+ // matching the envelope's recipient kid.
131
+ const hasEpochs = encryption?.epochs !== undefined && encryption.epochs.length > 0;
132
+ let epochCodec;
133
+ if (hasEpochs) {
134
+ try {
135
+ epochCodec = await provider.codecFor({
136
+ spaceId: 'local',
137
+ collectionId,
138
+ scheme: 'edv',
139
+ encryption,
140
+ keys: { keyAgreementKey, keyResolver }
141
+ });
142
+ }
143
+ catch (err) {
144
+ if (err instanceof KeyUnwrapError) {
145
+ throw new Error(`Cannot build the multi-recipient EDV cipher for collection ` +
146
+ `"${collectionId}": the key-agreement key is not a recipient of any ` +
147
+ 'key epoch on this collection. The owner must be a recipient of ' +
148
+ 'every epoch (recipient zero) before writing, or it would encrypt ' +
149
+ 'envelopes it cannot itself read.', { cause: err });
150
+ }
151
+ throw err;
152
+ }
153
+ if (!epochCodec) {
154
+ throw new Error(`Could not build the multi-recipient EDV cipher for collection ` +
155
+ `"${collectionId}".`);
156
+ }
157
+ }
158
+ const vaultKid = keyAgreementKey.id;
159
+ const knownEpochKids = new Set((encryption?.epochs ?? []).map(epoch => epochKeyIdFor(epoch.id)));
160
+ // Parses the codec's `EncodedWrite` (id + envelope body bytes) to the stored
161
+ // `{ id, envelope, epoch? }` shape. Shared by the create and update paths.
162
+ const readEncoded = (encoded) => {
163
+ if (typeof encoded.id !== 'string' ||
164
+ !(encoded.body instanceof Uint8Array)) {
165
+ throw new Error(`EDV encrypt for collection "${collectionId}" returned no id/envelope body.`);
166
+ }
167
+ const envelope = JSON.parse(new TextDecoder().decode(encoded.body));
168
+ return {
169
+ id: encoded.id,
170
+ envelope,
171
+ ...(typeof encoded.epoch === 'string' && { epoch: encoded.epoch })
172
+ };
173
+ };
174
+ return {
175
+ async encrypt({ data }) {
176
+ // `encode` with no caller id is the add() path: encrypt, then either derive
177
+ // and stamp the content-hash id (`'content'`) or use the minted random id.
178
+ // Writes go under the current epoch on a multi-recipient cipher.
179
+ const codec = epochCodec ?? directCodec;
180
+ const encoded = await codec.encode({
181
+ data: data
182
+ });
183
+ return readEncoded(encoded);
184
+ },
185
+ async encryptUpdate({ id, data, current }) {
186
+ // The update path (mutable random-id head document): hand the codec the
187
+ // prior stored envelope so it advances `sequence` from it and re-encrypts
188
+ // under the same id.
189
+ const codec = epochCodec ?? directCodec;
190
+ const priorResponse = {
191
+ data: current,
192
+ json: async () => current,
193
+ headers: { get: () => null }
194
+ };
195
+ const encoded = await codec.encode({
196
+ id,
197
+ data: data,
198
+ current: priorResponse
199
+ });
200
+ const { id: encodedId, envelope } = readEncoded(encoded);
201
+ return { id: encodedId, envelope };
202
+ },
203
+ async decrypt({ envelope }) {
204
+ // Route by the envelope's JWE recipient kids:
205
+ // 1. any kid is the key-agreement key id -- a pre-epoch envelope, so the
206
+ // direct codec (permanent tolerance, not a migration shim);
207
+ // 2. else, on an epoch cipher, any kid names a known epoch -- the epoch
208
+ // codec;
209
+ // 3. else UnknownEpochError: the marker is likely stale, or a single-key
210
+ // cipher met an envelope encrypted to a different key entirely.
211
+ const kids = envelopeRecipientKids(envelope);
212
+ const codec = selectCodec();
213
+ const response = {
214
+ data: envelope,
215
+ json: async () => envelope
216
+ };
217
+ return (await codec.decode(response));
218
+ function selectCodec() {
219
+ if (kids.some(kid => kid === vaultKid)) {
220
+ return directCodec;
221
+ }
222
+ if (epochCodec && kids.some(kid => knownEpochKids.has(kid))) {
223
+ return epochCodec;
224
+ }
225
+ // A malformed/empty-kid envelope falls through to the direct codec so it
226
+ // can surface its own decrypt error; a non-empty set of unroutable kids
227
+ // is the stale-marker signal.
228
+ if (kids.length === 0) {
229
+ return directCodec;
230
+ }
231
+ throw new UnknownEpochError({ collectionId, kids });
232
+ }
233
+ }
234
+ };
235
+ }
236
+ //# sourceMappingURL=docCipher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"docCipher.js","sourceRoot":"","sources":["../../src/edv/docCipher.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"epochKeys.d.ts","sourceRoot":"","sources":["../../src/edv/epochKeys.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAA;AAEpE,OAAO,KAAK,EACV,oBAAoB,EAErB,MAAM,aAAa,CAAA;AAOpB;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC;;OAEG;IACH,UAAU,EAAE,MAAM,CAAA;IAClB;;OAEG;IACH,QAAQ,EAAE,gBAAgB,CAAA;IAC1B;;;;OAIG;IACH,QAAQ,EAAE,gBAAgB,EAAE,CAAA;CAC7B;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,gBAAgB,CAAC,EACrC,UAAU,EACV,eAAe,EAChB,EAAE;IACD,UAAU,EAAE,oBAAoB,CAAA;IAChC,eAAe,EAAE,gBAAgB,CAAA;CAClC,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CA+DpC"}
1
+ {"version":3,"file":"epochKeys.d.ts","sourceRoot":"","sources":["../../src/edv/epochKeys.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAA;AAEpE,OAAO,KAAK,EACV,oBAAoB,EAErB,MAAM,aAAa,CAAA;AAQpB;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC;;OAEG;IACH,UAAU,EAAE,MAAM,CAAA;IAClB;;OAEG;IACH,QAAQ,EAAE,gBAAgB,CAAA;IAC1B;;;;OAIG;IACH,QAAQ,EAAE,gBAAgB,EAAE,CAAA;CAC7B;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,gBAAgB,CAAC,EACrC,UAAU,EACV,eAAe,EAChB,EAAE;IACD,UAAU,EAAE,oBAAoB,CAAA;IAChC,eAAe,EAAE,gBAAgB,CAAA;CAClC,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CA+FpC"}
@@ -1,5 +1,6 @@
1
- import { KeyUnwrapError } from '../errors.js';
1
+ import { IntegrityError, KeyUnwrapError } from '../errors.js';
2
2
  import { epochKeyIdFor, reconstructEpochKeyPair, unwrapEpochSecret } from './epochCrypto.js';
3
+ import { verifyEpochsMac } from './epochMac.js';
3
4
  /**
4
5
  * Resolves the reader's epoch keys from a marker. Returns `null` when the marker
5
6
  * declares no epochs (a single-key collection -- the caller keeps its existing
@@ -33,7 +34,7 @@ export async function resolveEpochKeys({ encryption, keyAgreementKey }) {
33
34
  // the newest epoch it holds -- defined deterministically as the LAST epoch in
34
35
  // the marker's canonical `epochs` order that names this reader, never the
35
36
  // incidental order in which secrets happened to unwrap. A reader that is not a
36
- // recipient of `currentEpoch` is a removed/historical reader whose writes the
37
+ // recipient of `currentEpoch` is a removed/archive reader whose writes the
37
38
  // server rejects via its revoked zcap anyway; selecting a deterministic
38
39
  // fallback here only keeps the local `writeEpoch`/`writeKey` well-defined
39
40
  // instead of assuming the `epochs` array is append-ordered newest-last.
@@ -42,23 +43,49 @@ export async function resolveEpochKeys({ encryption, keyAgreementKey }) {
42
43
  namedEpochs.find(epoch => epoch.id === currentEpoch)) ||
43
44
  namedEpochs[namedEpochs.length - 1];
44
45
  // The write epoch is unwrapped eagerly: `writeKey` must be a full key pair the
45
- // EDV cipher can name recipients with and encrypt under right away.
46
- const writeKey = await unwrapEpochKey({
46
+ // EDV cipher can name recipients with and encrypt under right away. Its raw
47
+ // secret is surfaced alongside so the epoch-configuration MAC can be verified.
48
+ const writeUnwrapped = await unwrapEpochKey({
47
49
  epoch: writeEpochEntry,
48
50
  keyAgreementKey
49
51
  });
50
- if (!writeKey) {
52
+ if (!writeUnwrapped) {
51
53
  throw new KeyUnwrapError(`This reader's recipient entry for the write epoch ` +
52
54
  `"${writeEpochEntry.id}" did not unwrap (a corrupt entry). Re-add ` +
53
55
  'this reader with addRecipient, or supply the correct key-agreement ' +
54
56
  'key.');
55
57
  }
58
+ const writeKey = writeUnwrapped.key;
59
+ // Authenticate the epoch configuration when this reader holds the marker's
60
+ // `currentEpoch` (its write epoch IS `currentEpoch`) and the marker carries a
61
+ // MAC. A reader whose write epoch is an older held epoch cannot key the MAC
62
+ // (its secret is not the current epoch's), so it skips verification -- its
63
+ // writes are rejected server-side via its revoked zcap anyway. An absent MAC
64
+ // is a legacy marker, accepted.
65
+ if (writeEpochEntry.id === encryption.currentEpoch &&
66
+ encryption.epochsMac !== undefined) {
67
+ const { v, alg } = encryption.epochsMac;
68
+ if (v !== 1 || alg !== 'HS256') {
69
+ throw new IntegrityError('The epoch configuration failed to authenticate: its MAC declares an ' +
70
+ `unsupported construction (v=${v}, alg="${alg}"). This is a ` +
71
+ 'server-side rollback or tamper.');
72
+ }
73
+ const authentic = await verifyEpochsMac({
74
+ marker: encryption,
75
+ epochSecret: writeUnwrapped.secret
76
+ });
77
+ if (!authentic) {
78
+ throw new IntegrityError('The epoch configuration failed to authenticate; a server-side ' +
79
+ 'rollback or tamper of the encryption marker was detected (the ' +
80
+ 'MAC over its epoch configuration does not verify).');
81
+ }
82
+ }
56
83
  // Read keys: the eagerly-unwrapped write key, plus a LAZY key per other named
57
84
  // epoch. Each lazy key knows its `id` up front (derived from the epoch id, so
58
85
  // the codec's kid-match filter needs no secret) and unwraps + reconstructs its
59
86
  // epoch secret only on first decrypt naming it, caching the result. So a
60
87
  // write-only handle -- or a reader that only ever touches current-epoch
61
- // resources -- never pays the ECDH + KDF + key-unwrap for historical epochs it
88
+ // resources -- never pays the ECDH + KDF + key-unwrap for archive epochs it
62
89
  // does not read.
63
90
  const readKeys = [writeKey];
64
91
  for (const epoch of namedEpochs) {
@@ -71,12 +98,15 @@ export async function resolveEpochKeys({ encryption, keyAgreementKey }) {
71
98
  /**
72
99
  * Unwraps and reconstructs a single epoch's key pair for this reader, or returns
73
100
  * `null` when the reader is not a recipient of the epoch or its entry does not
74
- * unwrap (a corrupt entry -- never treat `null` as a key).
101
+ * unwrap (a corrupt entry -- never treat `null` as a key). Returns the raw
102
+ * 32-byte epoch secret alongside the reconstructed key pair, so a caller that
103
+ * must authenticate the epoch configuration (the `epochsMac`) can key the MAC
104
+ * without re-unwrapping.
75
105
  *
76
106
  * @param options {object}
77
107
  * @param options.epoch {CollectionEncryptionEpoch} the epoch to unwrap
78
108
  * @param options.keyAgreementKey {IKeyAgreementKey} the reader's own KAK
79
- * @returns {Promise<IKeyAgreementKey | null>}
109
+ * @returns {Promise<{ key: IKeyAgreementKey; secret: Uint8Array } | null>}
80
110
  */
81
111
  async function unwrapEpochKey({ epoch, keyAgreementKey }) {
82
112
  const entry = epoch.recipients.find(recipient => recipient.header.kid === keyAgreementKey.id);
@@ -87,7 +117,7 @@ async function unwrapEpochKey({ epoch, keyAgreementKey }) {
87
117
  if (!secret) {
88
118
  return null;
89
119
  }
90
- return reconstructEpochKeyPair({ epochId: epoch.id, secret });
120
+ return { key: reconstructEpochKeyPair({ epochId: epoch.id, secret }), secret };
91
121
  }
92
122
  /**
93
123
  * Builds a lazily-unwrapping read key for a named epoch: an `IKeyAgreementKey`
@@ -107,16 +137,16 @@ function lazyEpochKey({ epoch, keyAgreementKey }) {
107
137
  let pending;
108
138
  const resolve = () => {
109
139
  if (pending === undefined) {
110
- const promise = unwrapEpochKey({ epoch, keyAgreementKey }).then(key => {
111
- if (!key) {
112
- // The reader was named in this epoch (else no lazy key was built) but
113
- // its entry did not unwrap: a corrupt entry. The codec's `_decrypt`
114
- // catches this and tries the next candidate before surfacing its own
115
- // typed failure.
140
+ const promise = unwrapEpochKey({ epoch, keyAgreementKey }).then(unwrapped => {
141
+ if (!unwrapped) {
142
+ // The reader was named in this epoch (else no lazy key was built)
143
+ // but its entry did not unwrap: a corrupt entry. The codec's
144
+ // `_decrypt` catches this and tries the next candidate before
145
+ // surfacing its own typed failure.
116
146
  throw new KeyUnwrapError(`This reader's recipient entry for epoch "${epoch.id}" did not ` +
117
147
  'unwrap (a corrupt entry).');
118
148
  }
119
- return key;
149
+ return unwrapped.key;
120
150
  });
121
151
  // Cache only a successful unwrap: drop a rejected promise so the next
122
152
  // read re-attempts (the failure may have been transient), rather than
@@ -1 +1 @@
1
- {"version":3,"file":"epochKeys.js","sourceRoot":"","sources":["../../src/edv/epochKeys.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"epochKeys.js","sourceRoot":"","sources":["../../src/edv/epochKeys.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import type { CollectionEncryption, CollectionEncryptionEpochsMac } from '../types.js';
2
+ /**
3
+ * Computes the `epochsMac` field for a marker under the current epoch's secret.
4
+ * Compute this over the exact marker state being written (member fields already
5
+ * stamped), since a compare-and-swap retry re-reads the marker.
6
+ *
7
+ * @param options {object}
8
+ * @param options.marker {CollectionEncryption} the marker being written
9
+ * @param options.epochSecret {Uint8Array} the 32-byte current epoch secret
10
+ * @returns {Promise<CollectionEncryptionEpochsMac>}
11
+ */
12
+ export declare function computeEpochsMac({ marker, epochSecret }: {
13
+ marker: CollectionEncryption;
14
+ epochSecret: Uint8Array;
15
+ }): Promise<CollectionEncryptionEpochsMac>;
16
+ /**
17
+ * Verifies a marker's `epochsMac` against a recomputation from the current
18
+ * epoch's secret. Returns `false` on any mismatch (or a malformed `mac`); the
19
+ * caller decides the error semantics. The MAC construction's own version/alg
20
+ * (`v` / `alg`) is validated by the caller before this is called.
21
+ *
22
+ * @param options {object}
23
+ * @param options.marker {CollectionEncryption} the marker to verify (its
24
+ * `epochsMac.mac` is the tag under test)
25
+ * @param options.epochSecret {Uint8Array} the 32-byte current epoch secret
26
+ * @returns {Promise<boolean>}
27
+ */
28
+ export declare function verifyEpochsMac({ marker, epochSecret }: {
29
+ marker: CollectionEncryption;
30
+ epochSecret: Uint8Array;
31
+ }): Promise<boolean>;
32
+ //# sourceMappingURL=epochMac.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"epochMac.d.ts","sourceRoot":"","sources":["../../src/edv/epochMac.ts"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EACV,oBAAoB,EACpB,6BAA6B,EAC9B,MAAM,aAAa,CAAA;AAwEpB;;;;;;;;;GASG;AACH,wBAAsB,gBAAgB,CAAC,EACrC,MAAM,EACN,WAAW,EACZ,EAAE;IACD,MAAM,EAAE,oBAAoB,CAAA;IAC5B,WAAW,EAAE,UAAU,CAAA;CACxB,GAAG,OAAO,CAAC,6BAA6B,CAAC,CAQzC;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,eAAe,CAAC,EACpC,MAAM,EACN,WAAW,EACZ,EAAE;IACD,MAAM,EAAE,oBAAoB,CAAA;IAC5B,WAAW,EAAE,UAAU,CAAA;CACxB,GAAG,OAAO,CAAC,OAAO,CAAC,CAkBnB"}
@@ -0,0 +1,117 @@
1
+ /*!
2
+ * Copyright (c) 2026 Interop Alliance. All rights reserved.
3
+ */
4
+ /**
5
+ * Authenticated epoch configuration for multi-recipient encrypted Collections:
6
+ * a MAC over a Collection `encryption` marker's epoch configuration, keyed from
7
+ * the current epoch's secret (which the server never holds). It lets a reader
8
+ * detect a server-side rollback of `currentEpoch` or a fabricated epoch list --
9
+ * a malicious server cannot forge a valid MAC without the epoch secret.
10
+ *
11
+ * The MAC covers only `scheme`, `version`, `currentEpoch`, and the ordered list
12
+ * of epoch ids -- deliberately NOT the recipient entries, so adding a recipient
13
+ * (which cannot be forged without the epoch secret anyway) does not invalidate
14
+ * the MAC. Covering `version` makes stripping the marker's scheme version
15
+ * MAC-detectable.
16
+ *
17
+ * Documented limitation (mirrors Cryptomator's versionMac): a server can still
18
+ * replay an ENTIRE prior consistent configuration (an old epoch list with its
19
+ * matching old MAC). Detecting that needs client-side monotonic state, which is
20
+ * out of scope here.
21
+ */
22
+ import { base64urlnopad } from '@scure/base';
23
+ const TEXT_ENCODER = new TextEncoder();
24
+ /**
25
+ * The HKDF `info` string binding the derived key to this MAC construction.
26
+ */
27
+ const MAC_KEY_INFO = TEXT_ENCODER.encode('was-epoch-config-mac/v1');
28
+ /**
29
+ * The domain-separation prefix prepended to the JSON payload before it is MACed.
30
+ */
31
+ const MAC_PAYLOAD_PREFIX = 'was-epoch-config/v1.';
32
+ /**
33
+ * Derives the HMAC-SHA256 key from a 32-byte epoch secret:
34
+ * HKDF-SHA256(ikm = the epoch secret, salt = empty, info =
35
+ * "was-epoch-config-mac/v1", length 32 bytes). Uses WebCrypto (`crypto.subtle`)
36
+ * so it works unchanged in Node 24 and browsers.
37
+ *
38
+ * @param epochSecret {Uint8Array} the 32-byte current epoch secret
39
+ * @returns {Promise<CryptoKey>} the derived HMAC key (sign + verify)
40
+ */
41
+ async function deriveMacKey(epochSecret) {
42
+ const ikm = await crypto.subtle.importKey('raw', epochSecret, 'HKDF', false, ['deriveKey']);
43
+ return crypto.subtle.deriveKey({
44
+ name: 'HKDF',
45
+ hash: 'SHA-256',
46
+ salt: new Uint8Array(0),
47
+ info: MAC_KEY_INFO
48
+ }, ikm, { name: 'HMAC', hash: 'SHA-256', length: 256 }, false, ['sign', 'verify']);
49
+ }
50
+ /**
51
+ * Builds the MACed payload bytes for a marker's epoch configuration:
52
+ * `UTF8("was-epoch-config/v1." + JSON.stringify({ scheme, version,
53
+ * currentEpoch, epochs }))`, with `version` normalized to `null` when absent
54
+ * and `epochs` the ordered list of epoch id strings. The object member order is
55
+ * fixed so both sides serialize identically.
56
+ *
57
+ * @param marker {CollectionEncryption} the marker whose epoch configuration is
58
+ * being authenticated
59
+ * @returns {Uint8Array}
60
+ */
61
+ function macPayload(marker) {
62
+ const payload = {
63
+ scheme: marker.scheme,
64
+ version: marker.version ?? null,
65
+ currentEpoch: marker.currentEpoch,
66
+ epochs: (marker.epochs ?? []).map(epoch => epoch.id)
67
+ };
68
+ const bytes = TEXT_ENCODER.encode(MAC_PAYLOAD_PREFIX + JSON.stringify(payload));
69
+ return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
70
+ }
71
+ /**
72
+ * Computes the `epochsMac` field for a marker under the current epoch's secret.
73
+ * Compute this over the exact marker state being written (member fields already
74
+ * stamped), since a compare-and-swap retry re-reads the marker.
75
+ *
76
+ * @param options {object}
77
+ * @param options.marker {CollectionEncryption} the marker being written
78
+ * @param options.epochSecret {Uint8Array} the 32-byte current epoch secret
79
+ * @returns {Promise<CollectionEncryptionEpochsMac>}
80
+ */
81
+ export async function computeEpochsMac({ marker, epochSecret }) {
82
+ const key = await deriveMacKey(epochSecret);
83
+ const signature = await crypto.subtle.sign('HMAC', key, macPayload(marker));
84
+ return {
85
+ v: 1,
86
+ alg: 'HS256',
87
+ mac: base64urlnopad.encode(new Uint8Array(signature))
88
+ };
89
+ }
90
+ /**
91
+ * Verifies a marker's `epochsMac` against a recomputation from the current
92
+ * epoch's secret. Returns `false` on any mismatch (or a malformed `mac`); the
93
+ * caller decides the error semantics. The MAC construction's own version/alg
94
+ * (`v` / `alg`) is validated by the caller before this is called.
95
+ *
96
+ * @param options {object}
97
+ * @param options.marker {CollectionEncryption} the marker to verify (its
98
+ * `epochsMac.mac` is the tag under test)
99
+ * @param options.epochSecret {Uint8Array} the 32-byte current epoch secret
100
+ * @returns {Promise<boolean>}
101
+ */
102
+ export async function verifyEpochsMac({ marker, epochSecret }) {
103
+ const epochsMac = marker.epochsMac;
104
+ if (!epochsMac) {
105
+ return false;
106
+ }
107
+ let mac;
108
+ try {
109
+ mac = base64urlnopad.decode(epochsMac.mac);
110
+ }
111
+ catch {
112
+ return false;
113
+ }
114
+ const key = await deriveMacKey(epochSecret);
115
+ return crypto.subtle.verify('HMAC', key, mac, macPayload(marker));
116
+ }
117
+ //# sourceMappingURL=epochMac.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"epochMac.js","sourceRoot":"","sources":["../../src/edv/epochMac.ts"],"names":[],"mappings":"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"}
@@ -27,4 +27,6 @@ export { WasTransport, JOSE_CONTENT_TYPE } from './WasTransport.js';
27
27
  export { initRecipients, addRecipient, removeRecipient } from './recipients.js';
28
28
  export type { OwnerKey, RecipientPublicKey } from './recipients.js';
29
29
  export { mintEpoch, epochKeyIdFor } from './epochCrypto.js';
30
+ export { createEdvDocCipher, ownerRecipient, UnknownEpochError, isEncryptedEnvelope } from './docCipher.js';
31
+ export type { DocCipher } from './docCipher.js';
30
32
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/edv/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAC7D,YAAY,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AAC5C,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AACnE,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAC/E,YAAY,EAAE,QAAQ,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AACnE,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/edv/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAC7D,YAAY,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AAC5C,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AACnE,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAC/E,YAAY,EAAE,QAAQ,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AACnE,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAC3D,OAAO,EACL,kBAAkB,EAClB,cAAc,EACd,iBAAiB,EACjB,mBAAmB,EACpB,MAAM,gBAAgB,CAAA;AACvB,YAAY,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA"}
package/dist/edv/index.js CHANGED
@@ -25,4 +25,5 @@ export { createEdvEncryption, EdvCodec } from './EdvCodec.js';
25
25
  export { WasTransport, JOSE_CONTENT_TYPE } from './WasTransport.js';
26
26
  export { initRecipients, addRecipient, removeRecipient } from './recipients.js';
27
27
  export { mintEpoch, epochKeyIdFor } from './epochCrypto.js';
28
+ export { createEdvDocCipher, ownerRecipient, UnknownEpochError, isEncryptedEnvelope } from './docCipher.js';
28
29
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/edv/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAE7D,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AACnE,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAE/E,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/edv/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAE7D,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AACnE,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAE/E,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAC3D,OAAO,EACL,kBAAkB,EAClB,cAAc,EACd,iBAAiB,EACjB,mBAAmB,EACpB,MAAM,gBAAgB,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"recipients.d.ts","sourceRoot":"","sources":["../../src/edv/recipients.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAA;AACpE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAClD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AAGxC,OAAO,KAAK,EACV,oBAAoB,EAEpB,cAAc,EACf,MAAM,aAAa,CAAA;AAOpB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AAE1D,YAAY,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AAE1D;;;GAGG;AACH,MAAM,WAAW,QAAQ;IACvB,eAAe,EAAE,gBAAgB,CAAA;CAClC;AAQD;;;;;;;;;;;;GAYG;AACH,wBAAsB,cAAc,CAAC,EACnC,UAAU,EACV,UAAU,EACX,EAAE;IACD,UAAU,EAAE,UAAU,CAAA;IACtB,UAAU,EAAE,kBAAkB,EAAE,CAAA;CACjC,GAAG,OAAO,CAAC,oBAAoB,CAAC,CA2BhC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,YAAY,CAAC,EACjC,UAAU,EACV,SAAS,EACT,KAAK,EACN,EAAE;IACD,UAAU,EAAE,UAAU,CAAA;IACtB,SAAS,EAAE,kBAAkB,CAAA;IAC7B,KAAK,EAAE,QAAQ,CAAA;CAChB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAuDhC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,wBAAsB,eAAe,CAAC,EACpC,UAAU,EACV,KAAK,EACL,WAAW,EACX,MAAM,EACN,mBAAgD,EACjD,EAAE;IACD,UAAU,EAAE,UAAU,CAAA;IACtB,KAAK,EAAE,KAAK,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,MAAM,EAAE,cAAc,GAAG,cAAc,EAAE,CAAA;IACzC,mBAAmB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,kBAAkB,CAAC,CAAA;CACnE,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAuFhC"}
1
+ {"version":3,"file":"recipients.d.ts","sourceRoot":"","sources":["../../src/edv/recipients.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAA;AACpE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAClD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AAGxC,OAAO,KAAK,EACV,oBAAoB,EAEpB,cAAc,EACf,MAAM,aAAa,CAAA;AAQpB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AAE1D,YAAY,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AAE1D;;;GAGG;AACH,MAAM,WAAW,QAAQ;IACvB,eAAe,EAAE,gBAAgB,CAAA;CAClC;AAQD;;;;;;;;;;;;GAYG;AACH,wBAAsB,cAAc,CAAC,EACnC,UAAU,EACV,UAAU,EACX,EAAE;IACD,UAAU,EAAE,UAAU,CAAA;IACtB,UAAU,EAAE,kBAAkB,EAAE,CAAA;CACjC,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAyChC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,YAAY,CAAC,EACjC,UAAU,EACV,SAAS,EACT,KAAK,EACN,EAAE;IACD,UAAU,EAAE,UAAU,CAAA;IACtB,SAAS,EAAE,kBAAkB,CAAA;IAC7B,KAAK,EAAE,QAAQ,CAAA;CAChB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAuDhC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,wBAAsB,eAAe,CAAC,EACpC,UAAU,EACV,KAAK,EACL,WAAW,EACX,MAAM,EACN,mBAAgD,EACjD,EAAE;IACD,UAAU,EAAE,UAAU,CAAA;IACtB,KAAK,EAAE,KAAK,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,MAAM,EAAE,cAAc,GAAG,cAAc,EAAE,CAAA;IACzC,mBAAmB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,kBAAkB,CAAC,CAAA;CACnE,GAAG,OAAO,CAAC,oBAAoB,CAAC,CA+FhC"}