pushnow-sdk 0.1.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 +231 -0
- package/README.zh-CN.md +59 -0
- package/dist/attachments.d.ts +6 -0
- package/dist/attachments.js +57 -0
- package/dist/auth.d.ts +6 -0
- package/dist/auth.js +91 -0
- package/dist/browser.js +2723 -0
- package/dist/config.d.ts +5 -0
- package/dist/config.js +33 -0
- package/dist/crypto.d.ts +10 -0
- package/dist/crypto.js +59 -0
- package/dist/encoding.d.ts +8 -0
- package/dist/encoding.js +34 -0
- package/dist/http.d.ts +15 -0
- package/dist/http.js +101 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +8 -0
- package/dist/messages.d.ts +5 -0
- package/dist/messages.js +132 -0
- package/dist/recipients.d.ts +3 -0
- package/dist/recipients.js +32 -0
- package/dist/send.d.ts +2 -0
- package/dist/send.js +37 -0
- package/dist/types.d.ts +145 -0
- package/dist/types.js +1 -0
- package/package.json +31 -0
package/dist/browser.js
ADDED
|
@@ -0,0 +1,2723 @@
|
|
|
1
|
+
// src/encoding.ts
|
|
2
|
+
var bytes = (value) => new TextEncoder().encode(value);
|
|
3
|
+
function base64(value) {
|
|
4
|
+
const data = value instanceof Uint8Array ? value : new Uint8Array(value);
|
|
5
|
+
let result = "";
|
|
6
|
+
for (let start = 0; start < data.length; start += 8192) result += String.fromCharCode(...data.subarray(start, start + 8192));
|
|
7
|
+
return btoa(result);
|
|
8
|
+
}
|
|
9
|
+
function decode(value, size) {
|
|
10
|
+
if (typeof value !== "string" || !/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(value)) throw new Error("Invalid Base64 encoding");
|
|
11
|
+
const decoded = Uint8Array.from(atob(value), (c) => c.charCodeAt(0));
|
|
12
|
+
if (size !== void 0 && decoded.length !== size || base64(decoded) !== value) throw new Error("Invalid key or encoding");
|
|
13
|
+
return decoded;
|
|
14
|
+
}
|
|
15
|
+
function cryptoAPI() {
|
|
16
|
+
if (!globalThis.crypto?.subtle) throw new Error("WebCrypto is required; use a secure HTTPS context");
|
|
17
|
+
return globalThis.crypto;
|
|
18
|
+
}
|
|
19
|
+
async function sha256(data) {
|
|
20
|
+
return [...new Uint8Array(await cryptoAPI().subtle.digest("SHA-256", data))].map((n) => n.toString(16).padStart(2, "0")).join("");
|
|
21
|
+
}
|
|
22
|
+
var fingerprint = (key) => sha256(decode(key, 65));
|
|
23
|
+
function uuid(value) {
|
|
24
|
+
if (typeof value !== "string" || !/^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value)) throw new Error("Invalid UUID");
|
|
25
|
+
}
|
|
26
|
+
function object(value) {
|
|
27
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("Expected an object");
|
|
28
|
+
return value;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// src/config.ts
|
|
32
|
+
function validateAPIURL(value) {
|
|
33
|
+
const url = new URL(value);
|
|
34
|
+
if (url.username || url.password || url.search || url.hash || url.pathname !== "/" || url.protocol !== "https:" && !(url.protocol === "http:" && ["localhost", "127.0.0.1", "[::1]"].includes(url.hostname))) {
|
|
35
|
+
throw new Error("Use an HTTPS API origin (HTTP is allowed only on localhost)");
|
|
36
|
+
}
|
|
37
|
+
return url.origin;
|
|
38
|
+
}
|
|
39
|
+
function validateArchive(value) {
|
|
40
|
+
const archive = object(value);
|
|
41
|
+
uuid(archive.id);
|
|
42
|
+
decode(archive.public_key, 65);
|
|
43
|
+
decode(archive.certificate, 64);
|
|
44
|
+
return { id: archive.id, public_key: archive.public_key, certificate: archive.certificate };
|
|
45
|
+
}
|
|
46
|
+
function validateConfig(value) {
|
|
47
|
+
const config = object(value);
|
|
48
|
+
for (const field of ["api_url", "user_id", "source_id", "source_key", "identity_public_key", "sender_private_key"]) {
|
|
49
|
+
if (typeof config[field] !== "string" || !config[field] || /[\r\n]/.test(config[field])) throw new Error(`Missing or invalid config field: ${field}`);
|
|
50
|
+
}
|
|
51
|
+
uuid(config.user_id);
|
|
52
|
+
uuid(config.source_id);
|
|
53
|
+
if (!/^[\x21-\x7e]{1,2048}$/.test(config.source_key)) throw new Error("Invalid source credential");
|
|
54
|
+
decode(config.identity_public_key, 65);
|
|
55
|
+
decode(config.sender_private_key, 32);
|
|
56
|
+
return {
|
|
57
|
+
api_url: validateAPIURL(config.api_url),
|
|
58
|
+
user_id: config.user_id,
|
|
59
|
+
source_id: config.source_id,
|
|
60
|
+
source_key: config.source_key,
|
|
61
|
+
identity_public_key: config.identity_public_key,
|
|
62
|
+
sender_private_key: config.sender_private_key,
|
|
63
|
+
archive: validateArchive(config.archive)
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// node_modules/@hpke/common/esm/src/errors.js
|
|
68
|
+
var HpkeError = class extends Error {
|
|
69
|
+
constructor(e) {
|
|
70
|
+
let message;
|
|
71
|
+
if (e instanceof Error) {
|
|
72
|
+
message = e.message;
|
|
73
|
+
} else if (typeof e === "string") {
|
|
74
|
+
message = e;
|
|
75
|
+
} else {
|
|
76
|
+
message = "";
|
|
77
|
+
}
|
|
78
|
+
super(message);
|
|
79
|
+
this.name = this.constructor.name;
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
var InvalidParamError = class extends HpkeError {
|
|
83
|
+
};
|
|
84
|
+
var SerializeError = class extends HpkeError {
|
|
85
|
+
};
|
|
86
|
+
var DeserializeError = class extends HpkeError {
|
|
87
|
+
};
|
|
88
|
+
var EncapError = class extends HpkeError {
|
|
89
|
+
};
|
|
90
|
+
var DecapError = class extends HpkeError {
|
|
91
|
+
};
|
|
92
|
+
var ExportError = class extends HpkeError {
|
|
93
|
+
};
|
|
94
|
+
var SealError = class extends HpkeError {
|
|
95
|
+
};
|
|
96
|
+
var OpenError = class extends HpkeError {
|
|
97
|
+
};
|
|
98
|
+
var MessageLimitReachedError = class extends HpkeError {
|
|
99
|
+
};
|
|
100
|
+
var DeriveKeyPairError = class extends HpkeError {
|
|
101
|
+
};
|
|
102
|
+
var NotSupportedError = class extends HpkeError {
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
// node_modules/@hpke/common/esm/_dnt.shims.js
|
|
106
|
+
var dntGlobals = {};
|
|
107
|
+
var dntGlobalThis = createMergeProxy(globalThis, dntGlobals);
|
|
108
|
+
function createMergeProxy(baseObj, extObj) {
|
|
109
|
+
return new Proxy(baseObj, {
|
|
110
|
+
get(_target, prop, _receiver) {
|
|
111
|
+
if (prop in extObj) {
|
|
112
|
+
return extObj[prop];
|
|
113
|
+
} else {
|
|
114
|
+
return baseObj[prop];
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
set(_target, prop, value) {
|
|
118
|
+
if (prop in extObj) {
|
|
119
|
+
delete extObj[prop];
|
|
120
|
+
}
|
|
121
|
+
baseObj[prop] = value;
|
|
122
|
+
return true;
|
|
123
|
+
},
|
|
124
|
+
deleteProperty(_target, prop) {
|
|
125
|
+
let success = false;
|
|
126
|
+
if (prop in extObj) {
|
|
127
|
+
delete extObj[prop];
|
|
128
|
+
success = true;
|
|
129
|
+
}
|
|
130
|
+
if (prop in baseObj) {
|
|
131
|
+
delete baseObj[prop];
|
|
132
|
+
success = true;
|
|
133
|
+
}
|
|
134
|
+
return success;
|
|
135
|
+
},
|
|
136
|
+
ownKeys(_target) {
|
|
137
|
+
const baseKeys = Reflect.ownKeys(baseObj);
|
|
138
|
+
const extKeys = Reflect.ownKeys(extObj);
|
|
139
|
+
const extKeysSet = new Set(extKeys);
|
|
140
|
+
return [...baseKeys.filter((k) => !extKeysSet.has(k)), ...extKeys];
|
|
141
|
+
},
|
|
142
|
+
defineProperty(_target, prop, desc) {
|
|
143
|
+
if (prop in extObj) {
|
|
144
|
+
delete extObj[prop];
|
|
145
|
+
}
|
|
146
|
+
Reflect.defineProperty(baseObj, prop, desc);
|
|
147
|
+
return true;
|
|
148
|
+
},
|
|
149
|
+
getOwnPropertyDescriptor(_target, prop) {
|
|
150
|
+
if (prop in extObj) {
|
|
151
|
+
return Reflect.getOwnPropertyDescriptor(extObj, prop);
|
|
152
|
+
} else {
|
|
153
|
+
return Reflect.getOwnPropertyDescriptor(baseObj, prop);
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
has(_target, prop) {
|
|
157
|
+
return prop in extObj || prop in baseObj;
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// node_modules/@hpke/common/esm/src/algorithm.js
|
|
163
|
+
async function loadSubtleCrypto() {
|
|
164
|
+
if (dntGlobalThis !== void 0 && globalThis.crypto !== void 0) {
|
|
165
|
+
return globalThis.crypto.subtle;
|
|
166
|
+
}
|
|
167
|
+
try {
|
|
168
|
+
const { webcrypto } = await import("crypto");
|
|
169
|
+
return webcrypto.subtle;
|
|
170
|
+
} catch (e) {
|
|
171
|
+
throw new NotSupportedError(e);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
var NativeAlgorithm = class {
|
|
175
|
+
constructor() {
|
|
176
|
+
Object.defineProperty(this, "_api", {
|
|
177
|
+
enumerable: true,
|
|
178
|
+
configurable: true,
|
|
179
|
+
writable: true,
|
|
180
|
+
value: void 0
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
async _setup() {
|
|
184
|
+
if (this._api !== void 0) {
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
this._api = await loadSubtleCrypto();
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
// node_modules/@hpke/common/esm/src/identifiers.js
|
|
192
|
+
var Mode = {
|
|
193
|
+
Base: 0,
|
|
194
|
+
Psk: 1,
|
|
195
|
+
Auth: 2,
|
|
196
|
+
AuthPsk: 3
|
|
197
|
+
};
|
|
198
|
+
var KemId = {
|
|
199
|
+
NotAssigned: 0,
|
|
200
|
+
DhkemP256HkdfSha256: 16,
|
|
201
|
+
DhkemP384HkdfSha384: 17,
|
|
202
|
+
DhkemP521HkdfSha512: 18,
|
|
203
|
+
DhkemSecp256k1HkdfSha256: 19,
|
|
204
|
+
DhkemX25519HkdfSha256: 32,
|
|
205
|
+
DhkemX448HkdfSha512: 33,
|
|
206
|
+
HybridkemX25519Kyber768: 48,
|
|
207
|
+
MlKem512: 64,
|
|
208
|
+
MlKem768: 65,
|
|
209
|
+
MlKem1024: 66,
|
|
210
|
+
XWing: 25722
|
|
211
|
+
};
|
|
212
|
+
var KdfId = {
|
|
213
|
+
HkdfSha256: 1,
|
|
214
|
+
HkdfSha384: 2,
|
|
215
|
+
HkdfSha512: 3,
|
|
216
|
+
Sha3256: 4,
|
|
217
|
+
Sha3384: 5,
|
|
218
|
+
Sha3512: 6,
|
|
219
|
+
Shake128: 16,
|
|
220
|
+
Shake256: 17,
|
|
221
|
+
TurboShake128: 18,
|
|
222
|
+
TurboShake256: 19
|
|
223
|
+
};
|
|
224
|
+
var AeadId = {
|
|
225
|
+
Aes128Gcm: 1,
|
|
226
|
+
Aes256Gcm: 2,
|
|
227
|
+
Chacha20Poly1305: 3,
|
|
228
|
+
ExportOnly: 65535
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
// node_modules/@hpke/common/esm/src/consts.js
|
|
232
|
+
var INPUT_LENGTH_LIMIT = 8192;
|
|
233
|
+
var INFO_LENGTH_LIMIT = 268435456;
|
|
234
|
+
var MINIMUM_PSK_LENGTH = 32;
|
|
235
|
+
var EMPTY = /* @__PURE__ */ new Uint8Array(0);
|
|
236
|
+
var BYTE_TO_BIGINT_256 = /* @__PURE__ */ (() => {
|
|
237
|
+
const out = new Array(256);
|
|
238
|
+
let i = 0;
|
|
239
|
+
let value = 0n;
|
|
240
|
+
while (i < 256) {
|
|
241
|
+
out[i] = value;
|
|
242
|
+
i++;
|
|
243
|
+
value += 1n;
|
|
244
|
+
}
|
|
245
|
+
return out;
|
|
246
|
+
})();
|
|
247
|
+
|
|
248
|
+
// node_modules/@hpke/common/esm/src/interfaces/kemInterface.js
|
|
249
|
+
var SUITE_ID_HEADER_KEM = /* @__PURE__ */ new Uint8Array([
|
|
250
|
+
75,
|
|
251
|
+
69,
|
|
252
|
+
77,
|
|
253
|
+
0,
|
|
254
|
+
0
|
|
255
|
+
]);
|
|
256
|
+
|
|
257
|
+
// node_modules/@hpke/common/esm/src/kdfs/hkdf.js
|
|
258
|
+
var HPKE_VERSION = /* @__PURE__ */ new Uint8Array([
|
|
259
|
+
72,
|
|
260
|
+
80,
|
|
261
|
+
75,
|
|
262
|
+
69,
|
|
263
|
+
45,
|
|
264
|
+
118,
|
|
265
|
+
49
|
|
266
|
+
]);
|
|
267
|
+
function toUint8Array(input) {
|
|
268
|
+
return new Uint8Array(toArrayBuffer(input));
|
|
269
|
+
}
|
|
270
|
+
function toArrayBuffer(input) {
|
|
271
|
+
if (input instanceof ArrayBuffer) {
|
|
272
|
+
return input;
|
|
273
|
+
}
|
|
274
|
+
if (ArrayBuffer.isView(input)) {
|
|
275
|
+
return new Uint8Array(input.buffer, input.byteOffset, input.byteLength).slice().buffer;
|
|
276
|
+
}
|
|
277
|
+
return new Uint8Array(input).slice().buffer;
|
|
278
|
+
}
|
|
279
|
+
var HkdfNative = class extends NativeAlgorithm {
|
|
280
|
+
constructor() {
|
|
281
|
+
super();
|
|
282
|
+
Object.defineProperty(this, "id", {
|
|
283
|
+
enumerable: true,
|
|
284
|
+
configurable: true,
|
|
285
|
+
writable: true,
|
|
286
|
+
value: KdfId.HkdfSha256
|
|
287
|
+
});
|
|
288
|
+
Object.defineProperty(this, "hashSize", {
|
|
289
|
+
enumerable: true,
|
|
290
|
+
configurable: true,
|
|
291
|
+
writable: true,
|
|
292
|
+
value: 0
|
|
293
|
+
});
|
|
294
|
+
Object.defineProperty(this, "_suiteId", {
|
|
295
|
+
enumerable: true,
|
|
296
|
+
configurable: true,
|
|
297
|
+
writable: true,
|
|
298
|
+
value: EMPTY
|
|
299
|
+
});
|
|
300
|
+
Object.defineProperty(this, "algHash", {
|
|
301
|
+
enumerable: true,
|
|
302
|
+
configurable: true,
|
|
303
|
+
writable: true,
|
|
304
|
+
value: {
|
|
305
|
+
name: "HMAC",
|
|
306
|
+
hash: "SHA-256",
|
|
307
|
+
length: 256
|
|
308
|
+
}
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
init(suiteId) {
|
|
312
|
+
this._suiteId = suiteId;
|
|
313
|
+
}
|
|
314
|
+
buildLabeledIkm(label, ikm) {
|
|
315
|
+
this._checkInit();
|
|
316
|
+
const ret = new Uint8Array(7 + this._suiteId.byteLength + label.byteLength + ikm.byteLength);
|
|
317
|
+
ret.set(HPKE_VERSION, 0);
|
|
318
|
+
ret.set(this._suiteId, 7);
|
|
319
|
+
ret.set(label, 7 + this._suiteId.byteLength);
|
|
320
|
+
ret.set(ikm, 7 + this._suiteId.byteLength + label.byteLength);
|
|
321
|
+
return ret;
|
|
322
|
+
}
|
|
323
|
+
buildLabeledInfo(label, info, len) {
|
|
324
|
+
this._checkInit();
|
|
325
|
+
const ret = new Uint8Array(9 + this._suiteId.byteLength + label.byteLength + info.byteLength);
|
|
326
|
+
ret.set(new Uint8Array([0, len]), 0);
|
|
327
|
+
ret.set(HPKE_VERSION, 2);
|
|
328
|
+
ret.set(this._suiteId, 9);
|
|
329
|
+
ret.set(label, 9 + this._suiteId.byteLength);
|
|
330
|
+
ret.set(info, 9 + this._suiteId.byteLength + label.byteLength);
|
|
331
|
+
return ret;
|
|
332
|
+
}
|
|
333
|
+
async extract(salt, ikm) {
|
|
334
|
+
await this._setup();
|
|
335
|
+
const saltBuf = salt.byteLength === 0 ? new ArrayBuffer(this.hashSize) : toArrayBuffer(salt);
|
|
336
|
+
if (saltBuf.byteLength !== this.hashSize) {
|
|
337
|
+
throw new InvalidParamError("The salt length must be the same as the hashSize");
|
|
338
|
+
}
|
|
339
|
+
const ikmBuf = toArrayBuffer(ikm);
|
|
340
|
+
const key = await this._api.importKey("raw", saltBuf, this.algHash, false, [
|
|
341
|
+
"sign"
|
|
342
|
+
]);
|
|
343
|
+
return await this._api.sign("HMAC", key, ikmBuf);
|
|
344
|
+
}
|
|
345
|
+
async expand(prk, info, len) {
|
|
346
|
+
await this._setup();
|
|
347
|
+
const prkBuf = toArrayBuffer(prk);
|
|
348
|
+
const key = await this._api.importKey("raw", prkBuf, this.algHash, false, [
|
|
349
|
+
"sign"
|
|
350
|
+
]);
|
|
351
|
+
const okm = new ArrayBuffer(len);
|
|
352
|
+
const okmBytes = new Uint8Array(okm);
|
|
353
|
+
let prev = EMPTY;
|
|
354
|
+
const mid = toUint8Array(info);
|
|
355
|
+
const tail = new Uint8Array(1);
|
|
356
|
+
if (len > 255 * this.hashSize) {
|
|
357
|
+
throw new Error("Entropy limit reached");
|
|
358
|
+
}
|
|
359
|
+
const tmp = new Uint8Array(this.hashSize + mid.length + 1);
|
|
360
|
+
for (let i = 1, cur = 0; cur < okmBytes.length; i++) {
|
|
361
|
+
tail[0] = i;
|
|
362
|
+
tmp.set(prev, 0);
|
|
363
|
+
tmp.set(mid, prev.length);
|
|
364
|
+
tmp.set(tail, prev.length + mid.length);
|
|
365
|
+
prev = new Uint8Array(await this._api.sign("HMAC", key, tmp.slice(0, prev.length + mid.length + 1)));
|
|
366
|
+
if (okmBytes.length - cur >= prev.length) {
|
|
367
|
+
okmBytes.set(prev, cur);
|
|
368
|
+
cur += prev.length;
|
|
369
|
+
} else {
|
|
370
|
+
okmBytes.set(prev.slice(0, okmBytes.length - cur), cur);
|
|
371
|
+
cur += okmBytes.length - cur;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
return okm;
|
|
375
|
+
}
|
|
376
|
+
async extractAndExpand(salt, ikm, info, len) {
|
|
377
|
+
await this._setup();
|
|
378
|
+
const ikmBuf = toArrayBuffer(ikm);
|
|
379
|
+
const baseKey = await this._api.importKey("raw", ikmBuf, "HKDF", false, ["deriveBits"]);
|
|
380
|
+
return await this._api.deriveBits({
|
|
381
|
+
name: "HKDF",
|
|
382
|
+
hash: this.algHash.hash,
|
|
383
|
+
salt: toArrayBuffer(salt),
|
|
384
|
+
info: toArrayBuffer(info)
|
|
385
|
+
}, baseKey, len * 8);
|
|
386
|
+
}
|
|
387
|
+
async labeledExtract(salt, label, ikm) {
|
|
388
|
+
return await this.extract(salt, this.buildLabeledIkm(label, ikm));
|
|
389
|
+
}
|
|
390
|
+
async labeledExpand(prk, label, info, len) {
|
|
391
|
+
return await this.expand(prk, this.buildLabeledInfo(label, info, len), len);
|
|
392
|
+
}
|
|
393
|
+
_checkInit() {
|
|
394
|
+
if (this._suiteId === EMPTY) {
|
|
395
|
+
throw new Error("Not initialized. Call init()");
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
};
|
|
399
|
+
var HkdfSha256Native = class extends HkdfNative {
|
|
400
|
+
constructor() {
|
|
401
|
+
super(...arguments);
|
|
402
|
+
Object.defineProperty(this, "id", {
|
|
403
|
+
enumerable: true,
|
|
404
|
+
configurable: true,
|
|
405
|
+
writable: true,
|
|
406
|
+
value: KdfId.HkdfSha256
|
|
407
|
+
});
|
|
408
|
+
Object.defineProperty(this, "hashSize", {
|
|
409
|
+
enumerable: true,
|
|
410
|
+
configurable: true,
|
|
411
|
+
writable: true,
|
|
412
|
+
value: 32
|
|
413
|
+
});
|
|
414
|
+
Object.defineProperty(this, "algHash", {
|
|
415
|
+
enumerable: true,
|
|
416
|
+
configurable: true,
|
|
417
|
+
writable: true,
|
|
418
|
+
value: {
|
|
419
|
+
name: "HMAC",
|
|
420
|
+
hash: "SHA-256",
|
|
421
|
+
length: 256
|
|
422
|
+
}
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
};
|
|
426
|
+
|
|
427
|
+
// node_modules/@hpke/common/esm/src/utils/misc.js
|
|
428
|
+
var isCryptoKeyPair = (x) => typeof x === "object" && x !== null && typeof x.privateKey === "object" && typeof x.publicKey === "object";
|
|
429
|
+
function i2Osp(n, w) {
|
|
430
|
+
if (w <= 0) {
|
|
431
|
+
throw new Error("i2Osp: too small size");
|
|
432
|
+
}
|
|
433
|
+
if (n >= 256 ** w) {
|
|
434
|
+
throw new Error("i2Osp: too large integer");
|
|
435
|
+
}
|
|
436
|
+
const ret = new Uint8Array(w);
|
|
437
|
+
for (let i = 0; i < w && n; i++) {
|
|
438
|
+
ret[w - (i + 1)] = n % 256;
|
|
439
|
+
n = Math.floor(n / 256);
|
|
440
|
+
}
|
|
441
|
+
return ret;
|
|
442
|
+
}
|
|
443
|
+
function concat(a, b) {
|
|
444
|
+
const ret = new Uint8Array(a.length + b.length);
|
|
445
|
+
ret.set(a, 0);
|
|
446
|
+
ret.set(b, a.length);
|
|
447
|
+
return ret;
|
|
448
|
+
}
|
|
449
|
+
function base64UrlToBytes(v) {
|
|
450
|
+
const base642 = v.replace(/-/g, "+").replace(/_/g, "/");
|
|
451
|
+
const byteString = atob(base642);
|
|
452
|
+
const ret = new Uint8Array(byteString.length);
|
|
453
|
+
for (let i = 0; i < byteString.length; i++) {
|
|
454
|
+
ret[i] = byteString.charCodeAt(i);
|
|
455
|
+
}
|
|
456
|
+
return ret;
|
|
457
|
+
}
|
|
458
|
+
function xor(a, b) {
|
|
459
|
+
if (a.byteLength !== b.byteLength) {
|
|
460
|
+
throw new Error("xor: different length inputs");
|
|
461
|
+
}
|
|
462
|
+
const buf = new Uint8Array(a.byteLength);
|
|
463
|
+
for (let i = 0; i < a.byteLength; i++) {
|
|
464
|
+
buf[i] = a[i] ^ b[i];
|
|
465
|
+
}
|
|
466
|
+
return buf;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
// node_modules/@hpke/common/esm/src/kems/dhkem.js
|
|
470
|
+
var LABEL_EAE_PRK = /* @__PURE__ */ new Uint8Array([
|
|
471
|
+
101,
|
|
472
|
+
97,
|
|
473
|
+
101,
|
|
474
|
+
95,
|
|
475
|
+
112,
|
|
476
|
+
114,
|
|
477
|
+
107
|
|
478
|
+
]);
|
|
479
|
+
var LABEL_SHARED_SECRET = /* @__PURE__ */ new Uint8Array([
|
|
480
|
+
115,
|
|
481
|
+
104,
|
|
482
|
+
97,
|
|
483
|
+
114,
|
|
484
|
+
101,
|
|
485
|
+
100,
|
|
486
|
+
95,
|
|
487
|
+
115,
|
|
488
|
+
101,
|
|
489
|
+
99,
|
|
490
|
+
114,
|
|
491
|
+
101,
|
|
492
|
+
116
|
|
493
|
+
]);
|
|
494
|
+
function concat3(a, b, c) {
|
|
495
|
+
const ret = new Uint8Array(a.length + b.length + c.length);
|
|
496
|
+
ret.set(a, 0);
|
|
497
|
+
ret.set(b, a.length);
|
|
498
|
+
ret.set(c, a.length + b.length);
|
|
499
|
+
return ret;
|
|
500
|
+
}
|
|
501
|
+
var Dhkem = class {
|
|
502
|
+
constructor(id, prim, kdf) {
|
|
503
|
+
Object.defineProperty(this, "id", {
|
|
504
|
+
enumerable: true,
|
|
505
|
+
configurable: true,
|
|
506
|
+
writable: true,
|
|
507
|
+
value: void 0
|
|
508
|
+
});
|
|
509
|
+
Object.defineProperty(this, "secretSize", {
|
|
510
|
+
enumerable: true,
|
|
511
|
+
configurable: true,
|
|
512
|
+
writable: true,
|
|
513
|
+
value: 0
|
|
514
|
+
});
|
|
515
|
+
Object.defineProperty(this, "encSize", {
|
|
516
|
+
enumerable: true,
|
|
517
|
+
configurable: true,
|
|
518
|
+
writable: true,
|
|
519
|
+
value: 0
|
|
520
|
+
});
|
|
521
|
+
Object.defineProperty(this, "publicKeySize", {
|
|
522
|
+
enumerable: true,
|
|
523
|
+
configurable: true,
|
|
524
|
+
writable: true,
|
|
525
|
+
value: 0
|
|
526
|
+
});
|
|
527
|
+
Object.defineProperty(this, "privateKeySize", {
|
|
528
|
+
enumerable: true,
|
|
529
|
+
configurable: true,
|
|
530
|
+
writable: true,
|
|
531
|
+
value: 0
|
|
532
|
+
});
|
|
533
|
+
Object.defineProperty(this, "_prim", {
|
|
534
|
+
enumerable: true,
|
|
535
|
+
configurable: true,
|
|
536
|
+
writable: true,
|
|
537
|
+
value: void 0
|
|
538
|
+
});
|
|
539
|
+
Object.defineProperty(this, "_kdf", {
|
|
540
|
+
enumerable: true,
|
|
541
|
+
configurable: true,
|
|
542
|
+
writable: true,
|
|
543
|
+
value: void 0
|
|
544
|
+
});
|
|
545
|
+
this.id = id;
|
|
546
|
+
this._prim = prim;
|
|
547
|
+
this._kdf = kdf;
|
|
548
|
+
const suiteId = new Uint8Array(SUITE_ID_HEADER_KEM);
|
|
549
|
+
suiteId.set(i2Osp(this.id, 2), 3);
|
|
550
|
+
this._kdf.init(suiteId);
|
|
551
|
+
}
|
|
552
|
+
async serializePublicKey(key) {
|
|
553
|
+
return await this._prim.serializePublicKey(key);
|
|
554
|
+
}
|
|
555
|
+
async deserializePublicKey(key) {
|
|
556
|
+
return await this._prim.deserializePublicKey(toArrayBuffer(key));
|
|
557
|
+
}
|
|
558
|
+
async serializePrivateKey(key) {
|
|
559
|
+
return await this._prim.serializePrivateKey(key);
|
|
560
|
+
}
|
|
561
|
+
async deserializePrivateKey(key) {
|
|
562
|
+
return await this._prim.deserializePrivateKey(toArrayBuffer(key));
|
|
563
|
+
}
|
|
564
|
+
async importKey(format, key, isPublic = true) {
|
|
565
|
+
return await this._prim.importKey(format, key, isPublic);
|
|
566
|
+
}
|
|
567
|
+
async generateKeyPair() {
|
|
568
|
+
return await this._prim.generateKeyPair();
|
|
569
|
+
}
|
|
570
|
+
async deriveKeyPair(ikm) {
|
|
571
|
+
const rawIkm = toArrayBuffer(ikm);
|
|
572
|
+
if (rawIkm.byteLength > INPUT_LENGTH_LIMIT) {
|
|
573
|
+
throw new InvalidParamError("Too long ikm");
|
|
574
|
+
}
|
|
575
|
+
return await this._prim.deriveKeyPair(rawIkm);
|
|
576
|
+
}
|
|
577
|
+
async encap(params) {
|
|
578
|
+
let ke;
|
|
579
|
+
if (params.ekm === void 0) {
|
|
580
|
+
ke = await this.generateKeyPair();
|
|
581
|
+
} else if (isCryptoKeyPair(params.ekm)) {
|
|
582
|
+
ke = params.ekm;
|
|
583
|
+
} else {
|
|
584
|
+
ke = await this.deriveKeyPair(params.ekm);
|
|
585
|
+
}
|
|
586
|
+
const enc = await this._prim.serializePublicKey(ke.publicKey);
|
|
587
|
+
const pkrm = await this._prim.serializePublicKey(params.recipientPublicKey);
|
|
588
|
+
try {
|
|
589
|
+
let dh;
|
|
590
|
+
if (params.senderKey === void 0) {
|
|
591
|
+
dh = new Uint8Array(await this._prim.dh(ke.privateKey, params.recipientPublicKey));
|
|
592
|
+
} else {
|
|
593
|
+
const sks = isCryptoKeyPair(params.senderKey) ? params.senderKey.privateKey : params.senderKey;
|
|
594
|
+
const dh1 = new Uint8Array(await this._prim.dh(ke.privateKey, params.recipientPublicKey));
|
|
595
|
+
const dh2 = new Uint8Array(await this._prim.dh(sks, params.recipientPublicKey));
|
|
596
|
+
dh = concat(dh1, dh2);
|
|
597
|
+
}
|
|
598
|
+
let kemContext;
|
|
599
|
+
if (params.senderKey === void 0) {
|
|
600
|
+
kemContext = concat(new Uint8Array(enc), new Uint8Array(pkrm));
|
|
601
|
+
} else {
|
|
602
|
+
const pks = isCryptoKeyPair(params.senderKey) ? params.senderKey.publicKey : await this._prim.derivePublicKey(params.senderKey);
|
|
603
|
+
const pksm = await this._prim.serializePublicKey(pks);
|
|
604
|
+
kemContext = concat3(new Uint8Array(enc), new Uint8Array(pkrm), new Uint8Array(pksm));
|
|
605
|
+
}
|
|
606
|
+
const sharedSecret = await this._generateSharedSecret(dh, kemContext);
|
|
607
|
+
return {
|
|
608
|
+
enc,
|
|
609
|
+
sharedSecret
|
|
610
|
+
};
|
|
611
|
+
} catch (e) {
|
|
612
|
+
throw new EncapError(e);
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
async decap(params) {
|
|
616
|
+
const enc = toArrayBuffer(params.enc);
|
|
617
|
+
const pke = await this._prim.deserializePublicKey(enc);
|
|
618
|
+
const skr = isCryptoKeyPair(params.recipientKey) ? params.recipientKey.privateKey : params.recipientKey;
|
|
619
|
+
const pkr = isCryptoKeyPair(params.recipientKey) ? params.recipientKey.publicKey : await this._prim.derivePublicKey(params.recipientKey);
|
|
620
|
+
const pkrm = await this._prim.serializePublicKey(pkr);
|
|
621
|
+
try {
|
|
622
|
+
let dh;
|
|
623
|
+
if (params.senderPublicKey === void 0) {
|
|
624
|
+
dh = new Uint8Array(await this._prim.dh(skr, pke));
|
|
625
|
+
} else {
|
|
626
|
+
const dh1 = new Uint8Array(await this._prim.dh(skr, pke));
|
|
627
|
+
const dh2 = new Uint8Array(await this._prim.dh(skr, params.senderPublicKey));
|
|
628
|
+
dh = concat(dh1, dh2);
|
|
629
|
+
}
|
|
630
|
+
let kemContext;
|
|
631
|
+
if (params.senderPublicKey === void 0) {
|
|
632
|
+
kemContext = concat(new Uint8Array(enc), new Uint8Array(pkrm));
|
|
633
|
+
} else {
|
|
634
|
+
const pksm = await this._prim.serializePublicKey(params.senderPublicKey);
|
|
635
|
+
kemContext = new Uint8Array(enc.byteLength + pkrm.byteLength + pksm.byteLength);
|
|
636
|
+
kemContext.set(new Uint8Array(enc), 0);
|
|
637
|
+
kemContext.set(new Uint8Array(pkrm), enc.byteLength);
|
|
638
|
+
kemContext.set(new Uint8Array(pksm), enc.byteLength + pkrm.byteLength);
|
|
639
|
+
}
|
|
640
|
+
return await this._generateSharedSecret(dh, kemContext);
|
|
641
|
+
} catch (e) {
|
|
642
|
+
throw new DecapError(e);
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
async _generateSharedSecret(dh, kemContext) {
|
|
646
|
+
const labeledIkm = this._kdf.buildLabeledIkm(LABEL_EAE_PRK, dh);
|
|
647
|
+
const labeledInfo = this._kdf.buildLabeledInfo(LABEL_SHARED_SECRET, kemContext, this.secretSize);
|
|
648
|
+
return await this._kdf.extractAndExpand(EMPTY, labeledIkm, labeledInfo, this.secretSize);
|
|
649
|
+
}
|
|
650
|
+
};
|
|
651
|
+
|
|
652
|
+
// node_modules/@hpke/common/esm/src/interfaces/dhkemPrimitives.js
|
|
653
|
+
var KEM_USAGES = ["deriveBits"];
|
|
654
|
+
var LABEL_DKP_PRK = /* @__PURE__ */ new Uint8Array([
|
|
655
|
+
100,
|
|
656
|
+
107,
|
|
657
|
+
112,
|
|
658
|
+
95,
|
|
659
|
+
112,
|
|
660
|
+
114,
|
|
661
|
+
107
|
|
662
|
+
]);
|
|
663
|
+
|
|
664
|
+
// node_modules/@hpke/common/esm/src/utils/bignum.js
|
|
665
|
+
var Bignum = class {
|
|
666
|
+
constructor(size) {
|
|
667
|
+
Object.defineProperty(this, "_num", {
|
|
668
|
+
enumerable: true,
|
|
669
|
+
configurable: true,
|
|
670
|
+
writable: true,
|
|
671
|
+
value: void 0
|
|
672
|
+
});
|
|
673
|
+
this._num = new Uint8Array(size);
|
|
674
|
+
}
|
|
675
|
+
val() {
|
|
676
|
+
return this._num;
|
|
677
|
+
}
|
|
678
|
+
reset() {
|
|
679
|
+
this._num.fill(0);
|
|
680
|
+
}
|
|
681
|
+
set(src) {
|
|
682
|
+
if (src.length !== this._num.length) {
|
|
683
|
+
throw new Error("Bignum.set: invalid argument");
|
|
684
|
+
}
|
|
685
|
+
this._num.set(src);
|
|
686
|
+
}
|
|
687
|
+
isZero() {
|
|
688
|
+
for (let i = 0; i < this._num.length; i++) {
|
|
689
|
+
if (this._num[i] !== 0) {
|
|
690
|
+
return false;
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
return true;
|
|
694
|
+
}
|
|
695
|
+
lessThan(v) {
|
|
696
|
+
if (v.length !== this._num.length) {
|
|
697
|
+
throw new Error("Bignum.lessThan: invalid argument");
|
|
698
|
+
}
|
|
699
|
+
for (let i = 0; i < this._num.length; i++) {
|
|
700
|
+
if (this._num[i] < v[i]) {
|
|
701
|
+
return true;
|
|
702
|
+
}
|
|
703
|
+
if (this._num[i] > v[i]) {
|
|
704
|
+
return false;
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
return false;
|
|
708
|
+
}
|
|
709
|
+
};
|
|
710
|
+
|
|
711
|
+
// node_modules/@hpke/common/esm/src/kems/dhkemPrimitives/ec.js
|
|
712
|
+
var LABEL_CANDIDATE = /* @__PURE__ */ new Uint8Array([
|
|
713
|
+
99,
|
|
714
|
+
97,
|
|
715
|
+
110,
|
|
716
|
+
100,
|
|
717
|
+
105,
|
|
718
|
+
100,
|
|
719
|
+
97,
|
|
720
|
+
116,
|
|
721
|
+
101
|
|
722
|
+
]);
|
|
723
|
+
var ORDER_P_256 = /* @__PURE__ */ new Uint8Array([
|
|
724
|
+
255,
|
|
725
|
+
255,
|
|
726
|
+
255,
|
|
727
|
+
255,
|
|
728
|
+
0,
|
|
729
|
+
0,
|
|
730
|
+
0,
|
|
731
|
+
0,
|
|
732
|
+
255,
|
|
733
|
+
255,
|
|
734
|
+
255,
|
|
735
|
+
255,
|
|
736
|
+
255,
|
|
737
|
+
255,
|
|
738
|
+
255,
|
|
739
|
+
255,
|
|
740
|
+
188,
|
|
741
|
+
230,
|
|
742
|
+
250,
|
|
743
|
+
173,
|
|
744
|
+
167,
|
|
745
|
+
23,
|
|
746
|
+
158,
|
|
747
|
+
132,
|
|
748
|
+
243,
|
|
749
|
+
185,
|
|
750
|
+
202,
|
|
751
|
+
194,
|
|
752
|
+
252,
|
|
753
|
+
99,
|
|
754
|
+
37,
|
|
755
|
+
81
|
|
756
|
+
]);
|
|
757
|
+
var ORDER_P_384 = /* @__PURE__ */ new Uint8Array([
|
|
758
|
+
255,
|
|
759
|
+
255,
|
|
760
|
+
255,
|
|
761
|
+
255,
|
|
762
|
+
255,
|
|
763
|
+
255,
|
|
764
|
+
255,
|
|
765
|
+
255,
|
|
766
|
+
255,
|
|
767
|
+
255,
|
|
768
|
+
255,
|
|
769
|
+
255,
|
|
770
|
+
255,
|
|
771
|
+
255,
|
|
772
|
+
255,
|
|
773
|
+
255,
|
|
774
|
+
255,
|
|
775
|
+
255,
|
|
776
|
+
255,
|
|
777
|
+
255,
|
|
778
|
+
255,
|
|
779
|
+
255,
|
|
780
|
+
255,
|
|
781
|
+
255,
|
|
782
|
+
199,
|
|
783
|
+
99,
|
|
784
|
+
77,
|
|
785
|
+
129,
|
|
786
|
+
244,
|
|
787
|
+
55,
|
|
788
|
+
45,
|
|
789
|
+
223,
|
|
790
|
+
88,
|
|
791
|
+
26,
|
|
792
|
+
13,
|
|
793
|
+
178,
|
|
794
|
+
72,
|
|
795
|
+
176,
|
|
796
|
+
167,
|
|
797
|
+
122,
|
|
798
|
+
236,
|
|
799
|
+
236,
|
|
800
|
+
25,
|
|
801
|
+
106,
|
|
802
|
+
204,
|
|
803
|
+
197,
|
|
804
|
+
41,
|
|
805
|
+
115
|
|
806
|
+
]);
|
|
807
|
+
var ORDER_P_521 = /* @__PURE__ */ new Uint8Array([
|
|
808
|
+
1,
|
|
809
|
+
255,
|
|
810
|
+
255,
|
|
811
|
+
255,
|
|
812
|
+
255,
|
|
813
|
+
255,
|
|
814
|
+
255,
|
|
815
|
+
255,
|
|
816
|
+
255,
|
|
817
|
+
255,
|
|
818
|
+
255,
|
|
819
|
+
255,
|
|
820
|
+
255,
|
|
821
|
+
255,
|
|
822
|
+
255,
|
|
823
|
+
255,
|
|
824
|
+
255,
|
|
825
|
+
255,
|
|
826
|
+
255,
|
|
827
|
+
255,
|
|
828
|
+
255,
|
|
829
|
+
255,
|
|
830
|
+
255,
|
|
831
|
+
255,
|
|
832
|
+
255,
|
|
833
|
+
255,
|
|
834
|
+
255,
|
|
835
|
+
255,
|
|
836
|
+
255,
|
|
837
|
+
255,
|
|
838
|
+
255,
|
|
839
|
+
255,
|
|
840
|
+
255,
|
|
841
|
+
250,
|
|
842
|
+
81,
|
|
843
|
+
134,
|
|
844
|
+
135,
|
|
845
|
+
131,
|
|
846
|
+
191,
|
|
847
|
+
47,
|
|
848
|
+
150,
|
|
849
|
+
107,
|
|
850
|
+
127,
|
|
851
|
+
204,
|
|
852
|
+
1,
|
|
853
|
+
72,
|
|
854
|
+
247,
|
|
855
|
+
9,
|
|
856
|
+
165,
|
|
857
|
+
208,
|
|
858
|
+
59,
|
|
859
|
+
181,
|
|
860
|
+
201,
|
|
861
|
+
184,
|
|
862
|
+
137,
|
|
863
|
+
156,
|
|
864
|
+
71,
|
|
865
|
+
174,
|
|
866
|
+
187,
|
|
867
|
+
111,
|
|
868
|
+
183,
|
|
869
|
+
30,
|
|
870
|
+
145,
|
|
871
|
+
56,
|
|
872
|
+
100,
|
|
873
|
+
9
|
|
874
|
+
]);
|
|
875
|
+
var PKCS8_ALG_ID_P_256 = /* @__PURE__ */ new Uint8Array([
|
|
876
|
+
48,
|
|
877
|
+
65,
|
|
878
|
+
2,
|
|
879
|
+
1,
|
|
880
|
+
0,
|
|
881
|
+
48,
|
|
882
|
+
19,
|
|
883
|
+
6,
|
|
884
|
+
7,
|
|
885
|
+
42,
|
|
886
|
+
134,
|
|
887
|
+
72,
|
|
888
|
+
206,
|
|
889
|
+
61,
|
|
890
|
+
2,
|
|
891
|
+
1,
|
|
892
|
+
6,
|
|
893
|
+
8,
|
|
894
|
+
42,
|
|
895
|
+
134,
|
|
896
|
+
72,
|
|
897
|
+
206,
|
|
898
|
+
61,
|
|
899
|
+
3,
|
|
900
|
+
1,
|
|
901
|
+
7,
|
|
902
|
+
4,
|
|
903
|
+
39,
|
|
904
|
+
48,
|
|
905
|
+
37,
|
|
906
|
+
2,
|
|
907
|
+
1,
|
|
908
|
+
1,
|
|
909
|
+
4,
|
|
910
|
+
32
|
|
911
|
+
]);
|
|
912
|
+
var PKCS8_ALG_ID_P_384 = /* @__PURE__ */ new Uint8Array([
|
|
913
|
+
48,
|
|
914
|
+
78,
|
|
915
|
+
2,
|
|
916
|
+
1,
|
|
917
|
+
0,
|
|
918
|
+
48,
|
|
919
|
+
16,
|
|
920
|
+
6,
|
|
921
|
+
7,
|
|
922
|
+
42,
|
|
923
|
+
134,
|
|
924
|
+
72,
|
|
925
|
+
206,
|
|
926
|
+
61,
|
|
927
|
+
2,
|
|
928
|
+
1,
|
|
929
|
+
6,
|
|
930
|
+
5,
|
|
931
|
+
43,
|
|
932
|
+
129,
|
|
933
|
+
4,
|
|
934
|
+
0,
|
|
935
|
+
34,
|
|
936
|
+
4,
|
|
937
|
+
55,
|
|
938
|
+
48,
|
|
939
|
+
53,
|
|
940
|
+
2,
|
|
941
|
+
1,
|
|
942
|
+
1,
|
|
943
|
+
4,
|
|
944
|
+
48
|
|
945
|
+
]);
|
|
946
|
+
var PKCS8_ALG_ID_P_521 = /* @__PURE__ */ new Uint8Array([
|
|
947
|
+
48,
|
|
948
|
+
96,
|
|
949
|
+
2,
|
|
950
|
+
1,
|
|
951
|
+
0,
|
|
952
|
+
48,
|
|
953
|
+
16,
|
|
954
|
+
6,
|
|
955
|
+
7,
|
|
956
|
+
42,
|
|
957
|
+
134,
|
|
958
|
+
72,
|
|
959
|
+
206,
|
|
960
|
+
61,
|
|
961
|
+
2,
|
|
962
|
+
1,
|
|
963
|
+
6,
|
|
964
|
+
5,
|
|
965
|
+
43,
|
|
966
|
+
129,
|
|
967
|
+
4,
|
|
968
|
+
0,
|
|
969
|
+
35,
|
|
970
|
+
4,
|
|
971
|
+
73,
|
|
972
|
+
48,
|
|
973
|
+
71,
|
|
974
|
+
2,
|
|
975
|
+
1,
|
|
976
|
+
1,
|
|
977
|
+
4,
|
|
978
|
+
66
|
|
979
|
+
]);
|
|
980
|
+
var EC_P_256_PARAMS = {
|
|
981
|
+
p: 0xffffffff00000001000000000000000000000000ffffffffffffffffffffffffn,
|
|
982
|
+
b: 0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604bn,
|
|
983
|
+
gx: 0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296n,
|
|
984
|
+
gy: 0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5n,
|
|
985
|
+
coordinateSize: 32
|
|
986
|
+
};
|
|
987
|
+
var EC_P_384_PARAMS = {
|
|
988
|
+
p: 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffffn,
|
|
989
|
+
b: 0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aefn,
|
|
990
|
+
gx: 0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7n,
|
|
991
|
+
gy: 0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5fn,
|
|
992
|
+
coordinateSize: 48
|
|
993
|
+
};
|
|
994
|
+
var EC_P_521_PARAMS = {
|
|
995
|
+
p: (1n << 521n) - 1n,
|
|
996
|
+
b: 0x0051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00n,
|
|
997
|
+
gx: 0x00c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66n,
|
|
998
|
+
gy: 0x011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650n,
|
|
999
|
+
coordinateSize: 66
|
|
1000
|
+
};
|
|
1001
|
+
function mod(a, p) {
|
|
1002
|
+
const r = a % p;
|
|
1003
|
+
return r >= 0n ? r : r + p;
|
|
1004
|
+
}
|
|
1005
|
+
function modPow(base, exponent, p) {
|
|
1006
|
+
let result = 1n;
|
|
1007
|
+
let b = mod(base, p);
|
|
1008
|
+
let e = exponent;
|
|
1009
|
+
while (e > 0n) {
|
|
1010
|
+
if ((e & 1n) === 1n) {
|
|
1011
|
+
result = mod(result * b, p);
|
|
1012
|
+
}
|
|
1013
|
+
b = mod(b * b, p);
|
|
1014
|
+
e >>= 1n;
|
|
1015
|
+
}
|
|
1016
|
+
return result;
|
|
1017
|
+
}
|
|
1018
|
+
function modSqrt(rhs, p) {
|
|
1019
|
+
const y = modPow(rhs, p + 1n >> 2n, p);
|
|
1020
|
+
if (mod(y * y, p) !== mod(rhs, p)) {
|
|
1021
|
+
throw new Error("Invalid ECDH point");
|
|
1022
|
+
}
|
|
1023
|
+
return y;
|
|
1024
|
+
}
|
|
1025
|
+
function bytesToBigInt(bytes2) {
|
|
1026
|
+
let v = 0n;
|
|
1027
|
+
for (const b of bytes2) {
|
|
1028
|
+
v = v << 8n | BYTE_TO_BIGINT_256[b];
|
|
1029
|
+
}
|
|
1030
|
+
return v;
|
|
1031
|
+
}
|
|
1032
|
+
function bigIntToBytes(v, len) {
|
|
1033
|
+
const out = new Uint8Array(len);
|
|
1034
|
+
let n = v;
|
|
1035
|
+
for (let i = len - 1; i >= 0; i--) {
|
|
1036
|
+
out[i] = Number(n & 0xffn);
|
|
1037
|
+
n >>= 8n;
|
|
1038
|
+
}
|
|
1039
|
+
if (n !== 0n) {
|
|
1040
|
+
throw new Error("Invalid coordinate length");
|
|
1041
|
+
}
|
|
1042
|
+
return out;
|
|
1043
|
+
}
|
|
1044
|
+
function buildRawUncompressedPublicKey(x, y, coordinateSize) {
|
|
1045
|
+
const out = new Uint8Array(1 + coordinateSize * 2);
|
|
1046
|
+
out[0] = 4;
|
|
1047
|
+
out.set(bigIntToBytes(x, coordinateSize), 1);
|
|
1048
|
+
out.set(bigIntToBytes(y, coordinateSize), 1 + coordinateSize);
|
|
1049
|
+
return out;
|
|
1050
|
+
}
|
|
1051
|
+
var Ec = class extends NativeAlgorithm {
|
|
1052
|
+
constructor(kem, hkdf) {
|
|
1053
|
+
super();
|
|
1054
|
+
Object.defineProperty(this, "_hkdf", {
|
|
1055
|
+
enumerable: true,
|
|
1056
|
+
configurable: true,
|
|
1057
|
+
writable: true,
|
|
1058
|
+
value: void 0
|
|
1059
|
+
});
|
|
1060
|
+
Object.defineProperty(this, "_alg", {
|
|
1061
|
+
enumerable: true,
|
|
1062
|
+
configurable: true,
|
|
1063
|
+
writable: true,
|
|
1064
|
+
value: void 0
|
|
1065
|
+
});
|
|
1066
|
+
Object.defineProperty(this, "_nPk", {
|
|
1067
|
+
enumerable: true,
|
|
1068
|
+
configurable: true,
|
|
1069
|
+
writable: true,
|
|
1070
|
+
value: void 0
|
|
1071
|
+
});
|
|
1072
|
+
Object.defineProperty(this, "_nSk", {
|
|
1073
|
+
enumerable: true,
|
|
1074
|
+
configurable: true,
|
|
1075
|
+
writable: true,
|
|
1076
|
+
value: void 0
|
|
1077
|
+
});
|
|
1078
|
+
Object.defineProperty(this, "_nDh", {
|
|
1079
|
+
enumerable: true,
|
|
1080
|
+
configurable: true,
|
|
1081
|
+
writable: true,
|
|
1082
|
+
value: void 0
|
|
1083
|
+
});
|
|
1084
|
+
Object.defineProperty(this, "_order", {
|
|
1085
|
+
enumerable: true,
|
|
1086
|
+
configurable: true,
|
|
1087
|
+
writable: true,
|
|
1088
|
+
value: void 0
|
|
1089
|
+
});
|
|
1090
|
+
Object.defineProperty(this, "_bitmask", {
|
|
1091
|
+
enumerable: true,
|
|
1092
|
+
configurable: true,
|
|
1093
|
+
writable: true,
|
|
1094
|
+
value: void 0
|
|
1095
|
+
});
|
|
1096
|
+
Object.defineProperty(this, "_pkcs8AlgId", {
|
|
1097
|
+
enumerable: true,
|
|
1098
|
+
configurable: true,
|
|
1099
|
+
writable: true,
|
|
1100
|
+
value: void 0
|
|
1101
|
+
});
|
|
1102
|
+
Object.defineProperty(this, "_curveParams", {
|
|
1103
|
+
enumerable: true,
|
|
1104
|
+
configurable: true,
|
|
1105
|
+
writable: true,
|
|
1106
|
+
value: void 0
|
|
1107
|
+
});
|
|
1108
|
+
this._hkdf = hkdf;
|
|
1109
|
+
switch (kem) {
|
|
1110
|
+
case KemId.DhkemP256HkdfSha256:
|
|
1111
|
+
this._alg = { name: "ECDH", namedCurve: "P-256" };
|
|
1112
|
+
this._nPk = 65;
|
|
1113
|
+
this._nSk = 32;
|
|
1114
|
+
this._nDh = 32;
|
|
1115
|
+
this._order = ORDER_P_256;
|
|
1116
|
+
this._bitmask = 255;
|
|
1117
|
+
this._pkcs8AlgId = PKCS8_ALG_ID_P_256;
|
|
1118
|
+
this._curveParams = EC_P_256_PARAMS;
|
|
1119
|
+
break;
|
|
1120
|
+
case KemId.DhkemP384HkdfSha384:
|
|
1121
|
+
this._alg = { name: "ECDH", namedCurve: "P-384" };
|
|
1122
|
+
this._nPk = 97;
|
|
1123
|
+
this._nSk = 48;
|
|
1124
|
+
this._nDh = 48;
|
|
1125
|
+
this._order = ORDER_P_384;
|
|
1126
|
+
this._bitmask = 255;
|
|
1127
|
+
this._pkcs8AlgId = PKCS8_ALG_ID_P_384;
|
|
1128
|
+
this._curveParams = EC_P_384_PARAMS;
|
|
1129
|
+
break;
|
|
1130
|
+
default:
|
|
1131
|
+
this._alg = { name: "ECDH", namedCurve: "P-521" };
|
|
1132
|
+
this._nPk = 133;
|
|
1133
|
+
this._nSk = 66;
|
|
1134
|
+
this._nDh = 66;
|
|
1135
|
+
this._order = ORDER_P_521;
|
|
1136
|
+
this._bitmask = 1;
|
|
1137
|
+
this._pkcs8AlgId = PKCS8_ALG_ID_P_521;
|
|
1138
|
+
this._curveParams = EC_P_521_PARAMS;
|
|
1139
|
+
break;
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1142
|
+
async serializePublicKey(key) {
|
|
1143
|
+
await this._setup();
|
|
1144
|
+
try {
|
|
1145
|
+
return await this._api.exportKey("raw", key);
|
|
1146
|
+
} catch (e) {
|
|
1147
|
+
throw new SerializeError(e);
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
async deserializePublicKey(key) {
|
|
1151
|
+
await this._setup();
|
|
1152
|
+
try {
|
|
1153
|
+
return await this._importRawKey(toArrayBuffer(key), true);
|
|
1154
|
+
} catch (e) {
|
|
1155
|
+
throw new DeserializeError(e);
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1158
|
+
async serializePrivateKey(key) {
|
|
1159
|
+
await this._setup();
|
|
1160
|
+
try {
|
|
1161
|
+
const jwk = await this._api.exportKey("jwk", key);
|
|
1162
|
+
if (!("d" in jwk)) {
|
|
1163
|
+
throw new Error("Not private key");
|
|
1164
|
+
}
|
|
1165
|
+
return base64UrlToBytes(jwk["d"]).buffer;
|
|
1166
|
+
} catch (e) {
|
|
1167
|
+
throw new SerializeError(e);
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
async deserializePrivateKey(key) {
|
|
1171
|
+
await this._setup();
|
|
1172
|
+
try {
|
|
1173
|
+
return await this._importRawKey(toArrayBuffer(key), false);
|
|
1174
|
+
} catch (e) {
|
|
1175
|
+
throw new DeserializeError(e);
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
async importKey(format, key, isPublic) {
|
|
1179
|
+
await this._setup();
|
|
1180
|
+
try {
|
|
1181
|
+
if (format === "raw") {
|
|
1182
|
+
return await this._importRawKey(key, isPublic);
|
|
1183
|
+
}
|
|
1184
|
+
if (key instanceof ArrayBuffer) {
|
|
1185
|
+
throw new Error("Invalid jwk key format");
|
|
1186
|
+
}
|
|
1187
|
+
return await this._importJWK(key, isPublic);
|
|
1188
|
+
} catch (e) {
|
|
1189
|
+
throw new DeserializeError(e);
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
async generateKeyPair() {
|
|
1193
|
+
await this._setup();
|
|
1194
|
+
try {
|
|
1195
|
+
return await this._api.generateKey(this._alg, true, KEM_USAGES);
|
|
1196
|
+
} catch (e) {
|
|
1197
|
+
throw new NotSupportedError(e);
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
async deriveKeyPair(ikm) {
|
|
1201
|
+
await this._setup();
|
|
1202
|
+
try {
|
|
1203
|
+
const rawIkm = toArrayBuffer(ikm);
|
|
1204
|
+
const dkpPrk = await this._hkdf.labeledExtract(EMPTY, LABEL_DKP_PRK, new Uint8Array(rawIkm));
|
|
1205
|
+
const bn = new Bignum(this._nSk);
|
|
1206
|
+
for (let counter = 0; bn.isZero() || !bn.lessThan(this._order); counter++) {
|
|
1207
|
+
if (counter > 255) {
|
|
1208
|
+
throw new Error("Faild to derive a key pair");
|
|
1209
|
+
}
|
|
1210
|
+
const bytes2 = new Uint8Array(await this._hkdf.labeledExpand(dkpPrk, LABEL_CANDIDATE, i2Osp(counter, 1), this._nSk));
|
|
1211
|
+
bytes2[0] = bytes2[0] & this._bitmask;
|
|
1212
|
+
bn.set(bytes2);
|
|
1213
|
+
}
|
|
1214
|
+
const sk = await this._deserializePkcs8Key(bn.val());
|
|
1215
|
+
bn.reset();
|
|
1216
|
+
return {
|
|
1217
|
+
privateKey: sk,
|
|
1218
|
+
publicKey: await this.derivePublicKey(sk)
|
|
1219
|
+
};
|
|
1220
|
+
} catch (e) {
|
|
1221
|
+
throw new DeriveKeyPairError(e);
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
async derivePublicKey(key) {
|
|
1225
|
+
await this._setup();
|
|
1226
|
+
try {
|
|
1227
|
+
const jwk = await this._api.exportKey("jwk", key);
|
|
1228
|
+
delete jwk["d"];
|
|
1229
|
+
delete jwk["key_ops"];
|
|
1230
|
+
return await this._api.importKey("jwk", jwk, this._alg, true, []);
|
|
1231
|
+
} catch {
|
|
1232
|
+
try {
|
|
1233
|
+
return await this._derivePublicKeyWithoutJwkExport(key);
|
|
1234
|
+
} catch (e) {
|
|
1235
|
+
throw new DeserializeError(e);
|
|
1236
|
+
}
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1239
|
+
async dh(sk, pk) {
|
|
1240
|
+
try {
|
|
1241
|
+
await this._setup();
|
|
1242
|
+
const bits = await this._api.deriveBits({
|
|
1243
|
+
name: "ECDH",
|
|
1244
|
+
public: pk
|
|
1245
|
+
}, sk, this._nDh * 8);
|
|
1246
|
+
return bits;
|
|
1247
|
+
} catch (e) {
|
|
1248
|
+
throw new SerializeError(e);
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
async _importRawKey(key, isPublic) {
|
|
1252
|
+
if (isPublic && key.byteLength !== this._nPk) {
|
|
1253
|
+
throw new Error("Invalid public key for the ciphersuite");
|
|
1254
|
+
}
|
|
1255
|
+
if (!isPublic && key.byteLength !== this._nSk) {
|
|
1256
|
+
throw new Error("Invalid private key for the ciphersuite");
|
|
1257
|
+
}
|
|
1258
|
+
if (isPublic) {
|
|
1259
|
+
return await this._api.importKey("raw", key, this._alg, true, []);
|
|
1260
|
+
}
|
|
1261
|
+
return await this._deserializePkcs8Key(new Uint8Array(key));
|
|
1262
|
+
}
|
|
1263
|
+
async _importJWK(key, isPublic) {
|
|
1264
|
+
if (typeof key.crv === "undefined" || key.crv !== this._alg.namedCurve) {
|
|
1265
|
+
throw new Error(`Invalid crv: ${key.crv}`);
|
|
1266
|
+
}
|
|
1267
|
+
if (isPublic) {
|
|
1268
|
+
if (typeof key.d !== "undefined") {
|
|
1269
|
+
throw new Error("Invalid key: `d` should not be set");
|
|
1270
|
+
}
|
|
1271
|
+
return await this._api.importKey("jwk", key, this._alg, true, []);
|
|
1272
|
+
}
|
|
1273
|
+
if (typeof key.d === "undefined") {
|
|
1274
|
+
throw new Error("Invalid key: `d` not found");
|
|
1275
|
+
}
|
|
1276
|
+
return await this._api.importKey("jwk", key, this._alg, true, KEM_USAGES);
|
|
1277
|
+
}
|
|
1278
|
+
async _deserializePkcs8Key(k) {
|
|
1279
|
+
const pkcs8Key = new Uint8Array(this._pkcs8AlgId.length + k.length);
|
|
1280
|
+
pkcs8Key.set(this._pkcs8AlgId, 0);
|
|
1281
|
+
pkcs8Key.set(k, this._pkcs8AlgId.length);
|
|
1282
|
+
return await this._api.importKey("pkcs8", pkcs8Key, this._alg, true, KEM_USAGES);
|
|
1283
|
+
}
|
|
1284
|
+
async _derivePublicKeyWithoutJwkExport(key) {
|
|
1285
|
+
const basePointRaw = buildRawUncompressedPublicKey(this._curveParams.gx, this._curveParams.gy, this._curveParams.coordinateSize);
|
|
1286
|
+
const basePoint = await this._api.importKey("raw", basePointRaw.buffer, this._alg, true, []);
|
|
1287
|
+
const xBytes = new Uint8Array(await this._api.deriveBits({
|
|
1288
|
+
name: "ECDH",
|
|
1289
|
+
public: basePoint
|
|
1290
|
+
}, key, this._nDh * 8));
|
|
1291
|
+
const p = this._curveParams.p;
|
|
1292
|
+
const x = bytesToBigInt(xBytes);
|
|
1293
|
+
const rhs = mod(modPow(x, 3n, p) - 3n * x + this._curveParams.b, p);
|
|
1294
|
+
let y = modSqrt(rhs, p);
|
|
1295
|
+
if ((y & 1n) === 1n) {
|
|
1296
|
+
y = p - y;
|
|
1297
|
+
}
|
|
1298
|
+
const pubRaw = buildRawUncompressedPublicKey(x, y, this._curveParams.coordinateSize);
|
|
1299
|
+
return await this._api.importKey("raw", pubRaw.buffer, this._alg, true, []);
|
|
1300
|
+
}
|
|
1301
|
+
};
|
|
1302
|
+
|
|
1303
|
+
// node_modules/@hpke/common/esm/src/interfaces/aeadEncryptionContext.js
|
|
1304
|
+
var AEAD_USAGES = ["encrypt", "decrypt"];
|
|
1305
|
+
|
|
1306
|
+
// node_modules/@hpke/common/esm/src/utils/noble.js
|
|
1307
|
+
function isBytes(a) {
|
|
1308
|
+
return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array";
|
|
1309
|
+
}
|
|
1310
|
+
function anumber(n, title = "") {
|
|
1311
|
+
if (!Number.isSafeInteger(n) || n < 0) {
|
|
1312
|
+
const prefix = title && `"${title}" `;
|
|
1313
|
+
throw new Error(`${prefix}expected integer >0, got ${n}`);
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
function abytes(value, length, title = "") {
|
|
1317
|
+
const bytes2 = isBytes(value);
|
|
1318
|
+
const len = value?.length;
|
|
1319
|
+
const needsLen = length !== void 0;
|
|
1320
|
+
if (!bytes2 || needsLen && len !== length) {
|
|
1321
|
+
const prefix = title && `"${title}" `;
|
|
1322
|
+
const ofLen = needsLen ? ` of length ${length}` : "";
|
|
1323
|
+
const got = bytes2 ? `length=${len}` : `type=${typeof value}`;
|
|
1324
|
+
throw new Error(prefix + "expected Uint8Array" + ofLen + ", got " + got);
|
|
1325
|
+
}
|
|
1326
|
+
return value;
|
|
1327
|
+
}
|
|
1328
|
+
function aexists(instance, checkFinished = true) {
|
|
1329
|
+
if (instance.destroyed)
|
|
1330
|
+
throw new Error("Hash instance has been destroyed");
|
|
1331
|
+
if (checkFinished && instance.finished) {
|
|
1332
|
+
throw new Error("Hash#digest() has already been called");
|
|
1333
|
+
}
|
|
1334
|
+
}
|
|
1335
|
+
function clean(...arrays) {
|
|
1336
|
+
for (let i = 0; i < arrays.length; i++) {
|
|
1337
|
+
arrays[i].fill(0);
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1340
|
+
var _endianTestBuffer = /* @__PURE__ */ new Uint32Array([287454020]);
|
|
1341
|
+
var _endianTestBytes = /* @__PURE__ */ new Uint8Array(_endianTestBuffer.buffer);
|
|
1342
|
+
var isLE = _endianTestBytes[0] === 68;
|
|
1343
|
+
|
|
1344
|
+
// node_modules/@hpke/common/esm/src/hash/hash.js
|
|
1345
|
+
function ahash(h) {
|
|
1346
|
+
if (typeof h !== "function" || typeof h.create !== "function") {
|
|
1347
|
+
throw new Error("Hash must wrapped by utils.createHasher");
|
|
1348
|
+
}
|
|
1349
|
+
anumber(h.outputLen);
|
|
1350
|
+
anumber(h.blockLen);
|
|
1351
|
+
}
|
|
1352
|
+
|
|
1353
|
+
// node_modules/@hpke/common/esm/src/hash/hmac.js
|
|
1354
|
+
var _HMAC = class {
|
|
1355
|
+
constructor(hash, key) {
|
|
1356
|
+
Object.defineProperty(this, "oHash", {
|
|
1357
|
+
enumerable: true,
|
|
1358
|
+
configurable: true,
|
|
1359
|
+
writable: true,
|
|
1360
|
+
value: void 0
|
|
1361
|
+
});
|
|
1362
|
+
Object.defineProperty(this, "iHash", {
|
|
1363
|
+
enumerable: true,
|
|
1364
|
+
configurable: true,
|
|
1365
|
+
writable: true,
|
|
1366
|
+
value: void 0
|
|
1367
|
+
});
|
|
1368
|
+
Object.defineProperty(this, "blockLen", {
|
|
1369
|
+
enumerable: true,
|
|
1370
|
+
configurable: true,
|
|
1371
|
+
writable: true,
|
|
1372
|
+
value: void 0
|
|
1373
|
+
});
|
|
1374
|
+
Object.defineProperty(this, "outputLen", {
|
|
1375
|
+
enumerable: true,
|
|
1376
|
+
configurable: true,
|
|
1377
|
+
writable: true,
|
|
1378
|
+
value: void 0
|
|
1379
|
+
});
|
|
1380
|
+
Object.defineProperty(this, "finished", {
|
|
1381
|
+
enumerable: true,
|
|
1382
|
+
configurable: true,
|
|
1383
|
+
writable: true,
|
|
1384
|
+
value: false
|
|
1385
|
+
});
|
|
1386
|
+
Object.defineProperty(this, "destroyed", {
|
|
1387
|
+
enumerable: true,
|
|
1388
|
+
configurable: true,
|
|
1389
|
+
writable: true,
|
|
1390
|
+
value: false
|
|
1391
|
+
});
|
|
1392
|
+
ahash(hash);
|
|
1393
|
+
abytes(key, void 0, "key");
|
|
1394
|
+
this.iHash = hash.create();
|
|
1395
|
+
if (typeof this.iHash.update !== "function") {
|
|
1396
|
+
throw new Error("Expected instance of class which extends utils.Hash");
|
|
1397
|
+
}
|
|
1398
|
+
this.blockLen = this.iHash.blockLen;
|
|
1399
|
+
this.outputLen = this.iHash.outputLen;
|
|
1400
|
+
const blockLen = this.blockLen;
|
|
1401
|
+
const pad = new Uint8Array(blockLen);
|
|
1402
|
+
pad.set(key.length > blockLen ? hash.create().update(key).digest() : key);
|
|
1403
|
+
for (let i = 0; i < pad.length; i++)
|
|
1404
|
+
pad[i] ^= 54;
|
|
1405
|
+
this.iHash.update(pad);
|
|
1406
|
+
this.oHash = hash.create();
|
|
1407
|
+
for (let i = 0; i < pad.length; i++)
|
|
1408
|
+
pad[i] ^= 54 ^ 92;
|
|
1409
|
+
this.oHash.update(pad);
|
|
1410
|
+
clean(pad);
|
|
1411
|
+
}
|
|
1412
|
+
update(buf) {
|
|
1413
|
+
aexists(this);
|
|
1414
|
+
this.iHash.update(buf);
|
|
1415
|
+
return this;
|
|
1416
|
+
}
|
|
1417
|
+
digestInto(out) {
|
|
1418
|
+
aexists(this);
|
|
1419
|
+
abytes(out, this.outputLen, "output");
|
|
1420
|
+
this.finished = true;
|
|
1421
|
+
this.iHash.digestInto(out);
|
|
1422
|
+
this.oHash.update(out);
|
|
1423
|
+
this.oHash.digestInto(out);
|
|
1424
|
+
this.destroy();
|
|
1425
|
+
}
|
|
1426
|
+
digest() {
|
|
1427
|
+
const out = new Uint8Array(this.oHash.outputLen);
|
|
1428
|
+
this.digestInto(out);
|
|
1429
|
+
return out;
|
|
1430
|
+
}
|
|
1431
|
+
_cloneInto(to) {
|
|
1432
|
+
to ||= Object.create(Object.getPrototypeOf(this), {});
|
|
1433
|
+
const { oHash, iHash, finished, destroyed, blockLen, outputLen } = this;
|
|
1434
|
+
to = to;
|
|
1435
|
+
to.finished = finished;
|
|
1436
|
+
to.destroyed = destroyed;
|
|
1437
|
+
to.blockLen = blockLen;
|
|
1438
|
+
to.outputLen = outputLen;
|
|
1439
|
+
to.oHash = oHash._cloneInto(to.oHash);
|
|
1440
|
+
to.iHash = iHash._cloneInto(to.iHash);
|
|
1441
|
+
return to;
|
|
1442
|
+
}
|
|
1443
|
+
clone() {
|
|
1444
|
+
return this._cloneInto();
|
|
1445
|
+
}
|
|
1446
|
+
destroy() {
|
|
1447
|
+
this.destroyed = true;
|
|
1448
|
+
this.oHash.destroy();
|
|
1449
|
+
this.iHash.destroy();
|
|
1450
|
+
}
|
|
1451
|
+
};
|
|
1452
|
+
var hmac = (hash, key, message) => new _HMAC(hash, key).update(message).digest();
|
|
1453
|
+
hmac.create = (hash, key) => new _HMAC(hash, key);
|
|
1454
|
+
|
|
1455
|
+
// node_modules/@hpke/common/esm/src/hash/u64.js
|
|
1456
|
+
var U32_MASK64 = 0xffffffffn;
|
|
1457
|
+
var _32n = 32n;
|
|
1458
|
+
function fromBig(n, le = false) {
|
|
1459
|
+
if (le) {
|
|
1460
|
+
return { h: Number(n & U32_MASK64), l: Number(n >> _32n & U32_MASK64) };
|
|
1461
|
+
}
|
|
1462
|
+
return {
|
|
1463
|
+
h: Number(n >> _32n & U32_MASK64) | 0,
|
|
1464
|
+
l: Number(n & U32_MASK64) | 0
|
|
1465
|
+
};
|
|
1466
|
+
}
|
|
1467
|
+
function split(lst, le = false) {
|
|
1468
|
+
const len = lst.length;
|
|
1469
|
+
const Ah = new Uint32Array(len);
|
|
1470
|
+
const Al = new Uint32Array(len);
|
|
1471
|
+
for (let i = 0; i < len; i++) {
|
|
1472
|
+
const { h, l } = fromBig(lst[i], le);
|
|
1473
|
+
[Ah[i], Al[i]] = [h, l];
|
|
1474
|
+
}
|
|
1475
|
+
return [Ah, Al];
|
|
1476
|
+
}
|
|
1477
|
+
|
|
1478
|
+
// node_modules/@hpke/common/esm/src/hash/sha3.js
|
|
1479
|
+
var _0n = 0n;
|
|
1480
|
+
var _1n = 1n;
|
|
1481
|
+
var _2n = 2n;
|
|
1482
|
+
var _7n = 7n;
|
|
1483
|
+
var _256n = 256n;
|
|
1484
|
+
var _0x71n = 0x71n;
|
|
1485
|
+
var SHA3_PI = [];
|
|
1486
|
+
var SHA3_ROTL = [];
|
|
1487
|
+
var _SHA3_IOTA = [];
|
|
1488
|
+
for (let round = 0, R = _1n, x = 1, y = 0; round < 24; round++) {
|
|
1489
|
+
[x, y] = [y, (2 * x + 3 * y) % 5];
|
|
1490
|
+
SHA3_PI.push(2 * (5 * y + x));
|
|
1491
|
+
SHA3_ROTL.push((round + 1) * (round + 2) / 2 % 64);
|
|
1492
|
+
let t = _0n;
|
|
1493
|
+
for (let j = 0; j < 7; j++) {
|
|
1494
|
+
R = (R << _1n ^ (R >> _7n) * _0x71n) % _256n;
|
|
1495
|
+
if (R & _2n)
|
|
1496
|
+
t ^= _1n << (_1n << BigInt(j)) - _1n;
|
|
1497
|
+
}
|
|
1498
|
+
_SHA3_IOTA.push(t);
|
|
1499
|
+
}
|
|
1500
|
+
var IOTAS = split(_SHA3_IOTA, true);
|
|
1501
|
+
var SHA3_IOTA_H = IOTAS[0];
|
|
1502
|
+
var SHA3_IOTA_L = IOTAS[1];
|
|
1503
|
+
|
|
1504
|
+
// node_modules/@hpke/core/esm/src/aeads/aesGcm.js
|
|
1505
|
+
var AesGcmContext = class extends NativeAlgorithm {
|
|
1506
|
+
constructor(key) {
|
|
1507
|
+
super();
|
|
1508
|
+
Object.defineProperty(this, "_rawKey", {
|
|
1509
|
+
enumerable: true,
|
|
1510
|
+
configurable: true,
|
|
1511
|
+
writable: true,
|
|
1512
|
+
value: void 0
|
|
1513
|
+
});
|
|
1514
|
+
Object.defineProperty(this, "_key", {
|
|
1515
|
+
enumerable: true,
|
|
1516
|
+
configurable: true,
|
|
1517
|
+
writable: true,
|
|
1518
|
+
value: void 0
|
|
1519
|
+
});
|
|
1520
|
+
this._rawKey = toArrayBuffer(key);
|
|
1521
|
+
}
|
|
1522
|
+
async seal(iv, data, aad) {
|
|
1523
|
+
await this._setupKey();
|
|
1524
|
+
const alg = {
|
|
1525
|
+
name: "AES-GCM",
|
|
1526
|
+
iv: toArrayBuffer(iv),
|
|
1527
|
+
additionalData: toArrayBuffer(aad)
|
|
1528
|
+
};
|
|
1529
|
+
const ct = await this._api.encrypt(alg, this._key, toArrayBuffer(data));
|
|
1530
|
+
return ct;
|
|
1531
|
+
}
|
|
1532
|
+
async open(iv, data, aad) {
|
|
1533
|
+
await this._setupKey();
|
|
1534
|
+
const alg = {
|
|
1535
|
+
name: "AES-GCM",
|
|
1536
|
+
iv: toArrayBuffer(iv),
|
|
1537
|
+
additionalData: toArrayBuffer(aad)
|
|
1538
|
+
};
|
|
1539
|
+
const pt = await this._api.decrypt(alg, this._key, toArrayBuffer(data));
|
|
1540
|
+
return pt;
|
|
1541
|
+
}
|
|
1542
|
+
async _setupKey() {
|
|
1543
|
+
if (this._key !== void 0) {
|
|
1544
|
+
return;
|
|
1545
|
+
}
|
|
1546
|
+
await this._setup();
|
|
1547
|
+
const key = await this._importKey(this._rawKey);
|
|
1548
|
+
new Uint8Array(this._rawKey).fill(0);
|
|
1549
|
+
this._key = key;
|
|
1550
|
+
return;
|
|
1551
|
+
}
|
|
1552
|
+
async _importKey(key) {
|
|
1553
|
+
return await this._api.importKey("raw", key, { name: "AES-GCM" }, true, AEAD_USAGES);
|
|
1554
|
+
}
|
|
1555
|
+
};
|
|
1556
|
+
var Aes128Gcm = class {
|
|
1557
|
+
constructor() {
|
|
1558
|
+
Object.defineProperty(this, "id", {
|
|
1559
|
+
enumerable: true,
|
|
1560
|
+
configurable: true,
|
|
1561
|
+
writable: true,
|
|
1562
|
+
value: AeadId.Aes128Gcm
|
|
1563
|
+
});
|
|
1564
|
+
Object.defineProperty(this, "keySize", {
|
|
1565
|
+
enumerable: true,
|
|
1566
|
+
configurable: true,
|
|
1567
|
+
writable: true,
|
|
1568
|
+
value: 16
|
|
1569
|
+
});
|
|
1570
|
+
Object.defineProperty(this, "nonceSize", {
|
|
1571
|
+
enumerable: true,
|
|
1572
|
+
configurable: true,
|
|
1573
|
+
writable: true,
|
|
1574
|
+
value: 12
|
|
1575
|
+
});
|
|
1576
|
+
Object.defineProperty(this, "tagSize", {
|
|
1577
|
+
enumerable: true,
|
|
1578
|
+
configurable: true,
|
|
1579
|
+
writable: true,
|
|
1580
|
+
value: 16
|
|
1581
|
+
});
|
|
1582
|
+
}
|
|
1583
|
+
createEncryptionContext(key) {
|
|
1584
|
+
return new AesGcmContext(key);
|
|
1585
|
+
}
|
|
1586
|
+
};
|
|
1587
|
+
var Aes256Gcm = class extends Aes128Gcm {
|
|
1588
|
+
constructor() {
|
|
1589
|
+
super(...arguments);
|
|
1590
|
+
Object.defineProperty(this, "id", {
|
|
1591
|
+
enumerable: true,
|
|
1592
|
+
configurable: true,
|
|
1593
|
+
writable: true,
|
|
1594
|
+
value: AeadId.Aes256Gcm
|
|
1595
|
+
});
|
|
1596
|
+
Object.defineProperty(this, "keySize", {
|
|
1597
|
+
enumerable: true,
|
|
1598
|
+
configurable: true,
|
|
1599
|
+
writable: true,
|
|
1600
|
+
value: 32
|
|
1601
|
+
});
|
|
1602
|
+
Object.defineProperty(this, "nonceSize", {
|
|
1603
|
+
enumerable: true,
|
|
1604
|
+
configurable: true,
|
|
1605
|
+
writable: true,
|
|
1606
|
+
value: 12
|
|
1607
|
+
});
|
|
1608
|
+
Object.defineProperty(this, "tagSize", {
|
|
1609
|
+
enumerable: true,
|
|
1610
|
+
configurable: true,
|
|
1611
|
+
writable: true,
|
|
1612
|
+
value: 16
|
|
1613
|
+
});
|
|
1614
|
+
}
|
|
1615
|
+
};
|
|
1616
|
+
|
|
1617
|
+
// node_modules/@hpke/core/esm/src/utils/emitNotSupported.js
|
|
1618
|
+
function emitNotSupported() {
|
|
1619
|
+
return new Promise((_resolve, reject) => {
|
|
1620
|
+
reject(new NotSupportedError("Not supported"));
|
|
1621
|
+
});
|
|
1622
|
+
}
|
|
1623
|
+
|
|
1624
|
+
// node_modules/@hpke/core/esm/src/exporterContext.js
|
|
1625
|
+
var LABEL_SEC = new Uint8Array([115, 101, 99]);
|
|
1626
|
+
var ExporterContextImpl = class {
|
|
1627
|
+
constructor(api, kdf, exporterSecret) {
|
|
1628
|
+
Object.defineProperty(this, "_api", {
|
|
1629
|
+
enumerable: true,
|
|
1630
|
+
configurable: true,
|
|
1631
|
+
writable: true,
|
|
1632
|
+
value: void 0
|
|
1633
|
+
});
|
|
1634
|
+
Object.defineProperty(this, "exporterSecret", {
|
|
1635
|
+
enumerable: true,
|
|
1636
|
+
configurable: true,
|
|
1637
|
+
writable: true,
|
|
1638
|
+
value: void 0
|
|
1639
|
+
});
|
|
1640
|
+
Object.defineProperty(this, "_kdf", {
|
|
1641
|
+
enumerable: true,
|
|
1642
|
+
configurable: true,
|
|
1643
|
+
writable: true,
|
|
1644
|
+
value: void 0
|
|
1645
|
+
});
|
|
1646
|
+
this._api = api;
|
|
1647
|
+
this._kdf = kdf;
|
|
1648
|
+
this.exporterSecret = exporterSecret;
|
|
1649
|
+
}
|
|
1650
|
+
async seal(_data, _aad) {
|
|
1651
|
+
return await emitNotSupported();
|
|
1652
|
+
}
|
|
1653
|
+
async open(_data, _aad) {
|
|
1654
|
+
return await emitNotSupported();
|
|
1655
|
+
}
|
|
1656
|
+
async export(exporterContext, len) {
|
|
1657
|
+
const rawExporterContext = toArrayBuffer(exporterContext);
|
|
1658
|
+
if (rawExporterContext.byteLength > INPUT_LENGTH_LIMIT) {
|
|
1659
|
+
throw new InvalidParamError("Too long exporter context");
|
|
1660
|
+
}
|
|
1661
|
+
try {
|
|
1662
|
+
return await this._kdf.labeledExpand(this.exporterSecret, LABEL_SEC, new Uint8Array(rawExporterContext), len);
|
|
1663
|
+
} catch (e) {
|
|
1664
|
+
throw new ExportError(e);
|
|
1665
|
+
}
|
|
1666
|
+
}
|
|
1667
|
+
};
|
|
1668
|
+
var RecipientExporterContextImpl = class extends ExporterContextImpl {
|
|
1669
|
+
};
|
|
1670
|
+
var SenderExporterContextImpl = class extends ExporterContextImpl {
|
|
1671
|
+
constructor(api, kdf, exporterSecret, enc) {
|
|
1672
|
+
super(api, kdf, exporterSecret);
|
|
1673
|
+
Object.defineProperty(this, "enc", {
|
|
1674
|
+
enumerable: true,
|
|
1675
|
+
configurable: true,
|
|
1676
|
+
writable: true,
|
|
1677
|
+
value: void 0
|
|
1678
|
+
});
|
|
1679
|
+
this.enc = enc;
|
|
1680
|
+
return;
|
|
1681
|
+
}
|
|
1682
|
+
};
|
|
1683
|
+
|
|
1684
|
+
// node_modules/@hpke/core/esm/src/encryptionContext.js
|
|
1685
|
+
var EncryptionContextImpl = class extends ExporterContextImpl {
|
|
1686
|
+
constructor(api, kdf, params) {
|
|
1687
|
+
super(api, kdf, params.exporterSecret);
|
|
1688
|
+
Object.defineProperty(this, "_aead", {
|
|
1689
|
+
enumerable: true,
|
|
1690
|
+
configurable: true,
|
|
1691
|
+
writable: true,
|
|
1692
|
+
value: void 0
|
|
1693
|
+
});
|
|
1694
|
+
Object.defineProperty(this, "_nK", {
|
|
1695
|
+
enumerable: true,
|
|
1696
|
+
configurable: true,
|
|
1697
|
+
writable: true,
|
|
1698
|
+
value: void 0
|
|
1699
|
+
});
|
|
1700
|
+
Object.defineProperty(this, "_nN", {
|
|
1701
|
+
enumerable: true,
|
|
1702
|
+
configurable: true,
|
|
1703
|
+
writable: true,
|
|
1704
|
+
value: void 0
|
|
1705
|
+
});
|
|
1706
|
+
Object.defineProperty(this, "_nT", {
|
|
1707
|
+
enumerable: true,
|
|
1708
|
+
configurable: true,
|
|
1709
|
+
writable: true,
|
|
1710
|
+
value: void 0
|
|
1711
|
+
});
|
|
1712
|
+
Object.defineProperty(this, "_ctx", {
|
|
1713
|
+
enumerable: true,
|
|
1714
|
+
configurable: true,
|
|
1715
|
+
writable: true,
|
|
1716
|
+
value: void 0
|
|
1717
|
+
});
|
|
1718
|
+
if (params.key === void 0 || params.baseNonce === void 0 || params.seq === void 0) {
|
|
1719
|
+
throw new Error("Required parameters are missing");
|
|
1720
|
+
}
|
|
1721
|
+
this._aead = params.aead;
|
|
1722
|
+
this._nK = this._aead.keySize;
|
|
1723
|
+
this._nN = this._aead.nonceSize;
|
|
1724
|
+
this._nT = this._aead.tagSize;
|
|
1725
|
+
const key = this._aead.createEncryptionContext(params.key);
|
|
1726
|
+
this._ctx = {
|
|
1727
|
+
key,
|
|
1728
|
+
baseNonce: params.baseNonce,
|
|
1729
|
+
seq: params.seq
|
|
1730
|
+
};
|
|
1731
|
+
}
|
|
1732
|
+
computeNonce(k) {
|
|
1733
|
+
const seqBytes = i2Osp(k.seq, k.baseNonce.byteLength);
|
|
1734
|
+
return xor(k.baseNonce, seqBytes).buffer;
|
|
1735
|
+
}
|
|
1736
|
+
incrementSeq(k) {
|
|
1737
|
+
if (k.seq > Number.MAX_SAFE_INTEGER) {
|
|
1738
|
+
throw new MessageLimitReachedError("Message limit reached");
|
|
1739
|
+
}
|
|
1740
|
+
k.seq += 1;
|
|
1741
|
+
return;
|
|
1742
|
+
}
|
|
1743
|
+
};
|
|
1744
|
+
|
|
1745
|
+
// node_modules/@hpke/core/esm/src/mutex.js
|
|
1746
|
+
var __classPrivateFieldGet = function(receiver, state, kind, f) {
|
|
1747
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
1748
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
1749
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
1750
|
+
};
|
|
1751
|
+
var __classPrivateFieldSet = function(receiver, state, value, kind, f) {
|
|
1752
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
1753
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
1754
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
1755
|
+
return kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;
|
|
1756
|
+
};
|
|
1757
|
+
var _Mutex_locked;
|
|
1758
|
+
var Mutex = class {
|
|
1759
|
+
constructor() {
|
|
1760
|
+
_Mutex_locked.set(this, Promise.resolve());
|
|
1761
|
+
}
|
|
1762
|
+
async lock() {
|
|
1763
|
+
let releaseLock;
|
|
1764
|
+
const nextLock = new Promise((resolve) => {
|
|
1765
|
+
releaseLock = resolve;
|
|
1766
|
+
});
|
|
1767
|
+
const previousLock = __classPrivateFieldGet(this, _Mutex_locked, "f");
|
|
1768
|
+
__classPrivateFieldSet(this, _Mutex_locked, nextLock, "f");
|
|
1769
|
+
await previousLock;
|
|
1770
|
+
return releaseLock;
|
|
1771
|
+
}
|
|
1772
|
+
};
|
|
1773
|
+
_Mutex_locked = /* @__PURE__ */ new WeakMap();
|
|
1774
|
+
|
|
1775
|
+
// node_modules/@hpke/core/esm/src/recipientContext.js
|
|
1776
|
+
var __classPrivateFieldGet2 = function(receiver, state, kind, f) {
|
|
1777
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
1778
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
1779
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
1780
|
+
};
|
|
1781
|
+
var __classPrivateFieldSet2 = function(receiver, state, value, kind, f) {
|
|
1782
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
1783
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
1784
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
1785
|
+
return kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;
|
|
1786
|
+
};
|
|
1787
|
+
var _RecipientContextImpl_mutex;
|
|
1788
|
+
var RecipientContextImpl = class extends EncryptionContextImpl {
|
|
1789
|
+
constructor() {
|
|
1790
|
+
super(...arguments);
|
|
1791
|
+
_RecipientContextImpl_mutex.set(this, void 0);
|
|
1792
|
+
}
|
|
1793
|
+
async open(data, aad = EMPTY.buffer) {
|
|
1794
|
+
__classPrivateFieldSet2(this, _RecipientContextImpl_mutex, __classPrivateFieldGet2(this, _RecipientContextImpl_mutex, "f") ?? new Mutex(), "f");
|
|
1795
|
+
const release = await __classPrivateFieldGet2(this, _RecipientContextImpl_mutex, "f").lock();
|
|
1796
|
+
let pt;
|
|
1797
|
+
try {
|
|
1798
|
+
pt = await this._ctx.key.open(this.computeNonce(this._ctx), toArrayBuffer(data), toArrayBuffer(aad));
|
|
1799
|
+
} catch (e) {
|
|
1800
|
+
throw new OpenError(e);
|
|
1801
|
+
} finally {
|
|
1802
|
+
release();
|
|
1803
|
+
}
|
|
1804
|
+
this.incrementSeq(this._ctx);
|
|
1805
|
+
return pt;
|
|
1806
|
+
}
|
|
1807
|
+
};
|
|
1808
|
+
_RecipientContextImpl_mutex = /* @__PURE__ */ new WeakMap();
|
|
1809
|
+
|
|
1810
|
+
// node_modules/@hpke/core/esm/src/senderContext.js
|
|
1811
|
+
var __classPrivateFieldGet3 = function(receiver, state, kind, f) {
|
|
1812
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
1813
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
1814
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
1815
|
+
};
|
|
1816
|
+
var __classPrivateFieldSet3 = function(receiver, state, value, kind, f) {
|
|
1817
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
1818
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
1819
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
1820
|
+
return kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;
|
|
1821
|
+
};
|
|
1822
|
+
var _SenderContextImpl_mutex;
|
|
1823
|
+
var SenderContextImpl = class extends EncryptionContextImpl {
|
|
1824
|
+
constructor(api, kdf, params, enc) {
|
|
1825
|
+
super(api, kdf, params);
|
|
1826
|
+
Object.defineProperty(this, "enc", {
|
|
1827
|
+
enumerable: true,
|
|
1828
|
+
configurable: true,
|
|
1829
|
+
writable: true,
|
|
1830
|
+
value: void 0
|
|
1831
|
+
});
|
|
1832
|
+
_SenderContextImpl_mutex.set(this, void 0);
|
|
1833
|
+
this.enc = enc;
|
|
1834
|
+
}
|
|
1835
|
+
async seal(data, aad = EMPTY.buffer) {
|
|
1836
|
+
__classPrivateFieldSet3(this, _SenderContextImpl_mutex, __classPrivateFieldGet3(this, _SenderContextImpl_mutex, "f") ?? new Mutex(), "f");
|
|
1837
|
+
const release = await __classPrivateFieldGet3(this, _SenderContextImpl_mutex, "f").lock();
|
|
1838
|
+
let ct;
|
|
1839
|
+
try {
|
|
1840
|
+
ct = await this._ctx.key.seal(this.computeNonce(this._ctx), toArrayBuffer(data), toArrayBuffer(aad));
|
|
1841
|
+
} catch (e) {
|
|
1842
|
+
throw new SealError(e);
|
|
1843
|
+
} finally {
|
|
1844
|
+
release();
|
|
1845
|
+
}
|
|
1846
|
+
this.incrementSeq(this._ctx);
|
|
1847
|
+
return ct;
|
|
1848
|
+
}
|
|
1849
|
+
};
|
|
1850
|
+
_SenderContextImpl_mutex = /* @__PURE__ */ new WeakMap();
|
|
1851
|
+
|
|
1852
|
+
// node_modules/@hpke/core/esm/src/cipherSuiteNative.js
|
|
1853
|
+
var LABEL_BASE_NONCE = new Uint8Array([
|
|
1854
|
+
98,
|
|
1855
|
+
97,
|
|
1856
|
+
115,
|
|
1857
|
+
101,
|
|
1858
|
+
95,
|
|
1859
|
+
110,
|
|
1860
|
+
111,
|
|
1861
|
+
110,
|
|
1862
|
+
99,
|
|
1863
|
+
101
|
|
1864
|
+
]);
|
|
1865
|
+
var LABEL_EXP = new Uint8Array([101, 120, 112]);
|
|
1866
|
+
var LABEL_INFO_HASH = new Uint8Array([
|
|
1867
|
+
105,
|
|
1868
|
+
110,
|
|
1869
|
+
102,
|
|
1870
|
+
111,
|
|
1871
|
+
95,
|
|
1872
|
+
104,
|
|
1873
|
+
97,
|
|
1874
|
+
115,
|
|
1875
|
+
104
|
|
1876
|
+
]);
|
|
1877
|
+
var LABEL_KEY = new Uint8Array([107, 101, 121]);
|
|
1878
|
+
var LABEL_PSK_ID_HASH = new Uint8Array([
|
|
1879
|
+
112,
|
|
1880
|
+
115,
|
|
1881
|
+
107,
|
|
1882
|
+
95,
|
|
1883
|
+
105,
|
|
1884
|
+
100,
|
|
1885
|
+
95,
|
|
1886
|
+
104,
|
|
1887
|
+
97,
|
|
1888
|
+
115,
|
|
1889
|
+
104
|
|
1890
|
+
]);
|
|
1891
|
+
var LABEL_SECRET = new Uint8Array([115, 101, 99, 114, 101, 116]);
|
|
1892
|
+
var SUITE_ID_HEADER_HPKE = new Uint8Array([
|
|
1893
|
+
72,
|
|
1894
|
+
80,
|
|
1895
|
+
75,
|
|
1896
|
+
69,
|
|
1897
|
+
0,
|
|
1898
|
+
0,
|
|
1899
|
+
0,
|
|
1900
|
+
0,
|
|
1901
|
+
0,
|
|
1902
|
+
0
|
|
1903
|
+
]);
|
|
1904
|
+
var CipherSuiteNative = class extends NativeAlgorithm {
|
|
1905
|
+
/**
|
|
1906
|
+
* @param params A set of parameters for building a cipher suite.
|
|
1907
|
+
*
|
|
1908
|
+
* If the error occurred, throws {@link InvalidParamError}.
|
|
1909
|
+
*
|
|
1910
|
+
* @throws {@link InvalidParamError}
|
|
1911
|
+
*/
|
|
1912
|
+
constructor(params) {
|
|
1913
|
+
super();
|
|
1914
|
+
Object.defineProperty(this, "_kem", {
|
|
1915
|
+
enumerable: true,
|
|
1916
|
+
configurable: true,
|
|
1917
|
+
writable: true,
|
|
1918
|
+
value: void 0
|
|
1919
|
+
});
|
|
1920
|
+
Object.defineProperty(this, "_kdf", {
|
|
1921
|
+
enumerable: true,
|
|
1922
|
+
configurable: true,
|
|
1923
|
+
writable: true,
|
|
1924
|
+
value: void 0
|
|
1925
|
+
});
|
|
1926
|
+
Object.defineProperty(this, "_aead", {
|
|
1927
|
+
enumerable: true,
|
|
1928
|
+
configurable: true,
|
|
1929
|
+
writable: true,
|
|
1930
|
+
value: void 0
|
|
1931
|
+
});
|
|
1932
|
+
Object.defineProperty(this, "_suiteId", {
|
|
1933
|
+
enumerable: true,
|
|
1934
|
+
configurable: true,
|
|
1935
|
+
writable: true,
|
|
1936
|
+
value: void 0
|
|
1937
|
+
});
|
|
1938
|
+
if (typeof params.kem === "number") {
|
|
1939
|
+
throw new InvalidParamError("KemId cannot be used");
|
|
1940
|
+
}
|
|
1941
|
+
this._kem = params.kem;
|
|
1942
|
+
if (typeof params.kdf === "number") {
|
|
1943
|
+
throw new InvalidParamError("KdfId cannot be used");
|
|
1944
|
+
}
|
|
1945
|
+
this._kdf = params.kdf;
|
|
1946
|
+
if (typeof params.aead === "number") {
|
|
1947
|
+
throw new InvalidParamError("AeadId cannot be used");
|
|
1948
|
+
}
|
|
1949
|
+
this._aead = params.aead;
|
|
1950
|
+
this._suiteId = new Uint8Array(SUITE_ID_HEADER_HPKE);
|
|
1951
|
+
this._suiteId.set(i2Osp(this._kem.id, 2), 4);
|
|
1952
|
+
this._suiteId.set(i2Osp(this._kdf.id, 2), 6);
|
|
1953
|
+
this._suiteId.set(i2Osp(this._aead.id, 2), 8);
|
|
1954
|
+
this._kdf.init(this._suiteId);
|
|
1955
|
+
}
|
|
1956
|
+
/**
|
|
1957
|
+
* Gets the KEM context of the ciphersuite.
|
|
1958
|
+
*/
|
|
1959
|
+
get kem() {
|
|
1960
|
+
return this._kem;
|
|
1961
|
+
}
|
|
1962
|
+
/**
|
|
1963
|
+
* Gets the KDF context of the ciphersuite.
|
|
1964
|
+
*/
|
|
1965
|
+
get kdf() {
|
|
1966
|
+
return this._kdf;
|
|
1967
|
+
}
|
|
1968
|
+
/**
|
|
1969
|
+
* Gets the AEAD context of the ciphersuite.
|
|
1970
|
+
*/
|
|
1971
|
+
get aead() {
|
|
1972
|
+
return this._aead;
|
|
1973
|
+
}
|
|
1974
|
+
/**
|
|
1975
|
+
* Creates an encryption context for a sender.
|
|
1976
|
+
*
|
|
1977
|
+
* If the error occurred, throws {@link DecapError} | {@link ValidationError}.
|
|
1978
|
+
*
|
|
1979
|
+
* @param params A set of parameters for the sender encryption context.
|
|
1980
|
+
* @returns A sender encryption context.
|
|
1981
|
+
* @throws {@link EncapError}, {@link ValidationError}
|
|
1982
|
+
*/
|
|
1983
|
+
async createSenderContext(params) {
|
|
1984
|
+
this._validateInputLength(params);
|
|
1985
|
+
await this._setup();
|
|
1986
|
+
const dh = await this._kem.encap(params);
|
|
1987
|
+
let mode;
|
|
1988
|
+
if (params.psk !== void 0) {
|
|
1989
|
+
mode = params.senderKey !== void 0 ? Mode.AuthPsk : Mode.Psk;
|
|
1990
|
+
} else {
|
|
1991
|
+
mode = params.senderKey !== void 0 ? Mode.Auth : Mode.Base;
|
|
1992
|
+
}
|
|
1993
|
+
return await this._keyScheduleS(mode, dh.sharedSecret, dh.enc, params);
|
|
1994
|
+
}
|
|
1995
|
+
/**
|
|
1996
|
+
* Creates an encryption context for a recipient.
|
|
1997
|
+
*
|
|
1998
|
+
* If the error occurred, throws {@link DecapError}
|
|
1999
|
+
* | {@link DeserializeError} | {@link ValidationError}.
|
|
2000
|
+
*
|
|
2001
|
+
* @param params A set of parameters for the recipient encryption context.
|
|
2002
|
+
* @returns A recipient encryption context.
|
|
2003
|
+
* @throws {@link DecapError}, {@link DeserializeError}, {@link ValidationError}
|
|
2004
|
+
*/
|
|
2005
|
+
async createRecipientContext(params) {
|
|
2006
|
+
this._validateInputLength(params);
|
|
2007
|
+
await this._setup();
|
|
2008
|
+
const sharedSecret = await this._kem.decap(params);
|
|
2009
|
+
let mode;
|
|
2010
|
+
if (params.psk !== void 0) {
|
|
2011
|
+
mode = params.senderPublicKey !== void 0 ? Mode.AuthPsk : Mode.Psk;
|
|
2012
|
+
} else {
|
|
2013
|
+
mode = params.senderPublicKey !== void 0 ? Mode.Auth : Mode.Base;
|
|
2014
|
+
}
|
|
2015
|
+
return await this._keyScheduleR(mode, sharedSecret, params);
|
|
2016
|
+
}
|
|
2017
|
+
/**
|
|
2018
|
+
* Encrypts a message to a recipient.
|
|
2019
|
+
*
|
|
2020
|
+
* If the error occurred, throws `EncapError` | `MessageLimitReachedError` | `SealError` | `ValidationError`.
|
|
2021
|
+
*
|
|
2022
|
+
* @param params A set of parameters for building a sender encryption context.
|
|
2023
|
+
* @param pt A plain text as bytes to be encrypted.
|
|
2024
|
+
* @param aad Additional authenticated data as bytes fed by an application.
|
|
2025
|
+
* @returns A cipher text and an encapsulated key as bytes.
|
|
2026
|
+
* @throws {@link EncapError}, {@link MessageLimitReachedError}, {@link SealError}, {@link ValidationError}
|
|
2027
|
+
*/
|
|
2028
|
+
async seal(params, pt, aad = EMPTY.buffer) {
|
|
2029
|
+
const ctx = await this.createSenderContext(params);
|
|
2030
|
+
return {
|
|
2031
|
+
ct: await ctx.seal(pt, aad),
|
|
2032
|
+
enc: ctx.enc
|
|
2033
|
+
};
|
|
2034
|
+
}
|
|
2035
|
+
/**
|
|
2036
|
+
* Decrypts a message from a sender.
|
|
2037
|
+
*
|
|
2038
|
+
* If the error occurred, throws `DecapError` | `DeserializeError` | `OpenError` | `ValidationError`.
|
|
2039
|
+
*
|
|
2040
|
+
* @param params A set of parameters for building a recipient encryption context.
|
|
2041
|
+
* @param ct An encrypted text as bytes to be decrypted.
|
|
2042
|
+
* @param aad Additional authenticated data as bytes fed by an application.
|
|
2043
|
+
* @returns A decrypted plain text as bytes.
|
|
2044
|
+
* @throws {@link DecapError}, {@link DeserializeError}, {@link OpenError}, {@link ValidationError}
|
|
2045
|
+
*/
|
|
2046
|
+
async open(params, ct, aad = EMPTY.buffer) {
|
|
2047
|
+
const ctx = await this.createRecipientContext(params);
|
|
2048
|
+
return await ctx.open(ct, aad);
|
|
2049
|
+
}
|
|
2050
|
+
// private verifyPskInputs(mode: Mode, params: KeyScheduleParams) {
|
|
2051
|
+
// const gotPsk = (params.psk !== undefined);
|
|
2052
|
+
// const gotPskId = (params.psk !== undefined && params.psk.id.byteLength > 0);
|
|
2053
|
+
// if (gotPsk !== gotPskId) {
|
|
2054
|
+
// throw new Error('Inconsistent PSK inputs');
|
|
2055
|
+
// }
|
|
2056
|
+
// if (gotPsk && (mode === Mode.Base || mode === Mode.Auth)) {
|
|
2057
|
+
// throw new Error('PSK input provided when not needed');
|
|
2058
|
+
// }
|
|
2059
|
+
// if (!gotPsk && (mode === Mode.Psk || mode === Mode.AuthPsk)) {
|
|
2060
|
+
// throw new Error('Missing required PSK input');
|
|
2061
|
+
// }
|
|
2062
|
+
// return;
|
|
2063
|
+
// }
|
|
2064
|
+
async _keySchedule(mode, sharedSecret, params) {
|
|
2065
|
+
const pskId = params.psk === void 0 ? EMPTY : toUint8Array(params.psk.id);
|
|
2066
|
+
const pskIdHash = await this._kdf.labeledExtract(EMPTY, LABEL_PSK_ID_HASH, pskId);
|
|
2067
|
+
const info = params.info === void 0 ? EMPTY : toUint8Array(params.info);
|
|
2068
|
+
const infoHash = await this._kdf.labeledExtract(EMPTY, LABEL_INFO_HASH, info);
|
|
2069
|
+
const keyScheduleContext = new Uint8Array(1 + pskIdHash.byteLength + infoHash.byteLength);
|
|
2070
|
+
keyScheduleContext.set(new Uint8Array([mode]), 0);
|
|
2071
|
+
keyScheduleContext.set(new Uint8Array(pskIdHash), 1);
|
|
2072
|
+
keyScheduleContext.set(new Uint8Array(infoHash), 1 + pskIdHash.byteLength);
|
|
2073
|
+
const psk = params.psk === void 0 ? EMPTY : toUint8Array(params.psk.key);
|
|
2074
|
+
const ikm = this._kdf.buildLabeledIkm(LABEL_SECRET, psk);
|
|
2075
|
+
const exporterSecretInfo = this._kdf.buildLabeledInfo(LABEL_EXP, keyScheduleContext, this._kdf.hashSize);
|
|
2076
|
+
const exporterSecret = await this._kdf.extractAndExpand(sharedSecret, ikm, exporterSecretInfo, this._kdf.hashSize);
|
|
2077
|
+
if (this._aead.id === AeadId.ExportOnly) {
|
|
2078
|
+
return { aead: this._aead, exporterSecret };
|
|
2079
|
+
}
|
|
2080
|
+
const keyInfo = this._kdf.buildLabeledInfo(LABEL_KEY, keyScheduleContext, this._aead.keySize);
|
|
2081
|
+
const key = await this._kdf.extractAndExpand(sharedSecret, ikm, keyInfo, this._aead.keySize);
|
|
2082
|
+
const baseNonceInfo = this._kdf.buildLabeledInfo(LABEL_BASE_NONCE, keyScheduleContext, this._aead.nonceSize);
|
|
2083
|
+
const baseNonce = await this._kdf.extractAndExpand(sharedSecret, ikm, baseNonceInfo, this._aead.nonceSize);
|
|
2084
|
+
return {
|
|
2085
|
+
aead: this._aead,
|
|
2086
|
+
exporterSecret,
|
|
2087
|
+
key,
|
|
2088
|
+
baseNonce: new Uint8Array(baseNonce),
|
|
2089
|
+
seq: 0
|
|
2090
|
+
};
|
|
2091
|
+
}
|
|
2092
|
+
async _keyScheduleS(mode, sharedSecret, enc, params) {
|
|
2093
|
+
const res = await this._keySchedule(mode, sharedSecret, params);
|
|
2094
|
+
if (res.key === void 0) {
|
|
2095
|
+
return new SenderExporterContextImpl(this._api, this._kdf, res.exporterSecret, enc);
|
|
2096
|
+
}
|
|
2097
|
+
return new SenderContextImpl(this._api, this._kdf, res, enc);
|
|
2098
|
+
}
|
|
2099
|
+
async _keyScheduleR(mode, sharedSecret, params) {
|
|
2100
|
+
const res = await this._keySchedule(mode, sharedSecret, params);
|
|
2101
|
+
if (res.key === void 0) {
|
|
2102
|
+
return new RecipientExporterContextImpl(this._api, this._kdf, res.exporterSecret);
|
|
2103
|
+
}
|
|
2104
|
+
return new RecipientContextImpl(this._api, this._kdf, res);
|
|
2105
|
+
}
|
|
2106
|
+
_validateInputLength(params) {
|
|
2107
|
+
if (params.info !== void 0 && params.info.byteLength > INFO_LENGTH_LIMIT) {
|
|
2108
|
+
throw new InvalidParamError("Too long info");
|
|
2109
|
+
}
|
|
2110
|
+
if (params.psk !== void 0) {
|
|
2111
|
+
if (params.psk.key.byteLength < MINIMUM_PSK_LENGTH) {
|
|
2112
|
+
throw new InvalidParamError(`PSK must have at least ${MINIMUM_PSK_LENGTH} bytes`);
|
|
2113
|
+
}
|
|
2114
|
+
if (params.psk.key.byteLength > INPUT_LENGTH_LIMIT) {
|
|
2115
|
+
throw new InvalidParamError("Too long psk.key");
|
|
2116
|
+
}
|
|
2117
|
+
if (params.psk.id.byteLength > INPUT_LENGTH_LIMIT) {
|
|
2118
|
+
throw new InvalidParamError("Too long psk.id");
|
|
2119
|
+
}
|
|
2120
|
+
}
|
|
2121
|
+
return;
|
|
2122
|
+
}
|
|
2123
|
+
};
|
|
2124
|
+
|
|
2125
|
+
// node_modules/@hpke/core/esm/src/kems/dhkemNative.js
|
|
2126
|
+
var DhkemP256HkdfSha256Native = class extends Dhkem {
|
|
2127
|
+
constructor() {
|
|
2128
|
+
const kdf = new HkdfSha256Native();
|
|
2129
|
+
const prim = new Ec(KemId.DhkemP256HkdfSha256, kdf);
|
|
2130
|
+
super(KemId.DhkemP256HkdfSha256, prim, kdf);
|
|
2131
|
+
Object.defineProperty(this, "id", {
|
|
2132
|
+
enumerable: true,
|
|
2133
|
+
configurable: true,
|
|
2134
|
+
writable: true,
|
|
2135
|
+
value: KemId.DhkemP256HkdfSha256
|
|
2136
|
+
});
|
|
2137
|
+
Object.defineProperty(this, "secretSize", {
|
|
2138
|
+
enumerable: true,
|
|
2139
|
+
configurable: true,
|
|
2140
|
+
writable: true,
|
|
2141
|
+
value: 32
|
|
2142
|
+
});
|
|
2143
|
+
Object.defineProperty(this, "encSize", {
|
|
2144
|
+
enumerable: true,
|
|
2145
|
+
configurable: true,
|
|
2146
|
+
writable: true,
|
|
2147
|
+
value: 65
|
|
2148
|
+
});
|
|
2149
|
+
Object.defineProperty(this, "publicKeySize", {
|
|
2150
|
+
enumerable: true,
|
|
2151
|
+
configurable: true,
|
|
2152
|
+
writable: true,
|
|
2153
|
+
value: 65
|
|
2154
|
+
});
|
|
2155
|
+
Object.defineProperty(this, "privateKeySize", {
|
|
2156
|
+
enumerable: true,
|
|
2157
|
+
configurable: true,
|
|
2158
|
+
writable: true,
|
|
2159
|
+
value: 32
|
|
2160
|
+
});
|
|
2161
|
+
}
|
|
2162
|
+
};
|
|
2163
|
+
|
|
2164
|
+
// node_modules/@hpke/core/esm/src/native.js
|
|
2165
|
+
var CipherSuite = class extends CipherSuiteNative {
|
|
2166
|
+
};
|
|
2167
|
+
var DhkemP256HkdfSha256 = class extends DhkemP256HkdfSha256Native {
|
|
2168
|
+
};
|
|
2169
|
+
var HkdfSha256 = class extends HkdfSha256Native {
|
|
2170
|
+
};
|
|
2171
|
+
|
|
2172
|
+
// node_modules/@hpke/core/esm/src/kems/dhkemPrimitives/x25519.js
|
|
2173
|
+
var PKCS8_ALG_ID_X25519 = new Uint8Array([
|
|
2174
|
+
48,
|
|
2175
|
+
46,
|
|
2176
|
+
2,
|
|
2177
|
+
1,
|
|
2178
|
+
0,
|
|
2179
|
+
48,
|
|
2180
|
+
5,
|
|
2181
|
+
6,
|
|
2182
|
+
3,
|
|
2183
|
+
43,
|
|
2184
|
+
101,
|
|
2185
|
+
110,
|
|
2186
|
+
4,
|
|
2187
|
+
34,
|
|
2188
|
+
4,
|
|
2189
|
+
32
|
|
2190
|
+
]);
|
|
2191
|
+
|
|
2192
|
+
// node_modules/@hpke/core/esm/src/kems/dhkemPrimitives/x448.js
|
|
2193
|
+
var PKCS8_ALG_ID_X448 = new Uint8Array([
|
|
2194
|
+
48,
|
|
2195
|
+
70,
|
|
2196
|
+
2,
|
|
2197
|
+
1,
|
|
2198
|
+
0,
|
|
2199
|
+
48,
|
|
2200
|
+
5,
|
|
2201
|
+
6,
|
|
2202
|
+
3,
|
|
2203
|
+
43,
|
|
2204
|
+
101,
|
|
2205
|
+
111,
|
|
2206
|
+
4,
|
|
2207
|
+
58,
|
|
2208
|
+
4,
|
|
2209
|
+
56
|
|
2210
|
+
]);
|
|
2211
|
+
|
|
2212
|
+
// src/crypto.ts
|
|
2213
|
+
var suite = new CipherSuite({ kem: new DhkemP256HkdfSha256(), kdf: new HkdfSha256(), aead: new Aes256Gcm() });
|
|
2214
|
+
var v2AAD = (purpose, config, messageID, archiveID) => bytes(JSON.stringify([2, purpose, config.user_id, config.source_id, messageID, archiveID]));
|
|
2215
|
+
async function generateAgreementKey() {
|
|
2216
|
+
cryptoAPI();
|
|
2217
|
+
const pair = await suite.kem.generateKeyPair();
|
|
2218
|
+
return { privateKey: base64(await suite.kem.serializePrivateKey(pair.privateKey)), publicKey: base64(await suite.kem.serializePublicKey(pair.publicKey)) };
|
|
2219
|
+
}
|
|
2220
|
+
async function senderPublicKey(privateKey) {
|
|
2221
|
+
const key = await suite.kem.deserializePrivateKey(decode(privateKey, 32));
|
|
2222
|
+
const jwk = await cryptoAPI().subtle.exportKey("jwk", key);
|
|
2223
|
+
if (!jwk.x || !jwk.y) throw new Error("Sender key cannot be derived");
|
|
2224
|
+
const publicJWK = { kty: "EC", crv: "P-256", x: jwk.x, y: jwk.y };
|
|
2225
|
+
const pub = await cryptoAPI().subtle.importKey("jwk", publicJWK, { name: "ECDH", namedCurve: "P-256" }, true, []);
|
|
2226
|
+
return base64(await cryptoAPI().subtle.exportKey("raw", pub));
|
|
2227
|
+
}
|
|
2228
|
+
async function verifyCertificate(root, kind, userID, id, publicKey, signature) {
|
|
2229
|
+
try {
|
|
2230
|
+
const key = await cryptoAPI().subtle.importKey("raw", decode(root, 65), { name: "ECDSA", namedCurve: "P-256" }, false, ["verify"]);
|
|
2231
|
+
await cryptoAPI().subtle.importKey("raw", decode(publicKey, 65), { name: "ECDH", namedCurve: "P-256" }, false, []);
|
|
2232
|
+
return await cryptoAPI().subtle.verify(
|
|
2233
|
+
{ name: "ECDSA", hash: "SHA-256" },
|
|
2234
|
+
key,
|
|
2235
|
+
decode(signature, 64),
|
|
2236
|
+
bytes(`pushnow-${kind}-v1
|
|
2237
|
+
${userID}
|
|
2238
|
+
${id}
|
|
2239
|
+
${publicKey}`)
|
|
2240
|
+
);
|
|
2241
|
+
} catch {
|
|
2242
|
+
return false;
|
|
2243
|
+
}
|
|
2244
|
+
}
|
|
2245
|
+
async function verifyArchive(config, value) {
|
|
2246
|
+
const archive = validateArchive(value);
|
|
2247
|
+
if (archive.id !== config.archive.id || archive.public_key !== config.archive.public_key || !await verifyCertificate(config.identity_public_key, "archive", config.user_id, archive.id, archive.public_key, archive.certificate)) throw new Error("Invalid or changed account archive");
|
|
2248
|
+
return archive;
|
|
2249
|
+
}
|
|
2250
|
+
async function sealV2(config, archive, purpose, messageID, plaintext) {
|
|
2251
|
+
cryptoAPI();
|
|
2252
|
+
const sender = await suite.createSenderContext({
|
|
2253
|
+
recipientPublicKey: await suite.kem.deserializePublicKey(decode(archive.public_key, 65)),
|
|
2254
|
+
senderKey: await suite.kem.deserializePrivateKey(decode(config.sender_private_key, 32)),
|
|
2255
|
+
info: bytes("pushnow-v2")
|
|
2256
|
+
});
|
|
2257
|
+
return { enc: base64(sender.enc), ciphertext: base64(await sender.seal(bytes(JSON.stringify(plaintext)), v2AAD(purpose, config, messageID, archive.id))) };
|
|
2258
|
+
}
|
|
2259
|
+
async function openSenderGrant(pending, grant) {
|
|
2260
|
+
const ciphertext = decode(grant.ciphertext);
|
|
2261
|
+
if (ciphertext.length > 8192 || ciphertext.length < 16) throw new Error("Invalid authorization grant size");
|
|
2262
|
+
const recipient = await suite.createRecipientContext({
|
|
2263
|
+
recipientKey: await suite.kem.deserializePrivateKey(decode(pending.key.privateKey, 32)),
|
|
2264
|
+
enc: decode(grant.enc, 65),
|
|
2265
|
+
info: bytes("pushnow-sender-grant-v2")
|
|
2266
|
+
});
|
|
2267
|
+
const plaintext = new Uint8Array(await recipient.open(ciphertext, bytes(JSON.stringify([2, "sender-grant", pending.authorization.id, pending.key.publicKey]))));
|
|
2268
|
+
try {
|
|
2269
|
+
return JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(plaintext));
|
|
2270
|
+
} catch {
|
|
2271
|
+
throw new Error("Invalid authorization grant");
|
|
2272
|
+
} finally {
|
|
2273
|
+
plaintext.fill(0);
|
|
2274
|
+
}
|
|
2275
|
+
}
|
|
2276
|
+
|
|
2277
|
+
// src/http.ts
|
|
2278
|
+
var APIError = class extends Error {
|
|
2279
|
+
constructor(status) {
|
|
2280
|
+
super(`PushNow API request failed (HTTP ${status})`);
|
|
2281
|
+
this.status = status;
|
|
2282
|
+
this.name = "APIError";
|
|
2283
|
+
}
|
|
2284
|
+
status;
|
|
2285
|
+
};
|
|
2286
|
+
function pathTemplate(path) {
|
|
2287
|
+
return path.replace(/\/authorizations\/[^/]+\/token$/, "/authorizations/:id/token").replace(/\/attachments\/[^/]+$/, "/attachments/:id");
|
|
2288
|
+
}
|
|
2289
|
+
async function json(response) {
|
|
2290
|
+
if (!response.body) throw new Error("Missing API response");
|
|
2291
|
+
const reader = response.body.getReader(), chunks = [];
|
|
2292
|
+
let size = 0;
|
|
2293
|
+
try {
|
|
2294
|
+
while (true) {
|
|
2295
|
+
const part = await reader.read();
|
|
2296
|
+
if (part.done) break;
|
|
2297
|
+
size += part.value.length;
|
|
2298
|
+
if (size > 2 * 1024 * 1024) {
|
|
2299
|
+
await reader.cancel();
|
|
2300
|
+
throw new Error("API response is too large");
|
|
2301
|
+
}
|
|
2302
|
+
chunks.push(part.value);
|
|
2303
|
+
}
|
|
2304
|
+
} finally {
|
|
2305
|
+
reader.releaseLock();
|
|
2306
|
+
}
|
|
2307
|
+
const data = new Uint8Array(size);
|
|
2308
|
+
let offset = 0;
|
|
2309
|
+
for (const chunk of chunks) {
|
|
2310
|
+
data.set(chunk, offset);
|
|
2311
|
+
offset += chunk.length;
|
|
2312
|
+
}
|
|
2313
|
+
try {
|
|
2314
|
+
return JSON.parse(new TextDecoder().decode(data));
|
|
2315
|
+
} catch {
|
|
2316
|
+
throw new Error("Invalid API JSON response");
|
|
2317
|
+
}
|
|
2318
|
+
}
|
|
2319
|
+
async function request(apiURL, path, options = {}) {
|
|
2320
|
+
const origin = validateAPIURL(apiURL), method = options.method ?? "GET";
|
|
2321
|
+
const started = Date.now(), controller = new AbortController();
|
|
2322
|
+
let status = null, outcome = "network_error";
|
|
2323
|
+
const abort = () => controller.abort();
|
|
2324
|
+
options.signal?.addEventListener("abort", abort, { once: true });
|
|
2325
|
+
if (options.signal?.aborted) controller.abort();
|
|
2326
|
+
const timer = setTimeout(abort, 3e4);
|
|
2327
|
+
try {
|
|
2328
|
+
controller.signal.throwIfAborted();
|
|
2329
|
+
const headers = {};
|
|
2330
|
+
if (options.token) headers.authorization = `Bearer ${options.token}`;
|
|
2331
|
+
if (options.body !== void 0) headers["content-type"] = options.binary ? "application/octet-stream" : "application/json";
|
|
2332
|
+
if (options.messageID) headers["idempotency-key"] = options.messageID;
|
|
2333
|
+
const response = await (options.fetcher ?? fetch)(new URL(path, origin), {
|
|
2334
|
+
method,
|
|
2335
|
+
headers,
|
|
2336
|
+
redirect: "error",
|
|
2337
|
+
credentials: "omit",
|
|
2338
|
+
cache: "no-store",
|
|
2339
|
+
signal: controller.signal,
|
|
2340
|
+
...options.body === void 0 ? {} : { body: options.binary ? options.body : JSON.stringify(options.body) }
|
|
2341
|
+
});
|
|
2342
|
+
status = response.status;
|
|
2343
|
+
if (!response.ok) {
|
|
2344
|
+
outcome = "http_error";
|
|
2345
|
+
await response.body?.cancel();
|
|
2346
|
+
throw new APIError(status);
|
|
2347
|
+
}
|
|
2348
|
+
const result = status === 204 ? null : await json(response);
|
|
2349
|
+
outcome = "success";
|
|
2350
|
+
return result;
|
|
2351
|
+
} catch (error) {
|
|
2352
|
+
if (controller.signal.aborted) {
|
|
2353
|
+
outcome = "aborted";
|
|
2354
|
+
throw new DOMException("Request aborted or timed out", "AbortError");
|
|
2355
|
+
}
|
|
2356
|
+
if (error instanceof APIError) throw error;
|
|
2357
|
+
throw new Error("PushNow request failed or returned an invalid response");
|
|
2358
|
+
} finally {
|
|
2359
|
+
clearTimeout(timer);
|
|
2360
|
+
options.signal?.removeEventListener("abort", abort);
|
|
2361
|
+
try {
|
|
2362
|
+
void Promise.resolve(options.onRequest?.(Object.freeze({
|
|
2363
|
+
method,
|
|
2364
|
+
path: pathTemplate(path),
|
|
2365
|
+
status,
|
|
2366
|
+
durationMs: Math.max(0, Date.now() - started),
|
|
2367
|
+
outcome
|
|
2368
|
+
}))).catch(() => {
|
|
2369
|
+
});
|
|
2370
|
+
} catch {
|
|
2371
|
+
}
|
|
2372
|
+
}
|
|
2373
|
+
}
|
|
2374
|
+
function authenticated(config, path, options = {}) {
|
|
2375
|
+
const validated = validateConfig(config);
|
|
2376
|
+
return request(validated.api_url, path, { ...options, token: validated.source_key });
|
|
2377
|
+
}
|
|
2378
|
+
|
|
2379
|
+
// src/recipients.ts
|
|
2380
|
+
async function verifyDirectory(input, value) {
|
|
2381
|
+
const config = validateConfig(input), directory = object(structuredClone(value));
|
|
2382
|
+
if (directory.user_id !== config.user_id || directory.source_id !== config.source_id || directory.identity_public_key !== config.identity_public_key) throw new Error("Account or source identity changed");
|
|
2383
|
+
if (typeof directory.source_public_key !== "string" || typeof directory.source_certificate !== "string" || !await verifyCertificate(config.identity_public_key, "source", config.user_id, config.source_id, directory.source_public_key, directory.source_certificate)) throw new Error("Invalid source certificate");
|
|
2384
|
+
if (await senderPublicKey(config.sender_private_key) !== directory.source_public_key) throw new Error("Sender key does not match source");
|
|
2385
|
+
await verifyArchive(config, directory.archive);
|
|
2386
|
+
if (!Array.isArray(directory.devices) || directory.devices.length > 1e3) throw new Error("Invalid device directory");
|
|
2387
|
+
const ids = /* @__PURE__ */ new Set();
|
|
2388
|
+
for (const value2 of directory.devices) {
|
|
2389
|
+
const d = object(value2);
|
|
2390
|
+
uuid(d.id);
|
|
2391
|
+
if (ids.has(d.id) || d.user_id !== config.user_id || d.status !== "active" || typeof d.notifications_enabled !== "boolean" || typeof d.name !== "string" || typeof d.platform !== "string" || typeof d.public_key !== "string" || typeof d.certificate !== "string" || !await verifyCertificate(config.identity_public_key, "device", config.user_id, d.id, d.public_key, d.certificate)) throw new Error("Invalid device certificate or metadata");
|
|
2392
|
+
ids.add(d.id);
|
|
2393
|
+
}
|
|
2394
|
+
return directory;
|
|
2395
|
+
}
|
|
2396
|
+
async function recipientsV2(input, options = {}) {
|
|
2397
|
+
const config = validateConfig(input);
|
|
2398
|
+
return verifyDirectory(config, await authenticated(config, "/v2/recipients", options));
|
|
2399
|
+
}
|
|
2400
|
+
|
|
2401
|
+
// src/auth.ts
|
|
2402
|
+
async function beginLogin(apiURL, name, options = {}) {
|
|
2403
|
+
if (typeof name !== "string" || !name.trim() || name.trim().length > 80) throw new Error("Sender name must have 1 to 80 characters");
|
|
2404
|
+
options.signal?.throwIfAborted();
|
|
2405
|
+
const api_url = validateAPIURL(apiURL), key = await generateAgreementKey();
|
|
2406
|
+
const value = object(await request(api_url, "/v2/authorizations", { ...options, method: "POST", body: { name: name.trim(), public_key: key.publicKey } }));
|
|
2407
|
+
uuid(value.id);
|
|
2408
|
+
if (typeof value.device_code !== "string" || typeof value.user_code !== "string" || typeof value.expires_at !== "string" || !Number.isFinite(Date.parse(value.expires_at)) || Date.parse(value.expires_at) <= Date.now()) throw new Error("Invalid authorization response");
|
|
2409
|
+
return {
|
|
2410
|
+
api_url,
|
|
2411
|
+
key,
|
|
2412
|
+
authorization: {
|
|
2413
|
+
id: value.id,
|
|
2414
|
+
device_code: value.device_code,
|
|
2415
|
+
user_code: value.user_code,
|
|
2416
|
+
expires_at: value.expires_at,
|
|
2417
|
+
interval: typeof value.interval === "number" && Number.isFinite(value.interval) ? Math.max(3, value.interval) : 3
|
|
2418
|
+
},
|
|
2419
|
+
fingerprint: await fingerprint(key.publicKey)
|
|
2420
|
+
};
|
|
2421
|
+
}
|
|
2422
|
+
async function wait(ms, signal) {
|
|
2423
|
+
signal?.throwIfAborted();
|
|
2424
|
+
await new Promise((resolve, reject) => {
|
|
2425
|
+
const abort = () => {
|
|
2426
|
+
clearTimeout(timer);
|
|
2427
|
+
signal?.removeEventListener("abort", abort);
|
|
2428
|
+
reject(new DOMException("Login aborted", "AbortError"));
|
|
2429
|
+
};
|
|
2430
|
+
const timer = setTimeout(() => {
|
|
2431
|
+
signal?.removeEventListener("abort", abort);
|
|
2432
|
+
resolve();
|
|
2433
|
+
}, ms);
|
|
2434
|
+
signal?.addEventListener("abort", abort, { once: true });
|
|
2435
|
+
if (signal?.aborted) abort();
|
|
2436
|
+
});
|
|
2437
|
+
}
|
|
2438
|
+
async function finishLogin(input, options) {
|
|
2439
|
+
if (!options || options.expectedIdentityFingerprint === void 0 && typeof options.confirmIdentity !== "function") throw new Error("Explicit account identity verification is required");
|
|
2440
|
+
const expected = options.expectedIdentityFingerprint?.toLowerCase();
|
|
2441
|
+
if (expected !== void 0 && !/^[a-f0-9]{64}$/.test(expected)) throw new Error("Expected identity fingerprint must be 64 hexadecimal characters");
|
|
2442
|
+
const pending = structuredClone(input), { authorization, key } = pending;
|
|
2443
|
+
const api_url = validateAPIURL(pending.api_url);
|
|
2444
|
+
if (await senderPublicKey(key.privateKey) !== key.publicKey) throw new Error("Pending authorization key mismatch");
|
|
2445
|
+
uuid(authorization.id);
|
|
2446
|
+
while (Date.now() < Date.parse(authorization.expires_at)) {
|
|
2447
|
+
options.signal?.throwIfAborted();
|
|
2448
|
+
let response;
|
|
2449
|
+
try {
|
|
2450
|
+
response = object(await request(
|
|
2451
|
+
api_url,
|
|
2452
|
+
`/v2/authorizations/${encodeURIComponent(authorization.id)}/token`,
|
|
2453
|
+
{ ...options, method: "POST", body: { device_code: authorization.device_code } }
|
|
2454
|
+
));
|
|
2455
|
+
} catch (error) {
|
|
2456
|
+
if (!(error instanceof APIError) || error.status !== 429) throw error;
|
|
2457
|
+
}
|
|
2458
|
+
if (response?.status === "approved") {
|
|
2459
|
+
const grant = object(await openSenderGrant(pending, object(response.grant)));
|
|
2460
|
+
const config = validateConfig({ ...grant, sender_private_key: key.privateKey });
|
|
2461
|
+
if (config.api_url !== api_url) throw new Error("Authorization API origin changed");
|
|
2462
|
+
await verifyArchive(config, config.archive);
|
|
2463
|
+
const accountFingerprint = await fingerprint(config.identity_public_key);
|
|
2464
|
+
const confirmed = expected !== void 0 ? expected === accountFingerprint : await options.confirmIdentity?.({ fingerprint: accountFingerprint, userID: config.user_id });
|
|
2465
|
+
if (confirmed !== true) throw new Error("Account identity not confirmed; discard this authorization");
|
|
2466
|
+
await recipientsV2(config, options);
|
|
2467
|
+
return config;
|
|
2468
|
+
}
|
|
2469
|
+
if (response && response.status !== "pending") throw new Error("Unexpected authorization state");
|
|
2470
|
+
const remaining = Date.parse(authorization.expires_at) - Date.now();
|
|
2471
|
+
if (remaining > 0) await wait(Math.min(remaining, Math.max(3, Number(authorization.interval) || 3) * 1e3), options.signal);
|
|
2472
|
+
}
|
|
2473
|
+
throw new Error("Authorization expired; start login again");
|
|
2474
|
+
}
|
|
2475
|
+
async function beginAccountLogin(apiURL, accessToken, name, options = {}) {
|
|
2476
|
+
if (!name.trim() || name.trim().length > 80) throw new Error("Invalid sender name");
|
|
2477
|
+
const api_url = validateAPIURL(apiURL), key = await generateAgreementKey();
|
|
2478
|
+
const value = object(await request(api_url, "/v2/account-authorizations", { ...options, token: accessToken, method: "POST", body: { name: name.trim(), public_key: key.publicKey } }));
|
|
2479
|
+
uuid(value.id);
|
|
2480
|
+
uuid(value.user_id);
|
|
2481
|
+
if (typeof value.device_code !== "string" || typeof value.user_code !== "string" || typeof value.expires_at !== "string" || !Number.isFinite(Date.parse(value.expires_at)) || Date.parse(value.expires_at) <= Date.now() || typeof value.identity_public_key !== "string") throw new Error("Invalid account authorization");
|
|
2482
|
+
return { api_url, key, authorization: { id: value.id, device_code: value.device_code, user_code: value.user_code, expires_at: value.expires_at, interval: 3 }, fingerprint: await fingerprint(key.publicKey), accountUserID: value.user_id, expectedIdentityFingerprint: await fingerprint(value.identity_public_key) };
|
|
2483
|
+
}
|
|
2484
|
+
async function finishAccountLogin(input, options = {}) {
|
|
2485
|
+
const config = await finishLogin(input, { ...options, expectedIdentityFingerprint: input.expectedIdentityFingerprint });
|
|
2486
|
+
if (config.user_id !== input.accountUserID) throw new Error("Authorization account changed");
|
|
2487
|
+
return config;
|
|
2488
|
+
}
|
|
2489
|
+
|
|
2490
|
+
// src/attachments.ts
|
|
2491
|
+
var maxAttachmentSize = 20 * 1024 * 1024 - 16;
|
|
2492
|
+
function validateAttachmentMetadata(metadata) {
|
|
2493
|
+
if (!metadata || typeof metadata.name !== "string" || !metadata.name.trim() || metadata.name.length > 255 || /[\x00-\x1f]/.test(metadata.name)) throw new Error("Invalid attachment name");
|
|
2494
|
+
if (metadata.mime !== void 0 && (typeof metadata.mime !== "string" || !/^[\w!#$&^.+-]+\/[\w!#$&^.+-]+(?:;[^\r\n]*)?$/.test(metadata.mime) || metadata.mime.length > 255)) throw new Error("Invalid attachment MIME type");
|
|
2495
|
+
if (metadata.id !== void 0) uuid(metadata.id);
|
|
2496
|
+
return { ...metadata };
|
|
2497
|
+
}
|
|
2498
|
+
function validateAttachmentData(data) {
|
|
2499
|
+
const size = typeof Blob !== "undefined" && data instanceof Blob ? data.size : data instanceof Uint8Array || data instanceof ArrayBuffer ? data.byteLength : NaN;
|
|
2500
|
+
if (!Number.isFinite(size)) throw new Error("Attachment must be a Blob, Uint8Array or ArrayBuffer");
|
|
2501
|
+
if (size > maxAttachmentSize) throw new Error("Attachment exceeds the 20 MiB encrypted size limit");
|
|
2502
|
+
}
|
|
2503
|
+
function validateDescriptor(value) {
|
|
2504
|
+
const d = object(value);
|
|
2505
|
+
uuid(d.id);
|
|
2506
|
+
validateAttachmentMetadata({ id: d.id, name: d.name, mime: d.mime });
|
|
2507
|
+
if (typeof d.mime !== "string" || !Number.isSafeInteger(d.size) || d.size < 0 || d.size > maxAttachmentSize || typeof d.read_token !== "string" || !/^[A-Za-z0-9_-]{43}$/.test(d.read_token) || typeof d.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(d.sha256)) throw new Error("Invalid attachment descriptor");
|
|
2508
|
+
decode(d.key, 32);
|
|
2509
|
+
decode(d.nonce, 12);
|
|
2510
|
+
return {
|
|
2511
|
+
id: d.id,
|
|
2512
|
+
name: d.name,
|
|
2513
|
+
mime: d.mime,
|
|
2514
|
+
size: d.size,
|
|
2515
|
+
read_token: d.read_token,
|
|
2516
|
+
key: d.key,
|
|
2517
|
+
nonce: d.nonce,
|
|
2518
|
+
sha256: d.sha256
|
|
2519
|
+
};
|
|
2520
|
+
}
|
|
2521
|
+
async function uploadAttachment(input, data, metadata, options = {}) {
|
|
2522
|
+
const config = validateConfig(input), meta = validateAttachmentMetadata(metadata);
|
|
2523
|
+
validateAttachmentData(data);
|
|
2524
|
+
options.signal?.throwIfAborted();
|
|
2525
|
+
const clear = typeof Blob !== "undefined" && data instanceof Blob ? new Uint8Array(await data.arrayBuffer()) : data instanceof Uint8Array ? new Uint8Array(data) : new Uint8Array(data.slice(0));
|
|
2526
|
+
const key = cryptoAPI().getRandomValues(new Uint8Array(32)), nonce = cryptoAPI().getRandomValues(new Uint8Array(12));
|
|
2527
|
+
const id = meta.id ?? cryptoAPI().randomUUID();
|
|
2528
|
+
try {
|
|
2529
|
+
const aes = await cryptoAPI().subtle.importKey("raw", key, "AES-GCM", false, ["encrypt"]);
|
|
2530
|
+
const ciphertext = await cryptoAPI().subtle.encrypt({
|
|
2531
|
+
name: "AES-GCM",
|
|
2532
|
+
iv: nonce,
|
|
2533
|
+
additionalData: bytes(JSON.stringify([2, "attachment", config.user_id, config.source_id, id]))
|
|
2534
|
+
}, aes, clear);
|
|
2535
|
+
const descriptor = {
|
|
2536
|
+
id,
|
|
2537
|
+
name: meta.name,
|
|
2538
|
+
mime: meta.mime ?? "application/octet-stream",
|
|
2539
|
+
size: clear.length,
|
|
2540
|
+
read_token: base64(cryptoAPI().getRandomValues(new Uint8Array(32))).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, ""),
|
|
2541
|
+
key: base64(key),
|
|
2542
|
+
nonce: base64(nonce),
|
|
2543
|
+
sha256: await sha256(clear)
|
|
2544
|
+
};
|
|
2545
|
+
await authenticated(config, "/v2/attachments", { ...options, method: "POST", body: { id, size: ciphertext.byteLength, read_token: descriptor.read_token } });
|
|
2546
|
+
await authenticated(config, `/v2/attachments/${id}`, { ...options, method: "PUT", binary: true, body: ciphertext });
|
|
2547
|
+
return descriptor;
|
|
2548
|
+
} finally {
|
|
2549
|
+
key.fill(0);
|
|
2550
|
+
clear.fill(0);
|
|
2551
|
+
}
|
|
2552
|
+
}
|
|
2553
|
+
|
|
2554
|
+
// src/messages.ts
|
|
2555
|
+
var bindings = /* @__PURE__ */ new WeakMap();
|
|
2556
|
+
var binding = (config) => JSON.stringify([config.api_url, config.user_id, config.source_id, config.identity_public_key, config.sender_private_key, config.archive.id, config.archive.public_key]);
|
|
2557
|
+
function validateContent(input) {
|
|
2558
|
+
const value = object(input);
|
|
2559
|
+
if (Object.keys(value).some((k) => !["title", "body", "links", "attachments", "image_id", "icon_id"].includes(k))) throw new Error("Unsupported message content field; pass routing fields such as sound in MessageOptions");
|
|
2560
|
+
if (typeof value.title !== "string" || typeof value.body !== "string") throw new Error("Message needs title and body");
|
|
2561
|
+
const links = value.links ?? [], attachments = value.attachments ?? [];
|
|
2562
|
+
if (!Array.isArray(links) || links.some((link) => typeof link !== "string") || !Array.isArray(attachments) || attachments.length > 20) throw new Error("Invalid links or attachment count");
|
|
2563
|
+
const descriptors = attachments.map(validateDescriptor), ids = new Set(descriptors.map((d) => d.id));
|
|
2564
|
+
if (ids.size !== descriptors.length) throw new Error("Duplicate attachment");
|
|
2565
|
+
for (const id of [value.image_id, value.icon_id]) if (id !== void 0) {
|
|
2566
|
+
uuid(id);
|
|
2567
|
+
if (!ids.has(id)) throw new Error("Image and icon must refer to an attached file");
|
|
2568
|
+
}
|
|
2569
|
+
const full = {
|
|
2570
|
+
title: value.title,
|
|
2571
|
+
body: value.body,
|
|
2572
|
+
links: [...links],
|
|
2573
|
+
attachments: descriptors,
|
|
2574
|
+
...value.image_id === void 0 ? {} : { image_id: value.image_id },
|
|
2575
|
+
...value.icon_id === void 0 ? {} : { icon_id: value.icon_id }
|
|
2576
|
+
};
|
|
2577
|
+
if (bytes(JSON.stringify(full)).length + 16 > 256 * 1024) throw new Error("Encrypted message manifest exceeds 256 KiB");
|
|
2578
|
+
return full;
|
|
2579
|
+
}
|
|
2580
|
+
function timestamp(value) {
|
|
2581
|
+
if (value === void 0) return void 0;
|
|
2582
|
+
if (typeof value !== "string") throw new Error("Invalid ISO timestamp");
|
|
2583
|
+
const match = /^(\d{4}-\d{2}-\d{2})T(\d{2}:\d{2}:\d{2})(?:\.(\d{1,3}))?(Z|[+-]\d{2}:\d{2})$/.exec(value);
|
|
2584
|
+
if (!match) throw new Error("Invalid ISO timestamp");
|
|
2585
|
+
const local = `${match[1]}T${match[2]}.${(match[3] ?? "").padEnd(3, "0")}Z`;
|
|
2586
|
+
if (!Number.isFinite(Date.parse(value)) || !Number.isFinite(Date.parse(local)) || new Date(local).toISOString() !== local) throw new Error("Invalid ISO timestamp");
|
|
2587
|
+
return new Date(value).toISOString();
|
|
2588
|
+
}
|
|
2589
|
+
function validateMessageOptions(options) {
|
|
2590
|
+
if (options.sound !== void 0 && !["default", "silent", "chime"].includes(options.sound)) throw new Error("Invalid sound; use default, silent or chime");
|
|
2591
|
+
if (options.inboxOnly !== void 0 && typeof options.inboxOnly !== "boolean") throw new Error("inboxOnly must be boolean");
|
|
2592
|
+
if (options.inboxOnly && options.deviceIds !== void 0) throw new Error("Choose inboxOnly or deviceIds, not both");
|
|
2593
|
+
if (options.deviceIds !== void 0) {
|
|
2594
|
+
if (!Array.isArray(options.deviceIds) || options.deviceIds.length > 100) throw new Error("Invalid target count");
|
|
2595
|
+
options.deviceIds.forEach(uuid);
|
|
2596
|
+
if (new Set(options.deviceIds).size !== options.deviceIds.length) throw new Error("Duplicate target");
|
|
2597
|
+
}
|
|
2598
|
+
if (options.messageID !== void 0) uuid(options.messageID);
|
|
2599
|
+
if (options.sourceKind !== void 0 && !["web", "cli", "api", "subscription"].includes(options.sourceKind)) throw new Error("Invalid source kind");
|
|
2600
|
+
const scheduledAt = timestamp(options.scheduledAt), expiresAt = timestamp(options.expiresAt), now = Date.now(), end = now + 30 * 864e5;
|
|
2601
|
+
if (scheduledAt && (Date.parse(scheduledAt) <= now || Date.parse(scheduledAt) > end)) throw new Error("Schedule must be in the next 30 days");
|
|
2602
|
+
if (expiresAt && (Date.parse(expiresAt) <= (scheduledAt ? Date.parse(scheduledAt) : now) || Date.parse(expiresAt) > end)) throw new Error("Expiry must follow delivery and be within 30 days");
|
|
2603
|
+
return { ...options, deviceIds: options.deviceIds && [...options.deviceIds], scheduledAt, expiresAt };
|
|
2604
|
+
}
|
|
2605
|
+
function truncateUTF8(value, limit) {
|
|
2606
|
+
let result = "", size = 0;
|
|
2607
|
+
for (const char of value) {
|
|
2608
|
+
const n = bytes(char).length;
|
|
2609
|
+
if (size + n > limit) break;
|
|
2610
|
+
result += char;
|
|
2611
|
+
size += n;
|
|
2612
|
+
}
|
|
2613
|
+
return result;
|
|
2614
|
+
}
|
|
2615
|
+
async function prepareMessageV2(input, inputDirectory, plaintext, inputOptions = {}) {
|
|
2616
|
+
const config = validateConfig(input), full = validateContent(plaintext), options = validateMessageOptions(inputOptions);
|
|
2617
|
+
const directory = await verifyDirectory(config, inputDirectory), messageID = options.messageID ?? cryptoAPI().randomUUID();
|
|
2618
|
+
let notify;
|
|
2619
|
+
if (options.inboxOnly) notify = [];
|
|
2620
|
+
else if (options.deviceIds !== void 0) {
|
|
2621
|
+
const selected = directory.devices.filter((d) => options.deviceIds.includes(d.id));
|
|
2622
|
+
if (selected.length !== options.deviceIds.length) throw new Error("Unknown notification device");
|
|
2623
|
+
notify = selected.filter((d) => d.notifications_enabled).map((d) => d.id);
|
|
2624
|
+
}
|
|
2625
|
+
const encrypted = await sealV2(config, directory.archive, "message", messageID, full);
|
|
2626
|
+
const previewData = { title: truncateUTF8(full.title, 400), body: truncateUTF8(full.body, 700) };
|
|
2627
|
+
const image = full.attachments.find((a) => a.id === full.image_id);
|
|
2628
|
+
if (image && bytes(JSON.stringify(image)).length <= 600) previewData.image = image;
|
|
2629
|
+
const previewSize = (envelope) => bytes(JSON.stringify({
|
|
2630
|
+
aps: { alert: { title: "PushNow", body: "You have a new encrypted reminder." }, "mutable-content": 1, sound: "pushnow-chime.wav" },
|
|
2631
|
+
secure_v2: {
|
|
2632
|
+
message_id: messageID,
|
|
2633
|
+
user_id: config.user_id,
|
|
2634
|
+
source_id: config.source_id,
|
|
2635
|
+
archive_id: directory.archive.id,
|
|
2636
|
+
device_id: "00000000-0000-0000-0000-000000000000",
|
|
2637
|
+
...envelope,
|
|
2638
|
+
source_public_key: directory.source_public_key,
|
|
2639
|
+
source_certificate: directory.source_certificate,
|
|
2640
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2641
|
+
read_at: null
|
|
2642
|
+
}
|
|
2643
|
+
})).length;
|
|
2644
|
+
let preview = await sealV2(config, directory.archive, "preview", messageID, previewData);
|
|
2645
|
+
if (previewSize(preview) > 3900 || decode(preview.ciphertext).length > 2400) {
|
|
2646
|
+
delete previewData.image;
|
|
2647
|
+
preview = await sealV2(config, directory.archive, "preview", messageID, previewData);
|
|
2648
|
+
}
|
|
2649
|
+
if (previewSize(preview) > 3900 || decode(preview.ciphertext).length > 2400) throw new Error("Encrypted preview is too large");
|
|
2650
|
+
const message = {
|
|
2651
|
+
message_id: messageID,
|
|
2652
|
+
archive_id: directory.archive.id,
|
|
2653
|
+
...encrypted,
|
|
2654
|
+
preview,
|
|
2655
|
+
attachment_ids: full.attachments.map((a) => a.id),
|
|
2656
|
+
...notify === void 0 ? {} : { notify_device_ids: notify },
|
|
2657
|
+
...options.sourceKind === void 0 ? {} : { source_kind: options.sourceKind },
|
|
2658
|
+
...options.scheduledAt === void 0 ? {} : { scheduled_at: options.scheduledAt },
|
|
2659
|
+
...options.expiresAt === void 0 ? {} : { expires_at: options.expiresAt },
|
|
2660
|
+
...options.sound === void 0 ? {} : { sound: options.sound }
|
|
2661
|
+
};
|
|
2662
|
+
Object.freeze(message.preview);
|
|
2663
|
+
Object.freeze(message.attachment_ids);
|
|
2664
|
+
if (message.notify_device_ids) Object.freeze(message.notify_device_ids);
|
|
2665
|
+
Object.freeze(message);
|
|
2666
|
+
bindings.set(message, binding(config));
|
|
2667
|
+
return message;
|
|
2668
|
+
}
|
|
2669
|
+
async function submitMessageV2(input, message, options = {}) {
|
|
2670
|
+
const config = validateConfig(input);
|
|
2671
|
+
if (bindings.get(message) !== binding(config)) throw new Error("Use the original prepared message with its authorized account and source");
|
|
2672
|
+
const result = object(await authenticated(config, "/v2/messages", { ...options, method: "POST", messageID: message.message_id, body: message }));
|
|
2673
|
+
if (result.message_id !== message.message_id || typeof result.deduplicated !== "boolean") throw new Error("Invalid message response");
|
|
2674
|
+
return { message_id: result.message_id, deduplicated: result.deduplicated };
|
|
2675
|
+
}
|
|
2676
|
+
|
|
2677
|
+
// src/send.ts
|
|
2678
|
+
async function sendNotification(input, notification, inputOptions = {}) {
|
|
2679
|
+
const config = validateConfig(input), options = { ...inputOptions, ...validateMessageOptions(inputOptions) };
|
|
2680
|
+
const { files = [], image, icon, ...content } = notification;
|
|
2681
|
+
const full = validateContent(content);
|
|
2682
|
+
if (!Array.isArray(files)) throw new Error("files must be an array");
|
|
2683
|
+
if (image && full.image_id || icon && full.icon_id) throw new Error("Choose a file upload or an existing attachment ID");
|
|
2684
|
+
const uploads = [...files, ...image ? [image] : [], ...icon ? [icon] : []].map((file) => {
|
|
2685
|
+
const meta = validateAttachmentMetadata(file);
|
|
2686
|
+
validateAttachmentData(file.data);
|
|
2687
|
+
return { ...meta, data: file.data };
|
|
2688
|
+
});
|
|
2689
|
+
if (full.attachments.length + uploads.length > 20) throw new Error("Maximum 20 attachments per notification");
|
|
2690
|
+
const knownIDs = [...full.attachments.map((a) => a.id), ...uploads.flatMap((a) => a.id ? [a.id] : [])];
|
|
2691
|
+
if (new Set(knownIDs).size !== knownIDs.length) throw new Error("Duplicate attachment");
|
|
2692
|
+
const directory = await recipientsV2(config, options);
|
|
2693
|
+
if (options.deviceIds?.some((id) => !directory.devices.some((d) => d.id === id))) throw new Error("Unknown notification device");
|
|
2694
|
+
for (let index = 0; index < uploads.length; index++) {
|
|
2695
|
+
const file = uploads[index];
|
|
2696
|
+
const descriptor = await uploadAttachment(config, file.data, file, options);
|
|
2697
|
+
full.attachments.push(descriptor);
|
|
2698
|
+
if (image && index === files.length) full.image_id = descriptor.id;
|
|
2699
|
+
if (icon && index === files.length + (image ? 1 : 0)) full.icon_id = descriptor.id;
|
|
2700
|
+
}
|
|
2701
|
+
const message = await prepareMessageV2(config, directory, full, options);
|
|
2702
|
+
return submitMessageV2(config, message, options);
|
|
2703
|
+
}
|
|
2704
|
+
export {
|
|
2705
|
+
APIError,
|
|
2706
|
+
beginAccountLogin,
|
|
2707
|
+
beginLogin,
|
|
2708
|
+
fingerprint,
|
|
2709
|
+
finishAccountLogin,
|
|
2710
|
+
finishLogin,
|
|
2711
|
+
prepareMessageV2,
|
|
2712
|
+
recipientsV2,
|
|
2713
|
+
sendNotification,
|
|
2714
|
+
submitMessageV2,
|
|
2715
|
+
uploadAttachment,
|
|
2716
|
+
validateConfig
|
|
2717
|
+
};
|
|
2718
|
+
/*! Bundled license information:
|
|
2719
|
+
|
|
2720
|
+
@hpke/common/esm/src/curve/modular.js:
|
|
2721
|
+
@hpke/common/esm/src/curve/montgomery.js:
|
|
2722
|
+
(*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) *)
|
|
2723
|
+
*/
|