@interop/was-client 0.9.2 → 0.10.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/README.md +27 -1
- package/dist/Collection.d.ts +49 -10
- package/dist/Collection.d.ts.map +1 -1
- package/dist/Collection.js +161 -61
- package/dist/Collection.js.map +1 -1
- package/dist/Resource.d.ts +13 -5
- package/dist/Resource.d.ts.map +1 -1
- package/dist/Resource.js +50 -38
- package/dist/Resource.js.map +1 -1
- package/dist/Space.d.ts +1 -0
- package/dist/Space.d.ts.map +1 -1
- package/dist/Space.js +24 -27
- package/dist/Space.js.map +1 -1
- package/dist/WasClient.d.ts +43 -2
- package/dist/WasClient.d.ts.map +1 -1
- package/dist/WasClient.js +90 -14
- package/dist/WasClient.js.map +1 -1
- package/dist/codec.d.ts +11 -4
- package/dist/codec.d.ts.map +1 -1
- package/dist/edv/EdvCodec.d.ts +64 -33
- package/dist/edv/EdvCodec.d.ts.map +1 -1
- package/dist/edv/EdvCodec.js +194 -86
- package/dist/edv/EdvCodec.js.map +1 -1
- package/dist/edv/WasTransport.d.ts +6 -12
- package/dist/edv/WasTransport.d.ts.map +1 -1
- package/dist/edv/WasTransport.js +6 -21
- package/dist/edv/WasTransport.js.map +1 -1
- package/dist/edv/constants.d.ts +30 -0
- package/dist/edv/constants.d.ts.map +1 -0
- package/dist/edv/constants.js +30 -0
- package/dist/edv/constants.js.map +1 -0
- package/dist/edv/index.d.ts +1 -1
- package/dist/edv/index.d.ts.map +1 -1
- package/dist/edv/index.js +1 -1
- package/dist/edv/index.js.map +1 -1
- package/dist/errors.d.ts +3 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +15 -5
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/internal/codec.d.ts +69 -4
- package/dist/internal/codec.d.ts.map +1 -1
- package/dist/internal/codec.js +93 -5
- package/dist/internal/codec.js.map +1 -1
- package/dist/internal/content.d.ts +74 -3
- package/dist/internal/content.d.ts.map +1 -1
- package/dist/internal/content.js +78 -7
- package/dist/internal/content.js.map +1 -1
- package/dist/internal/describe.d.ts.map +1 -1
- package/dist/internal/describe.js +2 -1
- package/dist/internal/describe.js.map +1 -1
- package/dist/internal/pagination.d.ts +45 -0
- package/dist/internal/pagination.d.ts.map +1 -0
- package/dist/internal/pagination.js +53 -0
- package/dist/internal/pagination.js.map +1 -0
- package/dist/internal/paths.d.ts +4 -0
- package/dist/internal/paths.d.ts.map +1 -1
- package/dist/internal/paths.js +10 -1
- package/dist/internal/paths.js.map +1 -1
- package/dist/internal/policy.d.ts +54 -0
- package/dist/internal/policy.d.ts.map +1 -0
- package/dist/internal/policy.js +58 -0
- package/dist/internal/policy.js.map +1 -0
- package/dist/internal/request.d.ts +4 -2
- package/dist/internal/request.d.ts.map +1 -1
- package/dist/internal/request.js +9 -2
- package/dist/internal/request.js.map +1 -1
- package/dist/internal/reserved.d.ts +3 -8
- package/dist/internal/reserved.d.ts.map +1 -1
- package/dist/internal/reserved.js +10 -20
- package/dist/internal/reserved.js.map +1 -1
- package/dist/internal/write.d.ts +37 -0
- package/dist/internal/write.d.ts.map +1 -0
- package/dist/internal/write.js +29 -0
- package/dist/internal/write.js.map +1 -0
- package/dist/types.d.ts +14 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +5 -5
package/dist/edv/EdvCodec.js
CHANGED
|
@@ -11,11 +11,11 @@
|
|
|
11
11
|
* app's `resolveKeys`; they never reach the server, which stores only opaque
|
|
12
12
|
* JWE envelopes.
|
|
13
13
|
*
|
|
14
|
-
* This reuses `EdvClientCore`'s
|
|
15
|
-
*
|
|
16
|
-
* the
|
|
17
|
-
* I/O, so the codec is a
|
|
18
|
-
* its own.
|
|
14
|
+
* This reuses `EdvClientCore`'s transport-free `documentCipher` (its public
|
|
15
|
+
* `EdvDocumentCipher` -- the same JWE machinery as the standalone
|
|
16
|
+
* `WasTransport`), but here the WAS Resource CRUD -- the transport role -- is
|
|
17
|
+
* played by core was-client's `Collection`/`Resource` I/O, so the codec is a
|
|
18
|
+
* pure encode/decode transform and needs no transport of its own.
|
|
19
19
|
*
|
|
20
20
|
* Scope (documents-only):
|
|
21
21
|
*
|
|
@@ -24,9 +24,12 @@
|
|
|
24
24
|
* a human-readable id is rejected (it would leak onto the URL). Carry a
|
|
25
25
|
* human-readable label inside the encrypted content instead. (Blind-derived
|
|
26
26
|
* ids are a deferred future item.)
|
|
27
|
-
* - **
|
|
28
|
-
* is
|
|
29
|
-
* (
|
|
27
|
+
* - **Inline non-JSON as a single JWE.** A `Blob`/`Uint8Array` under the size cap
|
|
28
|
+
* is encrypted as one document -- stored as a legible UTF-8 string for a
|
|
29
|
+
* text-family type (else base64) -- with the plaintext content type and the
|
|
30
|
+
* encoding carried in the document `meta`. An oversized one is
|
|
31
|
+
* rejected (large chunked encrypted blobs need the server's `chunked-streams`
|
|
32
|
+
* affordance).
|
|
30
33
|
* - **Enforced sequence (conditional writes).** The codec sets
|
|
31
34
|
* `conditionalWrites`, so the write path pre-reads the current envelope and
|
|
32
35
|
* hands it to `encode`: an update advances `sequence` from its prior value and
|
|
@@ -40,29 +43,23 @@
|
|
|
40
43
|
* this).
|
|
41
44
|
*/
|
|
42
45
|
import { EdvClientCore } from '@interop/edv-client';
|
|
43
|
-
import { ValidationError } from '../errors.js';
|
|
44
|
-
import { readJsonData } from '../internal/content.js';
|
|
45
|
-
import {
|
|
46
|
+
import { EncryptionError, ValidationError } from '../errors.js';
|
|
47
|
+
import { guessContentTypeFromId, isBlob, isTextContentType, readJsonData } from '../internal/content.js';
|
|
48
|
+
import { DEFAULT_CONTENT_TYPE, ENCODER } from './constants.js';
|
|
46
49
|
/**
|
|
47
|
-
* Default ceiling for a single-document (unchunked) encrypted binary
|
|
48
|
-
* Past this a `Blob`/`Uint8Array` is
|
|
49
|
-
* supported.
|
|
50
|
+
* Default ceiling for a single-document (unchunked) encrypted binary or text
|
|
51
|
+
* write, measured in raw (pre-base64) bytes. Past this a `Blob`/`Uint8Array` is
|
|
52
|
+
* rejected until chunked encrypted blobs are supported. 5 MiB; binary inflates
|
|
53
|
+
* ~33% under base64, text is stored verbatim.
|
|
50
54
|
*/
|
|
51
|
-
const DEFAULT_MAX_BLOB_BYTES = 1024 * 1024;
|
|
55
|
+
const DEFAULT_MAX_BLOB_BYTES = 5 * 1024 * 1024;
|
|
52
56
|
/**
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
* `
|
|
56
|
-
*
|
|
57
|
-
* `application/*+json` parser to mark envelopes distinctly in listings.
|
|
57
|
+
* A shared strict UTF-8 decoder used to test whether a non-JSON payload is
|
|
58
|
+
* valid UTF-8 (so it can be stored legibly as text rather than base64).
|
|
59
|
+
* `fatal: true` makes `decode` throw on malformed input; the decoder is
|
|
60
|
+
* stateless across non-streaming calls, so one instance is reused.
|
|
58
61
|
*/
|
|
59
|
-
const
|
|
60
|
-
/**
|
|
61
|
-
* Marker property tagging an encrypted document whose decrypted content is a
|
|
62
|
-
* binary blob (rather than a JSON value), so `decode` can reconstruct a `Blob`.
|
|
63
|
-
* Namespaced to avoid colliding with caller JSON.
|
|
64
|
-
*/
|
|
65
|
-
const BLOB_MARKER = '@interop/was-client:edvBlob';
|
|
62
|
+
const UTF8_DECODER = new TextDecoder('utf-8', { fatal: true });
|
|
66
63
|
/**
|
|
67
64
|
* Heuristic for an EDV document id: multibase base58btc (leading `z`) of a
|
|
68
65
|
* 128-bit value. Used to reject human-readable ids on `put()`. Deliberately a
|
|
@@ -71,10 +68,6 @@ const BLOB_MARKER = '@interop/was-client:edvBlob';
|
|
|
71
68
|
* decode-and-length verification.
|
|
72
69
|
*/
|
|
73
70
|
const EDV_DOC_ID = /^z[1-9A-HJ-NP-Za-km-z]{21,}$/;
|
|
74
|
-
const ENCODER = new TextEncoder();
|
|
75
|
-
function isBlob(value) {
|
|
76
|
-
return typeof Blob !== 'undefined' && value instanceof Blob;
|
|
77
|
-
}
|
|
78
71
|
/**
|
|
79
72
|
* Encodes bytes to standard base64 using the platform `btoa` (present in modern
|
|
80
73
|
* Node and browsers), via a binary string.
|
|
@@ -105,7 +98,7 @@ function base64ToBytes(base64) {
|
|
|
105
98
|
}
|
|
106
99
|
/**
|
|
107
100
|
* A {@link ResourceCodec} that encrypts on write and decrypts on read using an
|
|
108
|
-
* `EdvClientCore`'s
|
|
101
|
+
* `EdvClientCore`'s public `documentCipher`. One instance is bound per encrypted
|
|
109
102
|
* collection handle.
|
|
110
103
|
*/
|
|
111
104
|
export class EdvCodec {
|
|
@@ -138,20 +131,28 @@ export class EdvCodec {
|
|
|
138
131
|
'id, or carry the human-readable label inside the encrypted content.');
|
|
139
132
|
}
|
|
140
133
|
const docId = id ?? (await this._edv.generateId());
|
|
141
|
-
const content = await this.
|
|
134
|
+
const { content, meta } = await this._toDocument(data, contentType, docId);
|
|
142
135
|
// When the write path pre-read a current envelope, advance `sequence` from
|
|
143
|
-
// its prior value (`
|
|
136
|
+
// its prior value (`encrypt({ update: true })` increments it) and pin the
|
|
144
137
|
// write to the server's current ETag with `If-Match`. With no prior envelope
|
|
145
138
|
// this is a fresh insert (`sequence: 0`) guarded by `If-None-Match: *`
|
|
146
139
|
// (create-if-absent), so a concurrent first writer cannot be clobbered.
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
140
|
+
let priorDoc = null;
|
|
141
|
+
if (current) {
|
|
142
|
+
const read = await readJsonData(current);
|
|
143
|
+
this._assertEnvelope(read, 'update');
|
|
144
|
+
priorDoc = read;
|
|
145
|
+
}
|
|
146
|
+
const { documentCipher } = this._edv;
|
|
147
|
+
const recipients = documentCipher.createDefaultRecipients(this._keyAgreementKey);
|
|
148
|
+
const encrypted = await documentCipher.encrypt({
|
|
152
149
|
doc: {
|
|
153
150
|
id: docId,
|
|
154
151
|
content,
|
|
152
|
+
// `content` and `meta` are both sealed inside the JWE; `meta` carries the
|
|
153
|
+
// plaintext content type and the inline-encoding discriminator, taken
|
|
154
|
+
// fresh from this write (the new type/encoding wins on update).
|
|
155
|
+
meta,
|
|
155
156
|
...(priorDoc && { sequence: priorDoc.sequence })
|
|
156
157
|
},
|
|
157
158
|
recipients,
|
|
@@ -163,9 +164,17 @@ export class EdvCodec {
|
|
|
163
164
|
id: docId,
|
|
164
165
|
body: ENCODER.encode(JSON.stringify(encrypted)),
|
|
165
166
|
contentType: this._contentType,
|
|
167
|
+
// Surface the plaintext content type (the server-opaque envelope type stays
|
|
168
|
+
// `contentType`) so `add()` reports the real resource type.
|
|
169
|
+
resourceContentType: meta.contentType,
|
|
166
170
|
// Pin an update to the server's current ETag; guard a fresh insert with
|
|
167
|
-
// create-if-absent.
|
|
168
|
-
//
|
|
171
|
+
// create-if-absent. An update's `If-Match` carries a server-provided ETag,
|
|
172
|
+
// so it degrades to an advisory write against a backend without the
|
|
173
|
+
// conditional-writes feature (the ETag is absent). A fresh insert's
|
|
174
|
+
// `If-None-Match: *` needs no server-provided validator and so is emitted
|
|
175
|
+
// unconditionally by design -- it expresses the insert's intent
|
|
176
|
+
// (create-only-if-absent); a backend that does not honor it simply ignores
|
|
177
|
+
// it, leaving the write harmless rather than degraded.
|
|
169
178
|
...(priorDoc
|
|
170
179
|
? { ifMatch: current.headers.get('etag') ?? undefined }
|
|
171
180
|
: { ifNoneMatch: true })
|
|
@@ -175,74 +184,174 @@ export class EdvCodec {
|
|
|
175
184
|
* @inheritdoc
|
|
176
185
|
*/
|
|
177
186
|
async decode(response) {
|
|
178
|
-
const encryptedDoc =
|
|
179
|
-
|
|
187
|
+
const encryptedDoc = await readJsonData(response);
|
|
188
|
+
this._assertEnvelope(encryptedDoc, 'read');
|
|
189
|
+
const decrypted = await this._edv.documentCipher.decrypt({
|
|
180
190
|
encryptedDoc,
|
|
181
191
|
keyAgreementKey: this._keyAgreementKey
|
|
182
192
|
});
|
|
183
|
-
return this.
|
|
193
|
+
return this._fromDocument(decrypted.content, decrypted.meta);
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Asserts that a document read from an encrypted collection is an EDV envelope
|
|
197
|
+
* (`{ jwe, ... }`) before it is handed to the cipher. A plaintext or foreign
|
|
198
|
+
* resource -- one written without this codec -- carries no `jwe`, which would
|
|
199
|
+
* otherwise make the EDV core throw a raw `TypeError`. Surfacing a typed
|
|
200
|
+
* `EncryptionError` keeps the fail-closed contract legible to callers.
|
|
201
|
+
*
|
|
202
|
+
* @param doc {unknown}
|
|
203
|
+
* @param context {string} the operation in progress (`read` / `update`),
|
|
204
|
+
* for the message
|
|
205
|
+
* @returns {asserts doc is IEncryptedDocument}
|
|
206
|
+
*/
|
|
207
|
+
_assertEnvelope(doc, context) {
|
|
208
|
+
const jwe = doc !== null && typeof doc === 'object'
|
|
209
|
+
? doc.jwe
|
|
210
|
+
: undefined;
|
|
211
|
+
if (jwe === null || typeof jwe !== 'object') {
|
|
212
|
+
throw new EncryptionError(`Cannot ${context} an encrypted resource: the stored document is not ` +
|
|
213
|
+
'an EDV envelope (it carries no `jwe` field). It was likely written ' +
|
|
214
|
+
'as plaintext, or by a writer that did not use this encrypted ' +
|
|
215
|
+
'collection.');
|
|
216
|
+
}
|
|
184
217
|
}
|
|
185
218
|
/**
|
|
186
|
-
*
|
|
187
|
-
*
|
|
188
|
-
*
|
|
189
|
-
*
|
|
219
|
+
* Splits a caller value into a decrypted EDV document `{ content, meta }`,
|
|
220
|
+
* carrying the plaintext content type and inline-encoding discriminator in
|
|
221
|
+
* `meta`. Three cases:
|
|
222
|
+
*
|
|
223
|
+
* 1. JSON object/array to `content` verbatim, `meta = { contentType }` (no
|
|
224
|
+
* `encoding`); the shape of `content` is never inspected on read, so a
|
|
225
|
+
* caller object shaped like `{ text }` / `{ bytes }` round-trips as itself.
|
|
226
|
+
* 2. Text (`Blob`/`Uint8Array` of a text-family type that is valid UTF-8)
|
|
227
|
+
* to `content = { text }`, `meta = { contentType, encoding: 'utf-8' }`;
|
|
228
|
+
* stored legibly with no base64 inflation.
|
|
229
|
+
* 3. Binary (any other `Blob`/`Uint8Array`) to `content = { bytes: base64 }`,
|
|
230
|
+
* `meta = { contentType, encoding: 'base64' }`.
|
|
190
231
|
*
|
|
191
|
-
*
|
|
192
|
-
*
|
|
193
|
-
*
|
|
232
|
+
* A bare primitive is rejected (mirroring the plaintext `prepareBody`
|
|
233
|
+
* contract). The binary/text content type resolves as
|
|
234
|
+
* `contentType || blob.type || guessContentTypeFromId(id) || octet-stream`,
|
|
235
|
+
* mirroring `prepareBody`.
|
|
236
|
+
*
|
|
237
|
+
* @param data {ResourceData}
|
|
238
|
+
* @param [contentType] {string} caller-supplied content type
|
|
239
|
+
* @param [id] {string} resource id, for the extension guess
|
|
240
|
+
* @returns {Promise<{ content: Record<string, unknown>; meta:
|
|
241
|
+
* Record<string, unknown> }>}
|
|
194
242
|
*/
|
|
195
|
-
async
|
|
243
|
+
async _toDocument(data, contentType, id) {
|
|
244
|
+
let bytes;
|
|
245
|
+
let resolvedType;
|
|
196
246
|
if (isBlob(data)) {
|
|
197
|
-
|
|
198
|
-
|
|
247
|
+
bytes = new Uint8Array(await data.arrayBuffer());
|
|
248
|
+
resolvedType =
|
|
249
|
+
contentType ||
|
|
250
|
+
data.type ||
|
|
251
|
+
guessContentTypeFromId(id ?? '') ||
|
|
252
|
+
'application/octet-stream';
|
|
253
|
+
}
|
|
254
|
+
else if (data instanceof Uint8Array) {
|
|
255
|
+
bytes = data;
|
|
256
|
+
resolvedType =
|
|
257
|
+
contentType ||
|
|
258
|
+
guessContentTypeFromId(id ?? '') ||
|
|
259
|
+
'application/octet-stream';
|
|
199
260
|
}
|
|
200
|
-
if (
|
|
201
|
-
|
|
261
|
+
if (bytes !== undefined && resolvedType !== undefined) {
|
|
262
|
+
if (bytes.length > this._maxBlobBytes) {
|
|
263
|
+
throw new ValidationError(`Encrypted binary write of ${bytes.length} bytes exceeds the ` +
|
|
264
|
+
`single-document limit of ${this._maxBlobBytes} bytes. Chunked ` +
|
|
265
|
+
"encrypted blobs need the server's chunked-streams affordance " +
|
|
266
|
+
'(not yet available).');
|
|
267
|
+
}
|
|
268
|
+
// Text-family AND valid UTF-8 to store as a legible string. The UTF-8 gate
|
|
269
|
+
// guarantees the bytes survive the string round-trip exactly; anything
|
|
270
|
+
// else falls through to base64, which is always byte-safe.
|
|
271
|
+
if (isTextContentType(resolvedType)) {
|
|
272
|
+
const text = decodeUtf8(bytes);
|
|
273
|
+
if (text !== null) {
|
|
274
|
+
return {
|
|
275
|
+
content: { text },
|
|
276
|
+
meta: { contentType: resolvedType, encoding: 'utf-8' }
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
return {
|
|
281
|
+
content: { bytes: bytesToBase64(bytes) },
|
|
282
|
+
meta: { contentType: resolvedType, encoding: 'base64' }
|
|
283
|
+
};
|
|
202
284
|
}
|
|
203
285
|
if (data !== null && typeof data === 'object') {
|
|
204
|
-
|
|
286
|
+
// JSON object/array: content verbatim, no encoding (the read side treats an
|
|
287
|
+
// absent `meta.encoding` as JSON). EDV models `content` as an object
|
|
288
|
+
// record; a JSON array is also a valid encrypted value here, so widen it.
|
|
289
|
+
return {
|
|
290
|
+
content: data,
|
|
291
|
+
meta: { contentType: contentType ?? 'application/json' }
|
|
292
|
+
};
|
|
205
293
|
}
|
|
206
294
|
throw new ValidationError('Encrypted resource data must be a plain object/array (JSON) or a ' +
|
|
207
295
|
'Blob/Uint8Array (binary).');
|
|
208
296
|
}
|
|
209
297
|
/**
|
|
210
|
-
*
|
|
211
|
-
*
|
|
298
|
+
* Reconstructs a caller value from a decrypted EDV document, discriminating
|
|
299
|
+
* on `meta.encoding`:
|
|
212
300
|
*
|
|
213
|
-
*
|
|
214
|
-
*
|
|
215
|
-
*
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
`single-document limit of ${this._maxBlobBytes} bytes. Chunked ` +
|
|
221
|
-
"encrypted blobs need the server's chunked-streams affordance " +
|
|
222
|
-
'(not yet available).');
|
|
223
|
-
}
|
|
224
|
-
return { [BLOB_MARKER]: true, contentType, base64: bytesToBase64(bytes) };
|
|
225
|
-
}
|
|
226
|
-
/**
|
|
227
|
-
* Reconstructs a caller value from decrypted EDV document content: a `Blob`
|
|
228
|
-
* for a wrapped blob record, otherwise the JSON content verbatim.
|
|
301
|
+
* - `'utf-8'` to a `Blob` typed `meta.contentType` from `content.text`.
|
|
302
|
+
* - `'base64'` to a `Blob` typed `meta.contentType` from `content.bytes`.
|
|
303
|
+
* - absent (or `meta` absent) to `content` returned verbatim as JSON.
|
|
304
|
+
*
|
|
305
|
+
* A malformed inner shape (an encoding that does not match its container key's
|
|
306
|
+
* type) throws {@link EncryptionError} -- the decrypted-document analogue of
|
|
307
|
+
* `_assertEnvelope`'s outer guard.
|
|
229
308
|
*
|
|
230
309
|
* @param content {unknown}
|
|
310
|
+
* @param [meta] {Record<string, unknown>}
|
|
231
311
|
* @returns {Json | Blob}
|
|
232
312
|
*/
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
const
|
|
238
|
-
|
|
239
|
-
|
|
313
|
+
_fromDocument(content, meta) {
|
|
314
|
+
const encoding = meta?.encoding;
|
|
315
|
+
const contentType = typeof meta?.contentType === 'string' ? meta.contentType : undefined;
|
|
316
|
+
if (encoding === 'utf-8') {
|
|
317
|
+
const text = content?.text;
|
|
318
|
+
if (typeof text !== 'string') {
|
|
319
|
+
throw new EncryptionError('Malformed encrypted text document: meta.encoding is "utf-8" but ' +
|
|
320
|
+
'content.text is not a string.');
|
|
321
|
+
}
|
|
322
|
+
return new Blob([ENCODER.encode(text)], { type: contentType });
|
|
323
|
+
}
|
|
324
|
+
if (encoding === 'base64') {
|
|
325
|
+
const base64 = content?.bytes;
|
|
326
|
+
if (typeof base64 !== 'string') {
|
|
327
|
+
throw new EncryptionError('Malformed encrypted binary document: meta.encoding is "base64" but ' +
|
|
328
|
+
'content.bytes is not a string.');
|
|
329
|
+
}
|
|
330
|
+
return new Blob([base64ToBytes(base64)], {
|
|
331
|
+
type: contentType
|
|
240
332
|
});
|
|
241
333
|
}
|
|
242
334
|
return content;
|
|
243
335
|
}
|
|
244
336
|
}
|
|
245
|
-
/**
|
|
337
|
+
/**
|
|
338
|
+
* Decodes bytes as strict UTF-8, returning `null` when they are not valid UTF-8
|
|
339
|
+
* (so the caller can fall back to base64). Uses the shared fatal decoder.
|
|
340
|
+
*
|
|
341
|
+
* @param bytes {Uint8Array}
|
|
342
|
+
* @returns {string | null}
|
|
343
|
+
*/
|
|
344
|
+
function decodeUtf8(bytes) {
|
|
345
|
+
try {
|
|
346
|
+
return UTF8_DECODER.decode(bytes);
|
|
347
|
+
}
|
|
348
|
+
catch {
|
|
349
|
+
return null;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* The EDV scheme tag this provider handles (matches the Collection marker).
|
|
354
|
+
*/
|
|
246
355
|
const EDV_SCHEME = 'edv';
|
|
247
356
|
/**
|
|
248
357
|
* Builds an {@link EncryptionProvider} for the `edv` scheme: a pure **keystore**
|
|
@@ -263,8 +372,8 @@ const EDV_SCHEME = 'edv';
|
|
|
263
372
|
* `{ keyAgreementKey, keyResolver }`, or `null` if this client holds no keys
|
|
264
373
|
* for it (fail-closed -- not a plaintext signal)
|
|
265
374
|
* @param [options.contentType] {string} stored envelope content type;
|
|
266
|
-
* defaults to `application/json`. Pass `
|
|
267
|
-
* (`application/
|
|
375
|
+
* defaults to `application/json`. Pass `JOSE_CONTENT_TYPE`
|
|
376
|
+
* (`application/jose+json`) against a server that registers an
|
|
268
377
|
* `application/*+json` parser.
|
|
269
378
|
* @param [options.maxBlobBytes] {number} single-document binary cap (default
|
|
270
379
|
* 1 MiB)
|
|
@@ -295,5 +404,4 @@ export function createEdvEncryption({ resolveKeys, contentType = DEFAULT_CONTENT
|
|
|
295
404
|
}
|
|
296
405
|
};
|
|
297
406
|
}
|
|
298
|
-
export { EDV_CONTENT_TYPE };
|
|
299
407
|
//# sourceMappingURL=EdvCodec.js.map
|
package/dist/edv/EdvCodec.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EdvCodec.js","sourceRoot":"","sources":["../../src/edv/EdvCodec.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH
|
|
1
|
+
{"version":3,"file":"EdvCodec.js","sourceRoot":"","sources":["../../src/edv/EdvCodec.ts"],"names":[],"mappings":"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"}
|
|
@@ -19,12 +19,12 @@
|
|
|
19
19
|
* URL-safe and never a reserved segment.
|
|
20
20
|
* - **Encrypted content type.** Documents are stored as `application/json` by
|
|
21
21
|
* default, so the profile works against an unmodified WAS server. The
|
|
22
|
-
* preferred marker is `application/
|
|
22
|
+
* preferred marker is `application/jose+json` (exported as `JOSE_CONTENT_TYPE`),
|
|
23
23
|
* which distinguishes EDV envelopes from plaintext application JSON in
|
|
24
24
|
* listings and metadata -- but the server must register an `application/*+json`
|
|
25
25
|
* content-type parser to accept it (the reference was-teaching-server does; a
|
|
26
26
|
* server that does not will reject it with 415). Pass `contentType:
|
|
27
|
-
*
|
|
27
|
+
* JOSE_CONTENT_TYPE` to opt into it where the server supports it.
|
|
28
28
|
*
|
|
29
29
|
* Scope: documents only (`insert` / `update` / `get`). Blinded `find` / `count`
|
|
30
30
|
* / `updateIndex` and chunked streams (`storeChunk` / `getChunk`) require
|
|
@@ -36,13 +36,8 @@
|
|
|
36
36
|
import { Transport } from '@interop/edv-client';
|
|
37
37
|
import type { IEncryptedDocument } from '@interop/data-integrity-core';
|
|
38
38
|
import type { WasClient } from '../WasClient.js';
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
* envelope whose `jwe` property carries the ciphertext). Requires the server to
|
|
42
|
-
* register an `application/*+json` content-type parser; otherwise use the
|
|
43
|
-
* default `application/json` (see `WasTransport`'s `contentType` option).
|
|
44
|
-
*/
|
|
45
|
-
export declare const EDV_CONTENT_TYPE = "application/edv+json";
|
|
39
|
+
import { JOSE_CONTENT_TYPE } from './constants.js';
|
|
40
|
+
export { JOSE_CONTENT_TYPE };
|
|
46
41
|
/**
|
|
47
42
|
* The subset of `WasClient` this transport depends on: the signed-request
|
|
48
43
|
* escape hatch. Declared structurally so tests can supply a lightweight stub.
|
|
@@ -60,7 +55,7 @@ export declare class WasTransport extends Transport {
|
|
|
60
55
|
* @param options.collectionId {string} the vault Collection id
|
|
61
56
|
* @param [options.contentType] {string} content type for stored envelopes;
|
|
62
57
|
* defaults to `application/json` (accepted by an unmodified server). Pass
|
|
63
|
-
* `
|
|
58
|
+
* `JOSE_CONTENT_TYPE` against a server that registers an `application/*+json`
|
|
64
59
|
* parser.
|
|
65
60
|
*/
|
|
66
61
|
constructor({ was, spaceId, collectionId, contentType }: {
|
|
@@ -81,7 +76,7 @@ export declare class WasTransport extends Transport {
|
|
|
81
76
|
private _resourcePath;
|
|
82
77
|
/**
|
|
83
78
|
* Writes an encrypted document to its WAS resource path as
|
|
84
|
-
* `application/
|
|
79
|
+
* `application/jose+json` (the envelope serialized to bytes so the stored
|
|
85
80
|
* content type is exact).
|
|
86
81
|
*
|
|
87
82
|
* @param id {string}
|
|
@@ -174,5 +169,4 @@ export declare class WasTransport extends Transport {
|
|
|
174
169
|
*/
|
|
175
170
|
private _unsupported;
|
|
176
171
|
}
|
|
177
|
-
export {};
|
|
178
172
|
//# sourceMappingURL=WasTransport.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WasTransport.d.ts","sourceRoot":"","sources":["../../src/edv/WasTransport.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAE/C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAA;AACtE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;
|
|
1
|
+
{"version":3,"file":"WasTransport.d.ts","sourceRoot":"","sources":["../../src/edv/WasTransport.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAE/C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAA;AACtE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAIhD,OAAO,EAGL,iBAAiB,EAClB,MAAM,gBAAgB,CAAA;AAEvB,OAAO,EAAE,iBAAiB,EAAE,CAAA;AAE5B;;;GAGG;AACH,KAAK,YAAY,GAAG,IAAI,CAAC,SAAS,EAAE,SAAS,CAAC,CAAA;AA8B9C,qBAAa,YAAa,SAAQ,SAAS;IACzC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAE5B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAc;IAEnC;;;;;;;;;OASG;gBACS,EACV,GAAG,EACH,OAAO,EACP,YAAY,EACZ,WAAkC,EACnC,EAAE;QACD,GAAG,EAAE,YAAY,CAAA;QACjB,OAAO,EAAE,MAAM,CAAA;QACf,YAAY,EAAE,MAAM,CAAA;QACpB,WAAW,CAAC,EAAE,MAAM,CAAA;KACrB;IAQD;;;;;;;;OAQG;IACH,OAAO,CAAC,aAAa;IAIrB;;;;;;;;OAQG;YACW,IAAI;IAalB;;;;;;;;;;;;OAYG;IACY,MAAM,CAAC,EACpB,SAAS,EACV,GAAE;QAAE,SAAS,CAAC,EAAE,kBAAkB,CAAA;KAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAa1D;;;;;;;;;;OAUG;IACY,MAAM,CAAC,EACpB,SAAS,EACV,GAAE;QAAE,SAAS,CAAC,EAAE,kBAAkB,CAAA;KAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAoB1D;;;;;;;;;OASG;IACY,GAAG,CAAC,EACjB,EAAE,EACH,GAAE;QAAE,EAAE,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAuBrD;;;;;;OAMG;YACW,OAAO;IAYrB;;;;;OAKG;IACY,IAAI,IAAI,OAAO,CAAC,KAAK,CAAC;IAIrC;;;;OAIG;IACY,WAAW,IAAI,OAAO,CAAC,KAAK,CAAC;IAI5C;;;;OAIG;IACY,UAAU,IAAI,OAAO,CAAC,KAAK,CAAC;IAI3C;;;;OAIG;IACY,QAAQ,IAAI,OAAO,CAAC,KAAK,CAAC;IAIzC;;;;;;OAMG;IACH,OAAO,CAAC,YAAY;CAQrB"}
|
package/dist/edv/WasTransport.js
CHANGED
|
@@ -19,12 +19,12 @@
|
|
|
19
19
|
* URL-safe and never a reserved segment.
|
|
20
20
|
* - **Encrypted content type.** Documents are stored as `application/json` by
|
|
21
21
|
* default, so the profile works against an unmodified WAS server. The
|
|
22
|
-
* preferred marker is `application/
|
|
22
|
+
* preferred marker is `application/jose+json` (exported as `JOSE_CONTENT_TYPE`),
|
|
23
23
|
* which distinguishes EDV envelopes from plaintext application JSON in
|
|
24
24
|
* listings and metadata -- but the server must register an `application/*+json`
|
|
25
25
|
* content-type parser to accept it (the reference was-teaching-server does; a
|
|
26
26
|
* server that does not will reject it with 415). Pass `contentType:
|
|
27
|
-
*
|
|
27
|
+
* JOSE_CONTENT_TYPE` to opt into it where the server supports it.
|
|
28
28
|
*
|
|
29
29
|
* Scope: documents only (`insert` / `update` / `get`). Blinded `find` / `count`
|
|
30
30
|
* / `updateIndex` and chunked streams (`storeChunk` / `getChunk`) require
|
|
@@ -37,23 +37,8 @@ import { Transport } from '@interop/edv-client';
|
|
|
37
37
|
import { httpStatus } from '../errors.js';
|
|
38
38
|
import { readJsonData } from '../internal/content.js';
|
|
39
39
|
import { resourcePath } from '../internal/paths.js';
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
* envelope whose `jwe` property carries the ciphertext). Requires the server to
|
|
43
|
-
* register an `application/*+json` content-type parser; otherwise use the
|
|
44
|
-
* default `application/json` (see `WasTransport`'s `contentType` option).
|
|
45
|
-
*/
|
|
46
|
-
export const EDV_CONTENT_TYPE = 'application/edv+json';
|
|
47
|
-
/**
|
|
48
|
-
* The content type used by default: plain JSON, which an unmodified WAS server
|
|
49
|
-
* accepts. The stored envelope is still self-identifying by its `jwe` field.
|
|
50
|
-
*/
|
|
51
|
-
const DEFAULT_CONTENT_TYPE = 'application/json';
|
|
52
|
-
/**
|
|
53
|
-
* A shared `TextEncoder` for serializing envelope bytes (stateless, so one
|
|
54
|
-
* instance is reused across every `_put`).
|
|
55
|
-
*/
|
|
56
|
-
const ENCODER = new TextEncoder();
|
|
40
|
+
import { DEFAULT_CONTENT_TYPE, ENCODER, JOSE_CONTENT_TYPE } from './constants.js';
|
|
41
|
+
export { JOSE_CONTENT_TYPE };
|
|
57
42
|
/**
|
|
58
43
|
* Builds an `Error` carrying the `name` that `EdvClientCore` (and the reference
|
|
59
44
|
* `HttpsTransport`) dispatch on -- `DuplicateError`, `InvalidStateError`,
|
|
@@ -85,7 +70,7 @@ export class WasTransport extends Transport {
|
|
|
85
70
|
* @param options.collectionId {string} the vault Collection id
|
|
86
71
|
* @param [options.contentType] {string} content type for stored envelopes;
|
|
87
72
|
* defaults to `application/json` (accepted by an unmodified server). Pass
|
|
88
|
-
* `
|
|
73
|
+
* `JOSE_CONTENT_TYPE` against a server that registers an `application/*+json`
|
|
89
74
|
* parser.
|
|
90
75
|
*/
|
|
91
76
|
constructor({ was, spaceId, collectionId, contentType = DEFAULT_CONTENT_TYPE }) {
|
|
@@ -109,7 +94,7 @@ export class WasTransport extends Transport {
|
|
|
109
94
|
}
|
|
110
95
|
/**
|
|
111
96
|
* Writes an encrypted document to its WAS resource path as
|
|
112
|
-
* `application/
|
|
97
|
+
* `application/jose+json` (the envelope serialized to bytes so the stored
|
|
113
98
|
* content type is exact).
|
|
114
99
|
*
|
|
115
100
|
* @param id {string}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WasTransport.js","sourceRoot":"","sources":["../../src/edv/WasTransport.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAI/C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;
|
|
1
|
+
{"version":3,"file":"WasTransport.js","sourceRoot":"","sources":["../../src/edv/WasTransport.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2026 Interop Alliance. All rights reserved.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Shared EDV-over-WAS constants: the stored-envelope content types (the portable
|
|
6
|
+
* default and the preferred JOSE marker) and the `TextEncoder` used to serialize
|
|
7
|
+
* envelopes to bytes. Kept in one place so `WasTransport` and `EdvCodec` stay in
|
|
8
|
+
* lockstep instead of each declaring their own copy.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* The content type used by default: plain JSON, which an unmodified WAS server
|
|
12
|
+
* accepts. The stored envelope is still self-identifying by its `jwe` field.
|
|
13
|
+
*/
|
|
14
|
+
export declare const DEFAULT_CONTENT_TYPE = "application/json";
|
|
15
|
+
/**
|
|
16
|
+
* The preferred content type marking a stored EDV-encrypted document: the JWE
|
|
17
|
+
* JSON Serialization media type (`application/jose+json`, RFC 7516), which is
|
|
18
|
+
* the wire format the WAS spec's Encryption Scheme Registry maps the `edv`
|
|
19
|
+
* scheme to. The stored envelope's `jwe` property carries the ciphertext.
|
|
20
|
+
* Requires the server to register an `application/*+json` content-type parser;
|
|
21
|
+
* otherwise use the default `application/json` (see `WasTransport`'s
|
|
22
|
+
* `contentType` option).
|
|
23
|
+
*/
|
|
24
|
+
export declare const JOSE_CONTENT_TYPE = "application/jose+json";
|
|
25
|
+
/**
|
|
26
|
+
* A shared `TextEncoder` for serializing envelope bytes (stateless, so one
|
|
27
|
+
* instance is reused across every write).
|
|
28
|
+
*/
|
|
29
|
+
export declare const ENCODER: TextEncoder;
|
|
30
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/edv/constants.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;GAKG;AAEH;;;GAGG;AACH,eAAO,MAAM,oBAAoB,qBAAqB,CAAA;AAEtD;;;;;;;;GAQG;AACH,eAAO,MAAM,iBAAiB,0BAA0B,CAAA;AAExD;;;GAGG;AACH,eAAO,MAAM,OAAO,aAAoB,CAAA"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2026 Interop Alliance. All rights reserved.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Shared EDV-over-WAS constants: the stored-envelope content types (the portable
|
|
6
|
+
* default and the preferred JOSE marker) and the `TextEncoder` used to serialize
|
|
7
|
+
* envelopes to bytes. Kept in one place so `WasTransport` and `EdvCodec` stay in
|
|
8
|
+
* lockstep instead of each declaring their own copy.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* The content type used by default: plain JSON, which an unmodified WAS server
|
|
12
|
+
* accepts. The stored envelope is still self-identifying by its `jwe` field.
|
|
13
|
+
*/
|
|
14
|
+
export const DEFAULT_CONTENT_TYPE = 'application/json';
|
|
15
|
+
/**
|
|
16
|
+
* The preferred content type marking a stored EDV-encrypted document: the JWE
|
|
17
|
+
* JSON Serialization media type (`application/jose+json`, RFC 7516), which is
|
|
18
|
+
* the wire format the WAS spec's Encryption Scheme Registry maps the `edv`
|
|
19
|
+
* scheme to. The stored envelope's `jwe` property carries the ciphertext.
|
|
20
|
+
* Requires the server to register an `application/*+json` content-type parser;
|
|
21
|
+
* otherwise use the default `application/json` (see `WasTransport`'s
|
|
22
|
+
* `contentType` option).
|
|
23
|
+
*/
|
|
24
|
+
export const JOSE_CONTENT_TYPE = 'application/jose+json';
|
|
25
|
+
/**
|
|
26
|
+
* A shared `TextEncoder` for serializing envelope bytes (stateless, so one
|
|
27
|
+
* instance is reused across every write).
|
|
28
|
+
*/
|
|
29
|
+
export const ENCODER = new TextEncoder();
|
|
30
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/edv/constants.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH;;;;;GAKG;AAEH;;;GAGG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,kBAAkB,CAAA;AAEtD;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,uBAAuB,CAAA;AAExD;;;GAGG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAA"}
|