glow.ts 1.0.3 → 1.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.
Files changed (121) hide show
  1. package/README.md +6 -15
  2. package/dist/glow.cjs.js +4 -0
  3. package/dist/glow.cjs.js.map +1 -0
  4. package/dist/glow.es.js +993 -0
  5. package/dist/glow.es.js.map +1 -0
  6. package/dist/index.d.ts +544 -0
  7. package/package.json +34 -26
  8. package/dist/cjs2/config.js +0 -18
  9. package/dist/cjs2/config.js.map +0 -1
  10. package/dist/cjs2/crypto-storage/crypto-storage.js +0 -118
  11. package/dist/cjs2/crypto-storage/crypto-storage.js.map +0 -1
  12. package/dist/cjs2/crypto-storage/in-memory-storage.js +0 -36
  13. package/dist/cjs2/crypto-storage/in-memory-storage.js.map +0 -1
  14. package/dist/cjs2/crypto-storage/local-storage.driver.js +0 -36
  15. package/dist/cjs2/crypto-storage/local-storage.driver.js.map +0 -1
  16. package/dist/cjs2/crypto-storage/storage-driver.interface.js +0 -3
  17. package/dist/cjs2/crypto-storage/storage-driver.interface.js.map +0 -1
  18. package/dist/cjs2/index.js +0 -28
  19. package/dist/cjs2/index.js.map +0 -1
  20. package/dist/cjs2/keyring/keyring.js +0 -151
  21. package/dist/cjs2/keyring/keyring.js.map +0 -1
  22. package/dist/cjs2/keys/keys.js +0 -40
  23. package/dist/cjs2/keys/keys.js.map +0 -1
  24. package/dist/cjs2/mailbox/mailbox.js +0 -352
  25. package/dist/cjs2/mailbox/mailbox.js.map +0 -1
  26. package/dist/cjs2/nacl/encryption.helper.js +0 -101
  27. package/dist/cjs2/nacl/encryption.helper.js.map +0 -1
  28. package/dist/cjs2/nacl/js-nacl-driver.js +0 -110
  29. package/dist/cjs2/nacl/js-nacl-driver.js.map +0 -1
  30. package/dist/cjs2/nacl/keypair.interface.js +0 -3
  31. package/dist/cjs2/nacl/keypair.interface.js.map +0 -1
  32. package/dist/cjs2/nacl/nacl-driver.interface.js +0 -3
  33. package/dist/cjs2/nacl/nacl-driver.interface.js.map +0 -1
  34. package/dist/cjs2/nacl/nacl.js +0 -29
  35. package/dist/cjs2/nacl/nacl.js.map +0 -1
  36. package/dist/cjs2/relay/network-error.js +0 -12
  37. package/dist/cjs2/relay/network-error.js.map +0 -1
  38. package/dist/cjs2/relay/relay-factory.js +0 -22
  39. package/dist/cjs2/relay/relay-factory.js.map +0 -1
  40. package/dist/cjs2/relay/relay.js +0 -300
  41. package/dist/cjs2/relay/relay.js.map +0 -1
  42. package/dist/cjs2/utils/utils.js +0 -39
  43. package/dist/cjs2/utils/utils.js.map +0 -1
  44. package/dist/cjs2/zax.interface.js +0 -46
  45. package/dist/cjs2/zax.interface.js.map +0 -1
  46. package/dist/esm/config.js +0 -15
  47. package/dist/esm/config.js.map +0 -1
  48. package/dist/esm/crypto-storage/crypto-storage.js +0 -114
  49. package/dist/esm/crypto-storage/crypto-storage.js.map +0 -1
  50. package/dist/esm/crypto-storage/in-memory-storage.js +0 -32
  51. package/dist/esm/crypto-storage/in-memory-storage.js.map +0 -1
  52. package/dist/esm/crypto-storage/local-storage.driver.js +0 -32
  53. package/dist/esm/crypto-storage/local-storage.driver.js.map +0 -1
  54. package/dist/esm/crypto-storage/storage-driver.interface.js +0 -2
  55. package/dist/esm/crypto-storage/storage-driver.interface.js.map +0 -1
  56. package/dist/esm/index.js +0 -14
  57. package/dist/esm/index.js.map +0 -1
  58. package/dist/esm/keyring/keyring.js +0 -147
  59. package/dist/esm/keyring/keyring.js.map +0 -1
  60. package/dist/esm/keys/keys.js +0 -36
  61. package/dist/esm/keys/keys.js.map +0 -1
  62. package/dist/esm/mailbox/mailbox.js +0 -348
  63. package/dist/esm/mailbox/mailbox.js.map +0 -1
  64. package/dist/esm/nacl/encryption.helper.js +0 -97
  65. package/dist/esm/nacl/encryption.helper.js.map +0 -1
  66. package/dist/esm/nacl/js-nacl-driver.js +0 -106
  67. package/dist/esm/nacl/js-nacl-driver.js.map +0 -1
  68. package/dist/esm/nacl/keypair.interface.js +0 -2
  69. package/dist/esm/nacl/keypair.interface.js.map +0 -1
  70. package/dist/esm/nacl/nacl-driver.interface.js +0 -2
  71. package/dist/esm/nacl/nacl-driver.interface.js.map +0 -1
  72. package/dist/esm/nacl/nacl.js +0 -25
  73. package/dist/esm/nacl/nacl.js.map +0 -1
  74. package/dist/esm/relay/network-error.js +0 -8
  75. package/dist/esm/relay/network-error.js.map +0 -1
  76. package/dist/esm/relay/relay-factory.js +0 -18
  77. package/dist/esm/relay/relay-factory.js.map +0 -1
  78. package/dist/esm/relay/relay.js +0 -293
  79. package/dist/esm/relay/relay.js.map +0 -1
  80. package/dist/esm/utils/utils.js +0 -35
  81. package/dist/esm/utils/utils.js.map +0 -1
  82. package/dist/esm/zax.interface.js +0 -43
  83. package/dist/esm/zax.interface.js.map +0 -1
  84. package/dist/types/config.d.ts +0 -10
  85. package/dist/types/config.d.ts.map +0 -1
  86. package/dist/types/crypto-storage/crypto-storage.d.ts +0 -20
  87. package/dist/types/crypto-storage/crypto-storage.d.ts.map +0 -1
  88. package/dist/types/crypto-storage/in-memory-storage.d.ts +0 -17
  89. package/dist/types/crypto-storage/in-memory-storage.d.ts.map +0 -1
  90. package/dist/types/crypto-storage/local-storage.driver.d.ts +0 -15
  91. package/dist/types/crypto-storage/local-storage.driver.d.ts.map +0 -1
  92. package/dist/types/crypto-storage/storage-driver.interface.d.ts +0 -11
  93. package/dist/types/crypto-storage/storage-driver.interface.d.ts.map +0 -1
  94. package/dist/types/index.d.ts +0 -16
  95. package/dist/types/index.d.ts.map +0 -1
  96. package/dist/types/keyring/keyring.d.ts +0 -43
  97. package/dist/types/keyring/keyring.d.ts.map +0 -1
  98. package/dist/types/keys/keys.d.ts +0 -16
  99. package/dist/types/keys/keys.d.ts.map +0 -1
  100. package/dist/types/mailbox/mailbox.d.ts +0 -148
  101. package/dist/types/mailbox/mailbox.d.ts.map +0 -1
  102. package/dist/types/nacl/encryption.helper.d.ts +0 -37
  103. package/dist/types/nacl/encryption.helper.d.ts.map +0 -1
  104. package/dist/types/nacl/js-nacl-driver.d.ts +0 -39
  105. package/dist/types/nacl/js-nacl-driver.d.ts.map +0 -1
  106. package/dist/types/nacl/keypair.interface.d.ts +0 -5
  107. package/dist/types/nacl/keypair.interface.d.ts.map +0 -1
  108. package/dist/types/nacl/nacl-driver.interface.d.ts +0 -28
  109. package/dist/types/nacl/nacl-driver.interface.d.ts.map +0 -1
  110. package/dist/types/nacl/nacl.d.ts +0 -13
  111. package/dist/types/nacl/nacl.d.ts.map +0 -1
  112. package/dist/types/relay/network-error.d.ts +0 -6
  113. package/dist/types/relay/network-error.d.ts.map +0 -1
  114. package/dist/types/relay/relay-factory.d.ts +0 -10
  115. package/dist/types/relay/relay-factory.d.ts.map +0 -1
  116. package/dist/types/relay/relay.d.ts +0 -88
  117. package/dist/types/relay/relay.d.ts.map +0 -1
  118. package/dist/types/utils/utils.d.ts +0 -9
  119. package/dist/types/utils/utils.d.ts.map +0 -1
  120. package/dist/types/zax.interface.d.ts +0 -101
  121. package/dist/types/zax.interface.d.ts.map +0 -1
@@ -0,0 +1,993 @@
1
+ import { secretbox as k, box as f, randomBytes as K, hash as C } from "tweetnacl";
2
+ import { Mutex as R } from "async-mutex";
3
+ class o {
4
+ static toBase64(e) {
5
+ return typeof btoa < "u" ? btoa(this.decode_latin1(e)) : Buffer.from(this.decode_latin1(e), "latin1").toString("base64");
6
+ }
7
+ static fromBase64(e) {
8
+ return typeof btoa < "u" ? this.encode_latin1(atob(e)) : this.encode_latin1(Buffer.from(e, "base64").toString("latin1"));
9
+ }
10
+ static encode_latin1(e) {
11
+ const t = new Uint8Array(e.length);
12
+ for (let s = 0; s < e.length; s++) {
13
+ const n = e.charCodeAt(s);
14
+ if ((n & 255) !== n) throw { message: "Cannot encode string in Latin1", str: e };
15
+ t[s] = n & 255;
16
+ }
17
+ return t;
18
+ }
19
+ static decode_latin1(e) {
20
+ const t = [];
21
+ for (let s = 0; s < e.length; s++)
22
+ t.push(String.fromCharCode(e[s]));
23
+ return t.join("");
24
+ }
25
+ static toObject(e) {
26
+ return Array.from(e).reduce(
27
+ (t, [s, n]) => Object.assign(t, { [s]: n }),
28
+ {}
29
+ );
30
+ }
31
+ }
32
+ class B {
33
+ constructor() {
34
+ this.crypto_secretbox_KEYBYTES = k.keyLength, this.crypto_box_NONCEBYTES = f.nonceLength;
35
+ }
36
+ async crypto_secretbox_random_nonce() {
37
+ return K(k.nonceLength);
38
+ }
39
+ async crypto_secretbox(e, t, s) {
40
+ return k(e, t, s);
41
+ }
42
+ async crypto_secretbox_open(e, t, s) {
43
+ return k.open(e, t, s);
44
+ }
45
+ async crypto_box(e, t, s, n) {
46
+ return f(e, t, s, n);
47
+ }
48
+ async crypto_box_open(e, t, s, n) {
49
+ return f.open(e, t, s, n);
50
+ }
51
+ async crypto_box_random_nonce() {
52
+ return K(f.nonceLength);
53
+ }
54
+ async crypto_box_keypair() {
55
+ const e = f.keyPair();
56
+ return {
57
+ boxPk: e.publicKey,
58
+ boxSk: e.secretKey
59
+ };
60
+ }
61
+ async crypto_box_keypair_from_raw_sk(e) {
62
+ const t = f.keyPair.fromSecretKey(e);
63
+ return {
64
+ boxPk: t.publicKey,
65
+ boxSk: t.secretKey
66
+ };
67
+ }
68
+ async crypto_box_keypair_from_seed(e) {
69
+ return this.crypto_box_keypair_from_raw_sk(C(e).subarray(0, f.secretKeyLength));
70
+ }
71
+ async crypto_hash_sha256(e) {
72
+ const t = globalThis.crypto;
73
+ if (!t || !t.subtle)
74
+ throw new Error("Web Crypto API is not available. Please use a modern browser or Node.js 16+.");
75
+ const s = await t.subtle.digest("SHA-256", e);
76
+ return new Uint8Array(s);
77
+ }
78
+ async random_bytes(e) {
79
+ return K(e);
80
+ }
81
+ // Helper methods are based on `js-nacl` implementations
82
+ // https://github.com/tonyg/js-nacl/blob/cc70775cfc9d68a04905ca65c7f179b33a18066e/nacl_cooked.js
83
+ async encode_latin1(e) {
84
+ return o.encode_latin1(e);
85
+ }
86
+ async decode_latin1(e) {
87
+ return o.decode_latin1(e);
88
+ }
89
+ async encode_utf8(e) {
90
+ return this.encode_latin1(unescape(encodeURIComponent(e)));
91
+ }
92
+ async decode_utf8(e) {
93
+ return decodeURIComponent(escape(await this.decode_latin1(e)));
94
+ }
95
+ async to_hex(e) {
96
+ const t = [];
97
+ for (let s = 0; s < e.length; s++) {
98
+ const n = "0123456789abcdef";
99
+ t.push(n[e[s] >> 4 & 15]), t.push(n[e[s] & 15]);
100
+ }
101
+ return t.join("");
102
+ }
103
+ async from_hex(e) {
104
+ const t = new Uint8Array(e.length / 2);
105
+ for (let s = 0; s < e.length / 2; s++)
106
+ t[s] = parseInt(e.substr(2 * s, 2), 16);
107
+ return t;
108
+ }
109
+ /**
110
+ * h2(m) = sha256(sha256(64x0 + m))
111
+ * Zero out initial sha256 block, and double hash 0-padded message
112
+ * http://cs.nyu.edu/~dodis/ps/h-of-h.pdf
113
+ */
114
+ async h2(e) {
115
+ e instanceof Uint8Array || (e = await this.encode_latin1(e));
116
+ const t = 64, s = new Uint8Array(t + e.length);
117
+ return s.fill(0), s.set(e, t), this.crypto_hash_sha256(await this.crypto_hash_sha256(s));
118
+ }
119
+ }
120
+ class h {
121
+ constructor() {
122
+ }
123
+ static setDefaultInstance() {
124
+ return this.setInstance(new B());
125
+ }
126
+ static setInstance(e) {
127
+ if (this.driverInstance)
128
+ throw new Error("[NaCl] NaCl driver has been already set, it is supposed to be set only once");
129
+ return this.driverInstance = e, !0;
130
+ }
131
+ static getInstance() {
132
+ if (!this.driverInstance)
133
+ throw new Error("[NaCl] NaCl instance is not yet set");
134
+ return this.driverInstance;
135
+ }
136
+ }
137
+ class w {
138
+ constructor(e) {
139
+ if (this.keys = e, typeof e == "string") {
140
+ const { boxPk: t, boxSk: s } = JSON.parse(e);
141
+ this.keyPair = {
142
+ boxPk: o.fromBase64(t),
143
+ boxSk: o.fromBase64(s)
144
+ };
145
+ } else
146
+ this.keyPair = e;
147
+ }
148
+ static isEqual(e, t) {
149
+ return e.toString() === t.toString();
150
+ }
151
+ toString() {
152
+ return JSON.stringify({
153
+ boxPk: this.publicKey,
154
+ boxSk: this.privateKey
155
+ });
156
+ }
157
+ get publicKey() {
158
+ return o.toBase64(this.keyPair.boxPk);
159
+ }
160
+ get privateKey() {
161
+ return o.toBase64(this.keyPair.boxSk);
162
+ }
163
+ }
164
+ const v = 30 * 1e3, u = {
165
+ NONCE_TAG: "__nc",
166
+ SKEY_TAG: "storage_key",
167
+ STORAGE_ROOT: ".v1.stor.vlt12",
168
+ // Relay tokens, keys and hashes are 32 bytes
169
+ RELAY_TOKEN_LEN: 32,
170
+ // 5 min - Token expiration on the server side, matched with config.x.relay.token_timeout on Zax server
171
+ RELAY_TOKEN_TIMEOUT: 5 * 60 * 1e3 - v,
172
+ // 20 min - Session expiration on the server side, matched with config.x.relay.session_timeout on Zax server
173
+ RELAY_SESSION_TIMEOUT: 20 * 60 * 1e3 - v,
174
+ // 5 sec - Ajax request timeout
175
+ RELAY_AJAX_TIMEOUT: 5 * 1e3
176
+ };
177
+ class M {
178
+ constructor(e = "storage.") {
179
+ this.rootTag = `__glow.${e}`;
180
+ }
181
+ async get(e) {
182
+ return (await this.getMultiple([e]))[0];
183
+ }
184
+ async getMultiple(e) {
185
+ return e.map((t) => localStorage.getItem(this.tag(t)) || null);
186
+ }
187
+ async set(e, t) {
188
+ return this.setMultiple({ [e]: t });
189
+ }
190
+ async setMultiple(e) {
191
+ for (const t in e) {
192
+ const s = e[t];
193
+ s !== null && localStorage.setItem(this.tag(t), s);
194
+ }
195
+ }
196
+ async remove(e) {
197
+ this.removeMultiple([e]);
198
+ }
199
+ async removeMultiple(e) {
200
+ e.forEach((t) => localStorage.removeItem(this.tag(t)));
201
+ }
202
+ tag(e) {
203
+ return `${this.rootTag}.${e}`;
204
+ }
205
+ }
206
+ class E {
207
+ constructor(e, t) {
208
+ const s = h.getInstance();
209
+ this.nacl = s, this.driver = e, this.id = t ? `.${t}${u.STORAGE_ROOT}` : u.STORAGE_ROOT;
210
+ }
211
+ static async new(e) {
212
+ const t = this.getStorageDriver(), s = new E(t, e), n = s.addPrefix(u.SKEY_TAG), r = await t.get(n);
213
+ if (r) {
214
+ const { key: a } = JSON.parse(r);
215
+ s.storageKey = o.fromBase64(a);
216
+ } else
217
+ s.storageKey = await s.nacl.random_bytes(s.nacl.crypto_secretbox_KEYBYTES), await t.set(n, JSON.stringify({ key: o.toBase64(s.storageKey) }));
218
+ return s;
219
+ }
220
+ static getStorageDriver() {
221
+ if (this.storageDriver)
222
+ return this.storageDriver;
223
+ throw new Error("[CryptoStorage] StorageDriver instance is not yet set");
224
+ }
225
+ static setDefaultStorageDriver() {
226
+ return this.setStorageDriver(new M());
227
+ }
228
+ static setStorageDriver(e) {
229
+ if (this.storageDriver)
230
+ throw new Error("[CryptoStorage] StorageDriver has been already set, it is supposed to be set only once");
231
+ return this.storageDriver = e, !0;
232
+ }
233
+ async save(e, t) {
234
+ if (!this.driver)
235
+ throw new Error("[CryptoStorage] Storage driver is not set");
236
+ if (!this.storageKey)
237
+ throw new Error("[CryptoStorage] Storage key is not set");
238
+ const s = JSON.stringify(t), n = await this.nacl.encode_utf8(s), r = await this.nacl.crypto_secretbox_random_nonce(), a = await this.nacl.crypto_secretbox(n, r, this.storageKey);
239
+ return await this.driver.setMultiple({
240
+ [this.addPrefix(e)]: o.toBase64(a),
241
+ [this.addNonceTag(e)]: o.toBase64(r)
242
+ }), !0;
243
+ }
244
+ async get(e) {
245
+ if (!this.driver)
246
+ throw new Error("[CryptoStorage] Storage driver is not set");
247
+ if (!this.storageKey)
248
+ throw new Error("[CryptoStorage] Storage key is not set");
249
+ const [t, s] = await this.driver.getMultiple([this.addPrefix(e), this.addNonceTag(e)]);
250
+ if (!t || !s)
251
+ return null;
252
+ const n = o.fromBase64(t), r = o.fromBase64(s), a = await this.nacl.crypto_secretbox_open(n, r, this.storageKey);
253
+ if (a) {
254
+ const c = await this.nacl.decode_utf8(a);
255
+ return JSON.parse(c);
256
+ } else
257
+ throw new Error("[CryptoStorage] crypto_secretbox_open: decryption error");
258
+ }
259
+ async remove(e) {
260
+ if (!this.driver)
261
+ throw new Error("[CryptoStorage] Storage driver is not set");
262
+ return await this.driver.removeMultiple([this.addPrefix(e), this.addNonceTag(e)]), !0;
263
+ }
264
+ async selfDestruct() {
265
+ if (!this.driver)
266
+ throw new Error("[CryptoStorage] Storage driver is not set");
267
+ await this.driver.remove(this.addPrefix(u.SKEY_TAG));
268
+ }
269
+ // Keys are tagged in the storage with a versioned prefix
270
+ addPrefix(e) {
271
+ return this.id ? e + this.id : e;
272
+ }
273
+ addNonceTag(e) {
274
+ return this.addPrefix(`${u.NONCE_TAG}.${e}`);
275
+ }
276
+ }
277
+ const T = "__::commKey::__", y = class y {
278
+ constructor(e, t, s) {
279
+ this.guestKeys = /* @__PURE__ */ new Map(), this.nacl = e, this.storage = t, this.commKey = s;
280
+ }
281
+ static async new(e) {
282
+ const t = h.getInstance(), s = await E.new(e), n = await y.getCommKeyOrCreate(t, s), r = new y(t, s, n);
283
+ return await r.loadGuestKeys(), r;
284
+ }
285
+ static async fromBackup(e, t) {
286
+ const s = JSON.parse(t), n = o.fromBase64(s[T]), r = await y.new(e);
287
+ await r.setCommFromSecKey(n);
288
+ for (const [a, c] of Object.entries(s))
289
+ a !== T && await r.addGuest(a, c);
290
+ return r;
291
+ }
292
+ getNumberOfGuests() {
293
+ return this.guestKeys.size;
294
+ }
295
+ get guests() {
296
+ return this.guestKeys;
297
+ }
298
+ /**
299
+ * Returns public identity, which is the default communication key.
300
+ * Correspondents can know it, whereas Relays do not need it (other than
301
+ * temporarily for internal use during the ownership proof)
302
+ */
303
+ getPubCommKey() {
304
+ return this.commKey.publicKey;
305
+ }
306
+ getPrivateCommKey() {
307
+ return this.commKey.privateKey;
308
+ }
309
+ /**
310
+ * Returns HPK (hash of the public key) of the mailbox. This is what Zax relays
311
+ * uses as the universal address of the mailbox
312
+ */
313
+ async getHpk() {
314
+ const e = await this.nacl.h2(o.fromBase64(this.commKey.publicKey));
315
+ return o.toBase64(e);
316
+ }
317
+ getTagByHpk(e) {
318
+ for (const [t, s] of this.guestKeys)
319
+ if (s.hpk === e)
320
+ return t;
321
+ return null;
322
+ }
323
+ getGuestKey(e) {
324
+ const t = this.guestKeys.get(e);
325
+ return t ? t.pk : null;
326
+ }
327
+ // Backups
328
+ async backup() {
329
+ const e = {
330
+ [T]: this.commKey.privateKey
331
+ };
332
+ if (this.getNumberOfGuests() > 0)
333
+ for (const [t, s] of this.guestKeys)
334
+ t && s && (e[t] = s.pk);
335
+ return JSON.stringify(e);
336
+ }
337
+ async setCommFromSeed(e) {
338
+ this.commKey = new w(await this.nacl.crypto_box_keypair_from_seed(e)), await this.storage.save(y.commKeyTag, this.commKey.toString());
339
+ }
340
+ async setCommFromSecKey(e) {
341
+ this.commKey = new w(await this.nacl.crypto_box_keypair_from_raw_sk(e)), await this.storage.save(y.commKeyTag, this.commKey.toString());
342
+ }
343
+ async addGuest(e, t) {
344
+ const s = o.toBase64(await this.nacl.h2(o.fromBase64(t)));
345
+ return this.guestKeys.set(e, {
346
+ pk: t,
347
+ hpk: s
348
+ }), await this.saveGuests(), s;
349
+ }
350
+ async removeGuest(e) {
351
+ return this.guestKeys.has(e) && (this.guestKeys.delete(e), await this.saveGuests()), !0;
352
+ }
353
+ async loadGuestKeys() {
354
+ const e = await this.storage.get(y.guestRegistryTag);
355
+ if (e)
356
+ if (typeof e == "object")
357
+ this.guestKeys = new Map(Object.entries(e));
358
+ else
359
+ throw new Error("[Keyring] Guest keys is not an object");
360
+ else return;
361
+ }
362
+ async saveGuests() {
363
+ await this.storage.save(y.guestRegistryTag, o.toObject(this.guestKeys.entries()));
364
+ }
365
+ static async getCommKeyOrCreate(e, t) {
366
+ const s = await t.get(y.commKeyTag);
367
+ if (s && typeof s == "string")
368
+ return new w(s);
369
+ {
370
+ const n = await e.crypto_box_keypair(), r = new w(n);
371
+ return await t.save(y.commKeyTag, r.toString()), r;
372
+ }
373
+ }
374
+ async selfDestruct() {
375
+ await this.storage.remove(y.guestRegistryTag), await this.storage.remove(y.commKeyTag), await this.storage.selfDestruct();
376
+ }
377
+ };
378
+ y.commKeyTag = "comm_key", y.guestRegistryTag = "guest_registry";
379
+ let S = y;
380
+ class p {
381
+ constructor() {
382
+ }
383
+ /**
384
+ * Encodes a binary message with `cryptobox`
385
+ */
386
+ static async encodeMessage(e, t, s, n) {
387
+ const r = h.getInstance(), a = await this.makeNonce(n), c = await r.crypto_box(e, a, t, s);
388
+ return {
389
+ nonce: o.toBase64(a),
390
+ ctext: o.toBase64(c)
391
+ };
392
+ }
393
+ /**
394
+ * Decodes a binary message with `cryptobox_open`
395
+ * @returns null if failed to decode
396
+ */
397
+ static async decodeMessage(e, t, s, n) {
398
+ const r = h.getInstance(), a = await r.crypto_box_open(t, e, s, n);
399
+ return a && await r.decode_utf8(a);
400
+ }
401
+ /**
402
+ * Encodes a binary message with `secretbox` (used for file chunk encryption)
403
+ */
404
+ static async encodeMessageSymmetric(e, t) {
405
+ const s = h.getInstance(), n = await p.makeNonce(), r = await s.crypto_secretbox(e, n, t);
406
+ return {
407
+ nonce: o.toBase64(n),
408
+ ctext: o.toBase64(r)
409
+ };
410
+ }
411
+ /**
412
+ * Decodes a binary message with `secretbox_open` (used for file chunk decryption)
413
+ */
414
+ static async decodeMessageSymmetric(e, t, s) {
415
+ return await h.getInstance().crypto_secretbox_open(o.fromBase64(t), o.fromBase64(e), s);
416
+ }
417
+ // ---------- Nonce helper ----------
418
+ /**
419
+ * Makes a timestamp nonce that a relay expects for any crypto operations.
420
+ * Timestamp is the first 8 bytes, the rest is random, unless custom `data`
421
+ * is specified. `data` will be packed as next 4 bytes after timestamp.
422
+ */
423
+ static async makeNonce(e) {
424
+ const t = h.getInstance(), s = await t.crypto_box_random_nonce();
425
+ let n;
426
+ if (s.length !== t.crypto_box_NONCEBYTES)
427
+ throw new Error("[Mailbox] Wrong crypto_box nonce length");
428
+ n = 8;
429
+ const r = this.itoa(Math.floor(Date.now() / 1e3));
430
+ if (e && (n += 4), s.fill(0, 0, n), s.set(r, 8 - r.length), e) {
431
+ const a = this.itoa(e);
432
+ s.set(a, 12 - a.length);
433
+ }
434
+ return s;
435
+ }
436
+ /**
437
+ * Splits an integer into an array of bytes
438
+ */
439
+ static itoa(e) {
440
+ let t = e.toString(16);
441
+ t = t.length & 1 ? `0${t}` : t;
442
+ const s = t.length / 2, n = new Uint8Array(s);
443
+ for (let r = 0, a = 0; a < t.length; a += 2, r++)
444
+ n[r] = parseInt(t[a] + t[a + 1], 16);
445
+ return n;
446
+ }
447
+ }
448
+ var l = /* @__PURE__ */ ((i) => (i.count = "count", i.upload = "upload", i.download = "download", i.messageStatus = "messageStatus", i.delete = "delete", i.startFileUpload = "startFileUpload", i.uploadFileChunk = "uploadFileChunk", i.downloadFileChunk = "downloadFileChunk", i.fileStatus = "fileStatus", i.deleteFile = "deleteFile", i))(l || {}), b = /* @__PURE__ */ ((i) => (i.message = "message", i.file = "file", i.plain = "plain", i))(b || {});
449
+ class _ extends Error {
450
+ constructor(e) {
451
+ super(`GlowNetworkError status: ${e}`), this.status = e, this.name = "GlowNetworkError";
452
+ }
453
+ }
454
+ class N {
455
+ constructor(e) {
456
+ this.url = e, this.difficulty = 0, this.nacl = h.getInstance();
457
+ }
458
+ get isConnected() {
459
+ return !!(this.sessionKeys && this.publicKey);
460
+ }
461
+ // ---------- Connection initialization ----------
462
+ /**
463
+ * Exchanges tokens with a relay and gets a temp session key for this relay.
464
+ * Returns h₂(signature) and a relay public key
465
+ */
466
+ async openConnection() {
467
+ this.sessionKeys = new w(await this.nacl.crypto_box_keypair()), this.clientToken = await this.nacl.random_bytes(u.RELAY_TOKEN_LEN);
468
+ const e = await this.fetchRelayToken();
469
+ return this.publicKey = await this.fetchRelayPublicKey(e), {
470
+ h2Signature: await this.getSignature(e, this.sessionKeys),
471
+ relayPublicKey: this.publicKey
472
+ };
473
+ }
474
+ /**
475
+ * Sends a client token to a relay and saves a relay token
476
+ */
477
+ async fetchRelayToken() {
478
+ if (!this.clientToken)
479
+ throw new Error("[Relay] clientToken is required please openConnection first");
480
+ const e = await this.httpCall("start_session", o.toBase64(this.clientToken));
481
+ this.scheduleTokenExpiration();
482
+ const [t, s] = this.parseResponse("start_session", e);
483
+ return this.difficulty = parseInt(s, 10), this.difficulty > 10 && console.log(`[Relay] ${this.url} requested difficulty ${this.difficulty}. Session handshake may take longer.`), o.fromBase64(t);
484
+ }
485
+ /**
486
+ * Completes the handshake and saves a relay pubic key
487
+ */
488
+ async fetchRelayPublicKey(e) {
489
+ if (!this.clientToken)
490
+ throw new Error("[Relay] clientToken is required please openConnection first");
491
+ const t = o.toBase64(await this.nacl.h2(this.clientToken)), s = new Uint8Array([...this.clientToken, ...e]);
492
+ let n;
493
+ this.difficulty === 0 ? n = await this.nacl.h2(s) : n = await this.ensureNonceDifficulty(s);
494
+ const r = await this.httpCall("verify_session", t, o.toBase64(n));
495
+ return o.fromBase64(r);
496
+ }
497
+ /**
498
+ * Attaches a mailbox and fetches number of messages
499
+ */
500
+ async prove(e) {
501
+ if (!this.clientToken)
502
+ throw new Error("[Relay] clientToken is required please openConnection first");
503
+ if (!this.sessionKeys)
504
+ throw new Error("[Relay] No session key found, open the connection first");
505
+ const t = o.toBase64(await this.nacl.h2(this.clientToken)), s = await this.httpCall(
506
+ "prove",
507
+ t,
508
+ this.sessionKeys.publicKey,
509
+ e.nonce,
510
+ e.ctext
511
+ );
512
+ return this.scheduleSessionExpiration(), s;
513
+ }
514
+ async encodeMessage(e) {
515
+ if (!this.publicKey)
516
+ throw new Error("[Relay] No relay public key found, open the connection first");
517
+ if (!this.sessionKeys)
518
+ throw new Error("[Relay] No session key found, open the connection first");
519
+ return await p.encodeMessage(
520
+ await this.nacl.encode_utf8(e),
521
+ this.publicKey,
522
+ o.fromBase64(this.sessionKeys?.privateKey)
523
+ );
524
+ }
525
+ async decodeMessage(e, t) {
526
+ const s = this.publicKey;
527
+ if (!s)
528
+ throw new Error("[Relay] No relay public key found, open the connection first");
529
+ if (!this.sessionKeys)
530
+ throw new Error("[Relay] No session key found, open the connection first");
531
+ const n = await p.decodeMessage(
532
+ o.fromBase64(e),
533
+ o.fromBase64(t),
534
+ s,
535
+ o.fromBase64(this.sessionKeys.privateKey)
536
+ );
537
+ if (n === null)
538
+ throw new Error("[Relay] failed to decode message");
539
+ return JSON.parse(n);
540
+ }
541
+ // ---------- Low-level server request handling ----------
542
+ /**
543
+ * Executes a message/file command on a relay, parses and validates the response
544
+ */
545
+ async runCmd(e, t, s, n) {
546
+ if (!Object.keys(l).includes(e))
547
+ throw new Error(`[Relay] ${this.url} doesn't support command ${e}`);
548
+ const r = [t, s.nonce, s.ctext];
549
+ n && r.push(n);
550
+ const a = await this.httpCall("command", ...r);
551
+ return this.parseResponse(e, a);
552
+ }
553
+ async getSignature(e, t) {
554
+ if (!this.clientToken)
555
+ throw new Error("[Relay] clientToken is required please openConnection first");
556
+ const s = o.fromBase64(t.publicKey), n = new Uint8Array([...s, ...e, ...this.clientToken]);
557
+ return await this.nacl.h2(n);
558
+ }
559
+ /**
560
+ * Executes a call to a relay and return raw string response
561
+ */
562
+ // TODO: extract fetching into separate function
563
+ async httpCall(e, ...t) {
564
+ const s = new AbortController(), n = setTimeout(() => s.abort(), u.RELAY_AJAX_TIMEOUT), r = {
565
+ method: "POST",
566
+ headers: {
567
+ Accept: "text/plain",
568
+ "Content-Type": "text/plain"
569
+ },
570
+ body: t.join(`\r
571
+ `),
572
+ signal: s.signal
573
+ };
574
+ try {
575
+ const a = await fetch(`${this.url}/${e}`, r);
576
+ if (!a.ok)
577
+ throw a.status === 401 && (this.clearSession(), this.clearToken()), new _(a.status);
578
+ return await a.text();
579
+ } catch (a) {
580
+ throw a instanceof Error && a.name === "AbortError" ? new _(408) : a instanceof _ ? a : a instanceof TypeError ? new _(0) : a;
581
+ } finally {
582
+ clearTimeout(n);
583
+ }
584
+ }
585
+ /**
586
+ * Parses relay response and throws an error if its format is unexpected
587
+ */
588
+ parseResponse(e, t) {
589
+ const s = t.split(`\r
590
+ `);
591
+ if (!t || !this.validateResponse(e, s.length))
592
+ throw console.log(s), new Error(`[Relay] ${this.url} - ${e}: Bad response`);
593
+ return s;
594
+ }
595
+ /**
596
+ * Compares the expected number of lines in response with what was actually received from a relay
597
+ */
598
+ validateResponse(e, t) {
599
+ switch (e) {
600
+ case l.upload:
601
+ case l.messageStatus:
602
+ case l.delete:
603
+ return t === 1;
604
+ case l.downloadFileChunk:
605
+ return t === 3;
606
+ default:
607
+ return t === 2;
608
+ }
609
+ }
610
+ /**
611
+ * delete token locally before it was removed on server so will reconnect without getting unauthorized error
612
+ */
613
+ scheduleTokenExpiration() {
614
+ this.tokenExpirationTimeoutHandle && clearTimeout(this.tokenExpirationTimeoutHandle), this.tokenExpirationTimeoutHandle = setTimeout(() => this.clearToken(), u.RELAY_TOKEN_TIMEOUT);
615
+ }
616
+ clearToken() {
617
+ this.tokenExpirationTimeoutHandle && clearTimeout(this.tokenExpirationTimeoutHandle), this.clientToken && delete this.clientToken;
618
+ }
619
+ /**
620
+ * established session is valid only for some period need to remove it after it's ttl
621
+ * so relay will reconnect without receiving error from server
622
+ */
623
+ scheduleSessionExpiration() {
624
+ this.sessionExpirationTimeoutHandle && clearTimeout(this.sessionExpirationTimeoutHandle), this.sessionExpirationTimeoutHandle = setTimeout(() => {
625
+ this.clearSession();
626
+ }, u.RELAY_SESSION_TIMEOUT);
627
+ }
628
+ clearSession() {
629
+ this.sessionExpirationTimeoutHandle && clearTimeout(this.sessionExpirationTimeoutHandle), this.sessionKeys && delete this.sessionKeys;
630
+ }
631
+ // ---------- Difficulty adjustment ----------
632
+ /**
633
+ * Continuously calculates the nonce until one requested by a relay is found
634
+ */
635
+ async ensureNonceDifficulty(e) {
636
+ let t, s;
637
+ do
638
+ t = await this.nacl.random_bytes(32), s = await this.nacl.h2(new Uint8Array([...e, ...t]));
639
+ while (!this.arrayZeroBits(s));
640
+ return t;
641
+ }
642
+ /**
643
+ * Returns `true` if the rightmost n bits of a byte are 0.
644
+ * Check whether the rightmost difficulty bits of an Uint8Array are 0, where
645
+ * the lowest indexes of the array represent those rightmost bits. Thus if
646
+ * the difficulty is 17, then array[0] and array[1] should be 0, as should the
647
+ * rightmost bit of array[2]. This is used for our difficulty settings in Zax to
648
+ * reduce burden on a busy server by ensuring clients have to do some
649
+ * additional work during the session handshake
650
+ */
651
+ arrayZeroBits(e) {
652
+ let t, s = this.difficulty;
653
+ for (let n = 0; n <= 1 + this.difficulty / 8; n++) {
654
+ if (t = e[n], s <= 0)
655
+ return !0;
656
+ if (s > 8) {
657
+ if (s -= 8, t > 0)
658
+ return !1;
659
+ } else
660
+ return this.firstZeroBits(t, s);
661
+ }
662
+ return !1;
663
+ }
664
+ /**
665
+ * Returns `true` if the rightmost n bits of a byte are 0
666
+ */
667
+ firstZeroBits(e, t) {
668
+ return e === e >> t << t;
669
+ }
670
+ }
671
+ class O {
672
+ constructor() {
673
+ this.relays = {};
674
+ }
675
+ /**
676
+ * Relay factory, that returns a Relay instance for a given URL,
677
+ * or creates a new one if it hasn't yet been initialized.
678
+ */
679
+ getInstance(e) {
680
+ let t = this.relays[e];
681
+ return t || (t = this.relays[e] = new N(e)), t;
682
+ }
683
+ }
684
+ class x {
685
+ constructor(e, t, s) {
686
+ this.relayFactory = new O(), this.relayConnectionMutexes = /* @__PURE__ */ new Map(), this.nacl = e, this.keyRing = t, this.identity = s;
687
+ }
688
+ static async new(e) {
689
+ return new x(h.getInstance(), await S.new(e), e);
690
+ }
691
+ // ---------- Alternative initializers ----------
692
+ /**
693
+ * Create a Mailbox where the secret identity key is derived from a well-known seed
694
+ */
695
+ static async fromSeed(e, t) {
696
+ const s = await this.new(e);
697
+ return t instanceof Uint8Array || (t = o.encode_latin1(t)), await s.keyRing.setCommFromSeed(t), s;
698
+ }
699
+ /**
700
+ * Create a Mailbox from the known secret identity key
701
+ */
702
+ static async fromSecKey(e, t) {
703
+ const s = await this.new(e);
704
+ return t instanceof Uint8Array || (t = o.fromBase64(t)), await s.keyRing.setCommFromSecKey(t), s;
705
+ }
706
+ /**
707
+ * Create a Mailbox from the backup string
708
+ */
709
+ static async fromBackup(e, t) {
710
+ return new x(h.getInstance(), await S.fromBackup(e, t), e);
711
+ }
712
+ // ---------- Relay message commands (public API) ----------
713
+ /**
714
+ * Sends a free-form object to a guest we already have in our keyring. Set `encrypt` to `false` to
715
+ * send a plaintext message. Returns a token that can be used with `messageStatus` command to check
716
+ * the status of the message
717
+ */
718
+ async upload(e, t, s, n = !0) {
719
+ const r = await this.prepareRelay(e), a = this.getGuestKey(t), c = n ? await this.encodeMessage(t, s) : s, d = o.toBase64(await this.nacl.h2(o.fromBase64(a))), [g] = await this.runRelayCommand(r, l.upload, { to: d, payload: c });
720
+ return g;
721
+ }
722
+ /**
723
+ * Downloads all messages from a relay, decrypts them with a relay key,
724
+ * and then parses each message to find out if it's a text message, file message,
725
+ * or if it can't be decrypted because HPK is missing in the keyring.
726
+ * Returns an array of mixed messages
727
+ */
728
+ async download(e) {
729
+ const t = await this.prepareRelay(e), s = await this.runRelayCommand(t, l.download), n = await this.decryptResponse(t, s), r = [];
730
+ for (const a of n) {
731
+ const c = this.keyRing.getTagByHpk(a.from);
732
+ if (!c)
733
+ r.push(await this.parsePlainMessage(a));
734
+ else if (a.kind === "message")
735
+ r.push(await this.parseTextMessage(a, c));
736
+ else if (a.kind === "file")
737
+ r.push(await this.parseFileMessage(a, c));
738
+ else
739
+ throw new Error("[Mailbox] download - Unknown message type");
740
+ }
741
+ return r;
742
+ }
743
+ /**
744
+ * Marks a raw Zax message as one that can't be decrypted,
745
+ * because sender's HPK is not found in the keyring
746
+ */
747
+ async parsePlainMessage({ data: e, time: t, from: s, nonce: n }) {
748
+ return { data: e, time: t, from: s, nonce: n, kind: b.plain };
749
+ }
750
+ /**
751
+ * Decrypts a message that represents uploaded file metadata
752
+ */
753
+ async parseFileMessage(e, t) {
754
+ const { nonce: s, ctext: n, uploadID: r } = JSON.parse(e.data), a = await this.decodeMessage(t, s, n);
755
+ if (a === null)
756
+ throw new Error("[Mailbox] Failed to decode file message");
757
+ return { data: JSON.parse(a), time: e.time, senderTag: t, uploadID: r, nonce: s, kind: b.file };
758
+ }
759
+ /**
760
+ * Attempts to decrypt a regular encrypted Zax message. Returns plain message if it was sent encrypted
761
+ */
762
+ async parseTextMessage(e, t) {
763
+ let s = await this.decodeMessage(t, e.nonce, e.data);
764
+ return s || (s = e.data), { data: s, time: e.time, senderTag: t, nonce: e.nonce, kind: b.message };
765
+ }
766
+ /**
767
+ * Returns the number of messages in the mailbox on a given relay
768
+ */
769
+ async count(e) {
770
+ const t = await this.prepareRelay(e), s = await this.runRelayCommand(t, l.count);
771
+ return await this.decryptResponse(t, s);
772
+ }
773
+ /**
774
+ * Deletes messages from a relay given a list of base64 message nonces,
775
+ * and returns the number of remaining messages
776
+ */
777
+ async delete(e, t) {
778
+ const s = await this.prepareRelay(e), [n] = await this.runRelayCommand(s, l.delete, { payload: t });
779
+ return parseInt(n, 10);
780
+ }
781
+ /**
782
+ * Gets the status of a previously sent Zax message by a storage token.
783
+ * Returns "time to live" in seconds or a negative value if it's not applicable.
784
+ * See `MessageStatusResponse` values for reference
785
+ */
786
+ async messageStatus(e, t) {
787
+ const s = await this.prepareRelay(e), [n] = await this.runRelayCommand(s, l.messageStatus, { token: t });
788
+ return parseInt(n, 10);
789
+ }
790
+ // ---------- Relay file commands (public API) ----------
791
+ /**
792
+ * Asks Zax to start a new upload session, and returns a unique file identifier
793
+ * required to upload file chunks.
794
+ */
795
+ async startFileUpload(e, t, s) {
796
+ const n = await this.prepareRelay(e), r = this.getGuestKey(t), a = o.toBase64(await this.nacl.h2(o.fromBase64(r))), c = await this.nacl.random_bytes(this.nacl.crypto_secretbox_KEYBYTES);
797
+ s.skey = o.toBase64(c);
798
+ const d = await this.encodeMessage(t, JSON.stringify(s)), g = await this.runRelayCommand(n, l.startFileUpload, {
799
+ to: a,
800
+ file_size: s.orig_size,
801
+ metadata: d
802
+ }), m = await this.decryptResponse(n, g);
803
+ return m.skey = c, m;
804
+ }
805
+ /**
806
+ * Encrypts the file chunk symmetrically and transfers it to a relay
807
+ */
808
+ async uploadFileChunk(e, t, s, n, r, a) {
809
+ const c = await this.prepareRelay(e), d = await p.encodeMessageSymmetric(s, a), g = await this.runRelayCommand(c, l.uploadFileChunk, {
810
+ uploadID: t,
811
+ part: n,
812
+ last_chunk: r - 1 === n,
813
+ // marker of the last chunk, sent only once
814
+ nonce: d.nonce
815
+ }, d.ctext);
816
+ return await this.decryptResponse(c, g);
817
+ }
818
+ /**
819
+ * Returns the status of a file upload by its relay-specific uploadID. Uploader can call it
820
+ * to verify the correct transfer, and downloader can check if the file exists and retrieve
821
+ * the number of chunks
822
+ */
823
+ async getFileStatus(e, t) {
824
+ const s = await this.prepareRelay(e), n = await this.runRelayCommand(s, l.fileStatus, { uploadID: t });
825
+ return await this.decryptResponse(s, n);
826
+ }
827
+ /**
828
+ * Fetches the file metadata by uploadID, which was declared by the uploader
829
+ */
830
+ async getFileMetadata(e, t) {
831
+ return (await this.download(e)).filter((r) => r.kind === "file").find((r) => r.uploadID === t)?.data;
832
+ }
833
+ /**
834
+ * Downloads a binary chunk of a file from a relay by a given uploadID. The total number of chunks
835
+ * can be retrieved via a `getFileStatus` request
836
+ */
837
+ async downloadFileChunk(e, t, s, n) {
838
+ n instanceof Uint8Array || (n = o.fromBase64(n));
839
+ const r = await this.prepareRelay(e), a = await this.runRelayCommand(r, l.downloadFileChunk, { uploadID: t, part: s }), [c, d, g] = a, m = await r.decodeMessage(c, d);
840
+ return await p.decodeMessageSymmetric(m.nonce, g, n);
841
+ }
842
+ /**
843
+ * Deletes a file from the relay (or all chunks uploaded so far, if the upload was not completed).
844
+ * Can be called by either the sender or recipient
845
+ */
846
+ async deleteFile(e, t) {
847
+ const s = await this.prepareRelay(e), n = await this.runRelayCommand(s, l.deleteFile, { uploadID: t });
848
+ return await this.decryptResponse(s, n);
849
+ }
850
+ // ---------- Dealing with Relay ----------
851
+ /**
852
+ * Establishes a session, exchanges temp keys and proves our ownership of this
853
+ * Mailbox to this specific relay. This is the first function to start
854
+ * communications with any relay. Returns the number of messages in the mailbox
855
+ */
856
+ async connectToRelay(e) {
857
+ const t = this.relayFactory.getInstance(e), s = await t.openConnection(), n = await this.encryptSignature(s), r = await t.prove(await t.encodeMessage(JSON.stringify({
858
+ pub_key: this.keyRing.getPubCommKey(),
859
+ nonce: n.nonce,
860
+ ctext: n.ctext
861
+ })));
862
+ return parseInt(r, 10);
863
+ }
864
+ clearSession(e) {
865
+ const t = this.relayFactory.getInstance(e);
866
+ t.clearToken(), t.clearSession();
867
+ }
868
+ async encryptSignature(e) {
869
+ const t = o.fromBase64(this.keyRing.getPrivateCommKey());
870
+ return await p.encodeMessage(e.h2Signature, e.relayPublicKey, t);
871
+ }
872
+ /**
873
+ * Gets a singleton Relay instance, and reconnects to a relay if a previous token has expired
874
+ */
875
+ async prepareRelay(e) {
876
+ const t = this.relayFactory.getInstance(e);
877
+ return await this.getRelayConnectionMutex(e).runExclusive(async () => {
878
+ t.isConnected || await this.connectToRelay(e);
879
+ }), t;
880
+ }
881
+ /**
882
+ * Encrypts the payload of the command and sends it to a relay
883
+ */
884
+ async runRelayCommand(e, t, s, n) {
885
+ s = { cmd: t, ...s };
886
+ const r = await this.keyRing.getHpk(), a = await e.encodeMessage(JSON.stringify(s));
887
+ return await e.runCmd(t, r, a, n);
888
+ }
889
+ /**
890
+ * Parses relay's response to a command, for those commands that expect an encrypted message in return.
891
+ * Two lines of POST response will be nonce and ctext
892
+ */
893
+ async decryptResponse(e, t) {
894
+ const [s, n] = t;
895
+ return await e.decodeMessage(s, n);
896
+ }
897
+ // ---------- Message encoding / decoding ----------
898
+ /**
899
+ * Encodes `message` to the guest key of a guest already
900
+ * added to the keyring
901
+ */
902
+ async encodeMessage(e, t) {
903
+ const s = this.getGuestKey(e), n = this.keyRing.getPrivateCommKey();
904
+ return await p.encodeMessage(
905
+ await this.nacl.encode_utf8(t),
906
+ o.fromBase64(s),
907
+ o.fromBase64(n)
908
+ );
909
+ }
910
+ /**
911
+ * Decodes a ciphertext from a guest key already in our keyring with this nonce
912
+ * @returns null if failed to decode
913
+ */
914
+ async decodeMessage(e, t, s) {
915
+ const n = this.getGuestKey(e), r = this.keyRing.getPrivateCommKey();
916
+ let a;
917
+ try {
918
+ a = o.fromBase64(s);
919
+ } catch {
920
+ return null;
921
+ }
922
+ return await p.decodeMessage(
923
+ o.fromBase64(t),
924
+ a,
925
+ o.fromBase64(n),
926
+ o.fromBase64(r)
927
+ );
928
+ }
929
+ /**
930
+ * Wrapper around `keyring.getGuestKey` that handles unknown guests
931
+ */
932
+ getGuestKey(e) {
933
+ const t = this.keyRing.getGuestKey(e);
934
+ if (!t)
935
+ throw new Error(`[Mailbox] Unknown guest ${e}`);
936
+ return t;
937
+ }
938
+ // ---------- Destroying Mailbox ----------
939
+ /**
940
+ * Deletes a Mailbox and all its data from local CryptoStorage. This is a very
941
+ * destructive operation, use with caution - it will delete the Mailbox
942
+ * keyring along with all stored public keys. To restore that information, you
943
+ * will need to do another key exchange with all the guests on your keyring.
944
+ */
945
+ async selfDestruct() {
946
+ await this.keyRing.selfDestruct();
947
+ }
948
+ getRelayConnectionMutex(e) {
949
+ return this.relayConnectionMutexes.has(e) || this.relayConnectionMutexes.set(e, new R()), this.relayConnectionMutexes.get(e);
950
+ }
951
+ }
952
+ class A {
953
+ constructor() {
954
+ this.storage = {};
955
+ }
956
+ async get(e) {
957
+ return (await this.getMultiple([e]))[0];
958
+ }
959
+ async getMultiple(e) {
960
+ return e.map((t) => this.storage[t]);
961
+ }
962
+ set(e, t) {
963
+ return this.setMultiple({ [e]: t });
964
+ }
965
+ async setMultiple(e) {
966
+ for (const t in e)
967
+ this.storage[t] = e[t];
968
+ }
969
+ remove(e) {
970
+ return this.removeMultiple([e]);
971
+ }
972
+ async removeMultiple(e) {
973
+ e.forEach((t) => delete this.storage[t]);
974
+ }
975
+ reset() {
976
+ this.storage = {};
977
+ }
978
+ }
979
+ export {
980
+ E as CryptoStorage,
981
+ _ as GlowNetworkError,
982
+ A as InMemoryStorage,
983
+ B as JsNaClDriver,
984
+ S as KeyRing,
985
+ w as Keys,
986
+ M as LocalStorageDriver,
987
+ x as Mailbox,
988
+ h as NaCl,
989
+ N as Relay,
990
+ o as Utils,
991
+ b as ZaxMessageKind
992
+ };
993
+ //# sourceMappingURL=glow.es.js.map