@haex-space/vault-sdk 2.5.117 → 2.5.119

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -2,62 +2,363 @@
2
2
 
3
3
  var sqliteProxy = require('drizzle-orm/sqlite-proxy');
4
4
 
5
- // src/polyfills/localStorage.ts
6
- function installLocalStoragePolyfill() {
7
- if (typeof window === "undefined") {
8
- return;
9
- }
10
- console.log("[HaexSpace] Storage Polyfill loading immediately");
11
- let localStorageWorks = false;
12
- try {
13
- const testKey = "__ls_test__";
14
- localStorage.setItem(testKey, testKey);
15
- localStorage.removeItem(testKey);
16
- localStorageWorks = true;
17
- } catch {
18
- console.warn("[HaexSpace] localStorage blocked \u2013 using in-memory fallback");
5
+ var __defProp = Object.defineProperty;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __esm = (fn, res) => function __init() {
8
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
9
+ };
10
+ var __export = (target, all) => {
11
+ for (var name in all)
12
+ __defProp(target, name, { get: all[name], enumerable: true });
13
+ };
14
+
15
+ // src/crypto/vaultKey.ts
16
+ async function deriveKeyFromPassword(password, salt) {
17
+ const encoder = new TextEncoder();
18
+ const passwordBuffer = encoder.encode(password);
19
+ const saltBuffer = new Uint8Array(salt);
20
+ const keyMaterial = await crypto.subtle.importKey(
21
+ "raw",
22
+ passwordBuffer,
23
+ "PBKDF2",
24
+ false,
25
+ ["deriveKey"]
26
+ );
27
+ return await crypto.subtle.deriveKey(
28
+ {
29
+ name: "PBKDF2",
30
+ salt: saltBuffer,
31
+ iterations: PBKDF2_ITERATIONS,
32
+ hash: "SHA-256"
33
+ },
34
+ keyMaterial,
35
+ { name: ALGORITHM, length: KEY_LENGTH },
36
+ false,
37
+ // not extractable
38
+ ["encrypt", "decrypt"]
39
+ );
40
+ }
41
+ function generateVaultKey() {
42
+ return crypto.getRandomValues(new Uint8Array(32));
43
+ }
44
+ async function encryptString(data, derivedKey) {
45
+ const nonce = crypto.getRandomValues(new Uint8Array(12));
46
+ const encoder = new TextEncoder();
47
+ const dataBuffer = encoder.encode(data);
48
+ const encryptedBuffer = await crypto.subtle.encrypt(
49
+ {
50
+ name: ALGORITHM,
51
+ iv: nonce
52
+ },
53
+ derivedKey,
54
+ dataBuffer
55
+ );
56
+ return {
57
+ encryptedData: arrayBufferToBase64(encryptedBuffer),
58
+ nonce: arrayBufferToBase64(nonce)
59
+ };
60
+ }
61
+ async function decryptString(encryptedData, nonce, derivedKey) {
62
+ const encryptedBuffer = base64ToArrayBuffer(encryptedData);
63
+ const nonceBuffer = base64ToArrayBuffer(nonce);
64
+ const encryptedDataBuffer = new Uint8Array(encryptedBuffer);
65
+ const iv = new Uint8Array(nonceBuffer);
66
+ const decryptedBuffer = await crypto.subtle.decrypt(
67
+ {
68
+ name: ALGORITHM,
69
+ iv
70
+ },
71
+ derivedKey,
72
+ encryptedDataBuffer
73
+ );
74
+ const decoder = new TextDecoder();
75
+ return decoder.decode(decryptedBuffer);
76
+ }
77
+ async function encryptVaultKey(vaultKey, password) {
78
+ const salt = crypto.getRandomValues(new Uint8Array(32));
79
+ const derivedKey = await deriveKeyFromPassword(password, salt);
80
+ const nonce = crypto.getRandomValues(new Uint8Array(12));
81
+ const vaultKeyBuffer = new Uint8Array(vaultKey);
82
+ const encryptedBuffer = await crypto.subtle.encrypt(
83
+ {
84
+ name: ALGORITHM,
85
+ iv: nonce
86
+ },
87
+ derivedKey,
88
+ vaultKeyBuffer
89
+ );
90
+ return {
91
+ encryptedVaultKey: arrayBufferToBase64(encryptedBuffer),
92
+ salt: arrayBufferToBase64(salt),
93
+ vaultKeyNonce: arrayBufferToBase64(nonce)
94
+ };
95
+ }
96
+ async function decryptVaultKey(encryptedVaultKey, salt, vaultKeyNonce, password) {
97
+ const encryptedBuffer = base64ToArrayBuffer(encryptedVaultKey);
98
+ const saltBuffer = base64ToArrayBuffer(salt);
99
+ const nonceBuffer = base64ToArrayBuffer(vaultKeyNonce);
100
+ const derivedKey = await deriveKeyFromPassword(password, saltBuffer);
101
+ const encryptedData = new Uint8Array(encryptedBuffer);
102
+ const iv = new Uint8Array(nonceBuffer);
103
+ const decryptedBuffer = await crypto.subtle.decrypt(
104
+ {
105
+ name: ALGORITHM,
106
+ iv
107
+ },
108
+ derivedKey,
109
+ encryptedData
110
+ );
111
+ return new Uint8Array(decryptedBuffer);
112
+ }
113
+ async function decryptVaultName(encryptedVaultName, vaultNameNonce, vaultNameSalt, password) {
114
+ const saltBuffer = base64ToArrayBuffer(vaultNameSalt);
115
+ const derivedKey = await deriveKeyFromPassword(password, saltBuffer);
116
+ return decryptString(encryptedVaultName, vaultNameNonce, derivedKey);
117
+ }
118
+ async function encryptCrdtData(data, vaultKey) {
119
+ const vaultKeyBuffer = new Uint8Array(vaultKey);
120
+ const cryptoKey = await crypto.subtle.importKey(
121
+ "raw",
122
+ vaultKeyBuffer,
123
+ { name: ALGORITHM },
124
+ false,
125
+ ["encrypt"]
126
+ );
127
+ const nonce = crypto.getRandomValues(new Uint8Array(12));
128
+ const encoder = new TextEncoder();
129
+ const dataBuffer = encoder.encode(JSON.stringify(data));
130
+ const encryptedBuffer = await crypto.subtle.encrypt(
131
+ {
132
+ name: ALGORITHM,
133
+ iv: nonce
134
+ },
135
+ cryptoKey,
136
+ dataBuffer
137
+ );
138
+ return {
139
+ encryptedData: arrayBufferToBase64(encryptedBuffer),
140
+ nonce: arrayBufferToBase64(nonce)
141
+ };
142
+ }
143
+ async function wrapKey(keyToWrap, wrappingKey) {
144
+ const cryptoKey = await crypto.subtle.importKey(
145
+ "raw",
146
+ new Uint8Array(wrappingKey),
147
+ { name: ALGORITHM },
148
+ false,
149
+ ["encrypt"]
150
+ );
151
+ const nonce = crypto.getRandomValues(new Uint8Array(12));
152
+ const ciphertext = await crypto.subtle.encrypt(
153
+ { name: ALGORITHM, iv: nonce },
154
+ cryptoKey,
155
+ new Uint8Array(keyToWrap)
156
+ );
157
+ const result = new Uint8Array(12 + ciphertext.byteLength);
158
+ result.set(nonce, 0);
159
+ result.set(new Uint8Array(ciphertext), 12);
160
+ return result;
161
+ }
162
+ async function unwrapKey(wrappedKey, wrappingKey) {
163
+ const cryptoKey = await crypto.subtle.importKey(
164
+ "raw",
165
+ new Uint8Array(wrappingKey),
166
+ { name: ALGORITHM },
167
+ false,
168
+ ["decrypt"]
169
+ );
170
+ const nonce = wrappedKey.slice(0, 12);
171
+ const ciphertext = wrappedKey.slice(12);
172
+ const plaintext = await crypto.subtle.decrypt(
173
+ { name: ALGORITHM, iv: nonce },
174
+ cryptoKey,
175
+ ciphertext
176
+ );
177
+ return new Uint8Array(plaintext);
178
+ }
179
+ async function decryptCrdtData(encryptedData, nonce, vaultKey) {
180
+ const vaultKeyBuffer = new Uint8Array(vaultKey);
181
+ const cryptoKey = await crypto.subtle.importKey(
182
+ "raw",
183
+ vaultKeyBuffer,
184
+ { name: ALGORITHM },
185
+ false,
186
+ ["decrypt"]
187
+ );
188
+ const encryptedBuffer = base64ToArrayBuffer(encryptedData);
189
+ const nonceBuffer = base64ToArrayBuffer(nonce);
190
+ const encryptedDataBuffer = new Uint8Array(encryptedBuffer);
191
+ const iv = new Uint8Array(nonceBuffer);
192
+ const decryptedBuffer = await crypto.subtle.decrypt(
193
+ {
194
+ name: ALGORITHM,
195
+ iv
196
+ },
197
+ cryptoKey,
198
+ encryptedDataBuffer
199
+ );
200
+ const decoder = new TextDecoder();
201
+ const jsonString = decoder.decode(decryptedBuffer);
202
+ return JSON.parse(jsonString);
203
+ }
204
+ function arrayBufferToBase64(buffer) {
205
+ const bytes = buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer);
206
+ if (typeof Buffer !== "undefined") {
207
+ return Buffer.from(bytes).toString("base64");
19
208
  }
20
- if (!localStorageWorks) {
21
- const lsStorage = /* @__PURE__ */ new Map();
22
- const localStoragePoly = {
23
- getItem(key) {
24
- return lsStorage.get(key) || null;
25
- },
26
- setItem(key, value) {
27
- lsStorage.set(key, String(value));
28
- },
29
- removeItem(key) {
30
- lsStorage.delete(key);
31
- },
32
- clear() {
33
- lsStorage.clear();
34
- },
35
- get length() {
36
- return lsStorage.size;
37
- },
38
- key(index) {
39
- return Array.from(lsStorage.keys())[index] || null;
40
- }
41
- };
42
- try {
43
- Object.defineProperty(window, "localStorage", {
44
- value: localStoragePoly,
45
- writable: true,
46
- configurable: true
47
- });
48
- } catch {
49
- window.localStorage = localStoragePoly;
209
+ let binary = "";
210
+ for (let i = 0; i < bytes.length; i++) {
211
+ const byte = bytes[i];
212
+ if (byte !== void 0) {
213
+ binary += String.fromCharCode(byte);
50
214
  }
51
- console.log("[HaexSpace] localStorage replaced with in-memory polyfill");
52
215
  }
216
+ return btoa(binary);
53
217
  }
54
- function installSessionStoragePolyfill() {
55
- if (typeof window === "undefined") {
56
- return;
218
+ function base64ToArrayBuffer(base64) {
219
+ if (typeof Buffer !== "undefined") {
220
+ return new Uint8Array(Buffer.from(base64, "base64"));
57
221
  }
58
- try {
59
- const sessionStoragePoly = {
60
- getItem() {
222
+ const binary = atob(base64);
223
+ const bytes = new Uint8Array(binary.length);
224
+ for (let i = 0; i < binary.length; i++) {
225
+ bytes[i] = binary.charCodeAt(i);
226
+ }
227
+ return bytes;
228
+ }
229
+ var PBKDF2_ITERATIONS, KEY_LENGTH, ALGORITHM;
230
+ var init_vaultKey = __esm({
231
+ "src/crypto/vaultKey.ts"() {
232
+ PBKDF2_ITERATIONS = 6e5;
233
+ KEY_LENGTH = 256;
234
+ ALGORITHM = "AES-GCM";
235
+ }
236
+ });
237
+
238
+ // src/crypto/userKeypair.ts
239
+ var userKeypair_exports = {};
240
+ __export(userKeypair_exports, {
241
+ KEY_AGREEMENT_ALGO: () => exports.KEY_AGREEMENT_ALGO,
242
+ SIGNING_ALGO: () => exports.SIGNING_ALGO,
243
+ decryptPrivateKeyAsync: () => decryptPrivateKeyAsync,
244
+ encryptPrivateKeyAsync: () => encryptPrivateKeyAsync,
245
+ exportUserKeypairAsync: () => exportUserKeypairAsync,
246
+ generateUserKeypairAsync: () => generateUserKeypairAsync,
247
+ importPrivateKeyForKeyAgreementAsync: () => importPrivateKeyForKeyAgreementAsync,
248
+ importPublicKeyForKeyAgreementAsync: () => importPublicKeyForKeyAgreementAsync,
249
+ importUserPrivateKeyAsync: () => importUserPrivateKeyAsync,
250
+ importUserPublicKeyAsync: () => importUserPublicKeyAsync
251
+ });
252
+ async function generateUserKeypairAsync() {
253
+ const keypair = await crypto.subtle.generateKey(exports.SIGNING_ALGO, true, ["sign", "verify"]);
254
+ return { publicKey: keypair.publicKey, privateKey: keypair.privateKey };
255
+ }
256
+ async function exportUserKeypairAsync(keypair) {
257
+ const pub = await crypto.subtle.exportKey("spki", keypair.publicKey);
258
+ const priv = await crypto.subtle.exportKey("pkcs8", keypair.privateKey);
259
+ return { publicKey: arrayBufferToBase64(pub), privateKey: arrayBufferToBase64(priv) };
260
+ }
261
+ async function importUserPublicKeyAsync(base64) {
262
+ return crypto.subtle.importKey("spki", base64ToArrayBuffer(base64), exports.SIGNING_ALGO, true, ["verify"]);
263
+ }
264
+ async function importUserPrivateKeyAsync(base64) {
265
+ return crypto.subtle.importKey("pkcs8", base64ToArrayBuffer(base64), exports.SIGNING_ALGO, true, ["sign"]);
266
+ }
267
+ async function importPublicKeyForKeyAgreementAsync(base64) {
268
+ return crypto.subtle.importKey("spki", base64ToArrayBuffer(base64), exports.KEY_AGREEMENT_ALGO, true, []);
269
+ }
270
+ async function importPrivateKeyForKeyAgreementAsync(base64) {
271
+ return crypto.subtle.importKey("pkcs8", base64ToArrayBuffer(base64), exports.KEY_AGREEMENT_ALGO, true, ["deriveBits"]);
272
+ }
273
+ async function encryptPrivateKeyAsync(privateKeyBase64, password) {
274
+ const salt = crypto.getRandomValues(new Uint8Array(32));
275
+ const derivedKey = await deriveKeyFromPassword(password, salt);
276
+ const nonce = crypto.getRandomValues(new Uint8Array(12));
277
+ const encrypted = await crypto.subtle.encrypt(
278
+ { name: "AES-GCM", iv: nonce },
279
+ derivedKey,
280
+ new TextEncoder().encode(privateKeyBase64)
281
+ );
282
+ return {
283
+ encryptedPrivateKey: arrayBufferToBase64(encrypted),
284
+ nonce: arrayBufferToBase64(nonce),
285
+ salt: arrayBufferToBase64(salt)
286
+ };
287
+ }
288
+ async function decryptPrivateKeyAsync(encryptedPrivateKey, nonce, salt, password) {
289
+ const derivedKey = await deriveKeyFromPassword(password, base64ToArrayBuffer(salt));
290
+ const decrypted = await crypto.subtle.decrypt(
291
+ { name: "AES-GCM", iv: base64ToArrayBuffer(nonce) },
292
+ derivedKey,
293
+ base64ToArrayBuffer(encryptedPrivateKey)
294
+ );
295
+ return new TextDecoder().decode(decrypted);
296
+ }
297
+ exports.SIGNING_ALGO = void 0; exports.KEY_AGREEMENT_ALGO = void 0;
298
+ var init_userKeypair = __esm({
299
+ "src/crypto/userKeypair.ts"() {
300
+ init_vaultKey();
301
+ exports.SIGNING_ALGO = { name: "ECDSA", namedCurve: "P-256" };
302
+ exports.KEY_AGREEMENT_ALGO = { name: "ECDH", namedCurve: "P-256" };
303
+ }
304
+ });
305
+
306
+ // src/polyfills/localStorage.ts
307
+ function installLocalStoragePolyfill() {
308
+ if (typeof window === "undefined") {
309
+ return;
310
+ }
311
+ console.log("[HaexSpace] Storage Polyfill loading immediately");
312
+ let localStorageWorks = false;
313
+ try {
314
+ const testKey = "__ls_test__";
315
+ localStorage.setItem(testKey, testKey);
316
+ localStorage.removeItem(testKey);
317
+ localStorageWorks = true;
318
+ } catch {
319
+ console.warn("[HaexSpace] localStorage blocked \u2013 using in-memory fallback");
320
+ }
321
+ if (!localStorageWorks) {
322
+ const lsStorage = /* @__PURE__ */ new Map();
323
+ const localStoragePoly = {
324
+ getItem(key) {
325
+ return lsStorage.get(key) || null;
326
+ },
327
+ setItem(key, value) {
328
+ lsStorage.set(key, String(value));
329
+ },
330
+ removeItem(key) {
331
+ lsStorage.delete(key);
332
+ },
333
+ clear() {
334
+ lsStorage.clear();
335
+ },
336
+ get length() {
337
+ return lsStorage.size;
338
+ },
339
+ key(index) {
340
+ return Array.from(lsStorage.keys())[index] || null;
341
+ }
342
+ };
343
+ try {
344
+ Object.defineProperty(window, "localStorage", {
345
+ value: localStoragePoly,
346
+ writable: true,
347
+ configurable: true
348
+ });
349
+ } catch {
350
+ window.localStorage = localStoragePoly;
351
+ }
352
+ console.log("[HaexSpace] localStorage replaced with in-memory polyfill");
353
+ }
354
+ }
355
+ function installSessionStoragePolyfill() {
356
+ if (typeof window === "undefined") {
357
+ return;
358
+ }
359
+ try {
360
+ const sessionStoragePoly = {
361
+ getItem() {
61
362
  return null;
62
363
  },
63
364
  setItem() {
@@ -643,404 +944,187 @@ var LOCALSEND_COMMANDS = {
643
944
  /** Get current settings */
644
945
  getSettings: "localsend_get_settings",
645
946
  /** Update settings */
646
- setSettings: "localsend_set_settings",
647
- // Discovery (desktop only)
648
- /** Start device discovery via multicast UDP */
649
- startDiscovery: "localsend_start_discovery",
650
- /** Stop device discovery */
651
- stopDiscovery: "localsend_stop_discovery",
652
- /** Get list of discovered devices */
653
- getDevices: "localsend_get_devices",
654
- // Network scan (mobile only)
655
- /** Scan network for devices via HTTP */
656
- scanNetwork: "localsend_scan_network",
657
- // Server (receiving files)
658
- /** Start the HTTPS server for receiving files */
659
- startServer: "localsend_start_server",
660
- /** Stop the HTTPS server */
661
- stopServer: "localsend_stop_server",
662
- /** Get server status */
663
- getServerStatus: "localsend_get_server_status",
664
- /** Get pending incoming transfer requests */
665
- getPendingTransfers: "localsend_get_pending_transfers",
666
- /** Accept an incoming transfer */
667
- acceptTransfer: "localsend_accept_transfer",
668
- /** Reject an incoming transfer */
669
- rejectTransfer: "localsend_reject_transfer",
670
- // Client (sending files)
671
- /** Prepare files for sending - collect metadata */
672
- prepareFiles: "localsend_prepare_files",
673
- /** Send files to a device */
674
- sendFiles: "localsend_send_files",
675
- /** Cancel an outgoing transfer */
676
- cancelSend: "localsend_cancel_send"
677
- };
678
-
679
- // src/commands/spaces.ts
680
- var SPACE_COMMANDS = {
681
- /** Bulk assign rows to spaces */
682
- assign: "extension_space_assign",
683
- /** Bulk unassign rows from spaces */
684
- unassign: "extension_space_unassign",
685
- /** Get space assignments for a table */
686
- getAssignments: "extension_space_get_assignments",
687
- /** List all spaces the user is a member of (with decrypted names) */
688
- list: "extension_space_list",
689
- /** Create a new shared space */
690
- create: "extension_space_create",
691
- /** List available sync backends */
692
- listBackends: "extension_space_list_backends"
693
- };
694
-
695
- // src/commands/index.ts
696
- var TAURI_COMMANDS = {
697
- database: DATABASE_COMMANDS,
698
- permissions: PERMISSIONS_COMMANDS,
699
- web: WEB_COMMANDS,
700
- webStorage: WEB_STORAGE_COMMANDS,
701
- filesystem: FILESYSTEM_COMMANDS,
702
- externalBridge: EXTERNAL_BRIDGE_COMMANDS,
703
- extension: EXTENSION_COMMANDS,
704
- remoteStorage: REMOTE_STORAGE_COMMANDS,
705
- localsend: LOCALSEND_COMMANDS,
706
- spaces: SPACE_COMMANDS
707
- };
708
-
709
- // src/api/storage.ts
710
- var StorageAPI = class {
711
- constructor(client) {
712
- this.client = client;
713
- }
714
- async getItem(key) {
715
- return this.client.request(WEB_STORAGE_COMMANDS.getItem, { key });
716
- }
717
- async setItem(key, value) {
718
- await this.client.request(WEB_STORAGE_COMMANDS.setItem, { key, value });
719
- }
720
- async removeItem(key) {
721
- await this.client.request(WEB_STORAGE_COMMANDS.removeItem, { key });
722
- }
723
- async clear() {
724
- await this.client.request(WEB_STORAGE_COMMANDS.clear);
725
- }
726
- async keys() {
727
- return this.client.request(WEB_STORAGE_COMMANDS.keys);
728
- }
729
- };
730
-
731
- // src/api/database.ts
732
- var DatabaseAPI = class {
733
- constructor(client) {
734
- this.client = client;
735
- }
736
- async query(query, params) {
737
- const result = await this.client.request(
738
- DATABASE_COMMANDS.query,
739
- {
740
- query,
741
- params: params || []
742
- }
743
- );
744
- return result.rows;
745
- }
746
- async queryOne(query, params) {
747
- const rows = await this.query(query, params);
748
- return rows.length > 0 ? rows[0] ?? null : null;
749
- }
750
- async execute(query, params) {
751
- return this.client.request(DATABASE_COMMANDS.execute, {
752
- query,
753
- params: params || []
754
- });
755
- }
756
- async transaction(statements) {
757
- await this.client.request(DATABASE_COMMANDS.transaction, {
758
- statements
759
- });
760
- }
761
- async createTable(tableName, columns) {
762
- const query = `CREATE TABLE IF NOT EXISTS ${tableName} (${columns})`;
763
- await this.execute(query);
764
- }
765
- async dropTable(tableName) {
766
- const query = `DROP TABLE IF EXISTS ${tableName}`;
767
- await this.execute(query);
768
- }
769
- /**
770
- * Registers and applies extension migrations with HaexVault
771
- *
772
- * HaexVault will:
773
- * 1. Validate all SQL statements (ensure only extension's own tables are accessed)
774
- * 2. Store migrations with applied_at = NULL
775
- * 3. Query pending migrations sorted by name
776
- * 4. Apply pending migrations and set up CRDT triggers
777
- * 5. Mark successful migrations with applied_at timestamp
778
- *
779
- * @param extensionVersion - The version of the extension
780
- * @param migrations - Array of migration objects with name and SQL content
781
- * @returns Promise with migration result (applied count, already applied count, applied migration names)
782
- */
783
- async registerMigrationsAsync(extensionVersion, migrations) {
784
- return this.client.request(
785
- DATABASE_COMMANDS.registerMigrations,
786
- {
787
- extensionVersion,
788
- migrations
789
- }
790
- );
791
- }
792
- async insert(tableName, data) {
793
- const keys = Object.keys(data);
794
- const values = Object.values(data);
795
- const placeholders = keys.map(() => "?").join(", ");
796
- const query = `INSERT INTO ${tableName} (${keys.join(
797
- ", "
798
- )}) VALUES (${placeholders})`;
799
- const result = await this.execute(query, values);
800
- return result.lastInsertId ?? -1;
801
- }
802
- async update(tableName, data, where, whereParams) {
803
- const keys = Object.keys(data);
804
- const values = Object.values(data);
805
- const setClause = keys.map((key) => `${key} = ?`).join(", ");
806
- const query = `UPDATE ${tableName} SET ${setClause} WHERE ${where}`;
807
- const result = await this.execute(query, [
808
- ...values,
809
- ...whereParams || []
810
- ]);
811
- return result.rowsAffected;
812
- }
813
- async delete(tableName, where, whereParams) {
814
- const query = `DELETE FROM ${tableName} WHERE ${where}`;
815
- const result = await this.execute(query, whereParams);
816
- return result.rowsAffected;
817
- }
818
- async count(tableName, where, whereParams) {
819
- const query = where ? `SELECT COUNT(*) as count FROM ${tableName} WHERE ${where}` : `SELECT COUNT(*) as count FROM ${tableName}`;
820
- const result = await this.queryOne(query, whereParams);
821
- return result?.count ?? 0;
822
- }
823
- };
824
-
825
- // src/crypto/vaultKey.ts
826
- var PBKDF2_ITERATIONS = 6e5;
827
- var KEY_LENGTH = 256;
828
- var ALGORITHM = "AES-GCM";
829
- async function deriveKeyFromPassword(password, salt) {
830
- const encoder = new TextEncoder();
831
- const passwordBuffer = encoder.encode(password);
832
- const saltBuffer = new Uint8Array(salt);
833
- const keyMaterial = await crypto.subtle.importKey(
834
- "raw",
835
- passwordBuffer,
836
- "PBKDF2",
837
- false,
838
- ["deriveKey"]
839
- );
840
- return await crypto.subtle.deriveKey(
841
- {
842
- name: "PBKDF2",
843
- salt: saltBuffer,
844
- iterations: PBKDF2_ITERATIONS,
845
- hash: "SHA-256"
846
- },
847
- keyMaterial,
848
- { name: ALGORITHM, length: KEY_LENGTH },
849
- false,
850
- // not extractable
851
- ["encrypt", "decrypt"]
852
- );
853
- }
854
- function generateVaultKey() {
855
- return crypto.getRandomValues(new Uint8Array(32));
856
- }
857
- async function encryptString(data, derivedKey) {
858
- const nonce = crypto.getRandomValues(new Uint8Array(12));
859
- const encoder = new TextEncoder();
860
- const dataBuffer = encoder.encode(data);
861
- const encryptedBuffer = await crypto.subtle.encrypt(
862
- {
863
- name: ALGORITHM,
864
- iv: nonce
865
- },
866
- derivedKey,
867
- dataBuffer
868
- );
869
- return {
870
- encryptedData: arrayBufferToBase64(encryptedBuffer),
871
- nonce: arrayBufferToBase64(nonce)
872
- };
873
- }
874
- async function decryptString(encryptedData, nonce, derivedKey) {
875
- const encryptedBuffer = base64ToArrayBuffer(encryptedData);
876
- const nonceBuffer = base64ToArrayBuffer(nonce);
877
- const encryptedDataBuffer = new Uint8Array(encryptedBuffer);
878
- const iv = new Uint8Array(nonceBuffer);
879
- const decryptedBuffer = await crypto.subtle.decrypt(
880
- {
881
- name: ALGORITHM,
882
- iv
883
- },
884
- derivedKey,
885
- encryptedDataBuffer
886
- );
887
- const decoder = new TextDecoder();
888
- return decoder.decode(decryptedBuffer);
889
- }
890
- async function encryptVaultKey(vaultKey, password) {
891
- const salt = crypto.getRandomValues(new Uint8Array(32));
892
- const derivedKey = await deriveKeyFromPassword(password, salt);
893
- const nonce = crypto.getRandomValues(new Uint8Array(12));
894
- const vaultKeyBuffer = new Uint8Array(vaultKey);
895
- const encryptedBuffer = await crypto.subtle.encrypt(
896
- {
897
- name: ALGORITHM,
898
- iv: nonce
899
- },
900
- derivedKey,
901
- vaultKeyBuffer
902
- );
903
- return {
904
- encryptedVaultKey: arrayBufferToBase64(encryptedBuffer),
905
- salt: arrayBufferToBase64(salt),
906
- vaultKeyNonce: arrayBufferToBase64(nonce)
907
- };
908
- }
909
- async function decryptVaultKey(encryptedVaultKey, salt, vaultKeyNonce, password) {
910
- const encryptedBuffer = base64ToArrayBuffer(encryptedVaultKey);
911
- const saltBuffer = base64ToArrayBuffer(salt);
912
- const nonceBuffer = base64ToArrayBuffer(vaultKeyNonce);
913
- const derivedKey = await deriveKeyFromPassword(password, saltBuffer);
914
- const encryptedData = new Uint8Array(encryptedBuffer);
915
- const iv = new Uint8Array(nonceBuffer);
916
- const decryptedBuffer = await crypto.subtle.decrypt(
917
- {
918
- name: ALGORITHM,
919
- iv
920
- },
921
- derivedKey,
922
- encryptedData
923
- );
924
- return new Uint8Array(decryptedBuffer);
925
- }
926
- async function decryptVaultName(encryptedVaultName, vaultNameNonce, vaultNameSalt, password) {
927
- const saltBuffer = base64ToArrayBuffer(vaultNameSalt);
928
- const derivedKey = await deriveKeyFromPassword(password, saltBuffer);
929
- return decryptString(encryptedVaultName, vaultNameNonce, derivedKey);
930
- }
931
- async function encryptCrdtData(data, vaultKey) {
932
- const vaultKeyBuffer = new Uint8Array(vaultKey);
933
- const cryptoKey = await crypto.subtle.importKey(
934
- "raw",
935
- vaultKeyBuffer,
936
- { name: ALGORITHM },
937
- false,
938
- ["encrypt"]
939
- );
940
- const nonce = crypto.getRandomValues(new Uint8Array(12));
941
- const encoder = new TextEncoder();
942
- const dataBuffer = encoder.encode(JSON.stringify(data));
943
- const encryptedBuffer = await crypto.subtle.encrypt(
944
- {
945
- name: ALGORITHM,
946
- iv: nonce
947
- },
948
- cryptoKey,
949
- dataBuffer
950
- );
951
- return {
952
- encryptedData: arrayBufferToBase64(encryptedBuffer),
953
- nonce: arrayBufferToBase64(nonce)
954
- };
955
- }
956
- async function wrapKey(keyToWrap, wrappingKey) {
957
- const cryptoKey = await crypto.subtle.importKey(
958
- "raw",
959
- new Uint8Array(wrappingKey),
960
- { name: ALGORITHM },
961
- false,
962
- ["encrypt"]
963
- );
964
- const nonce = crypto.getRandomValues(new Uint8Array(12));
965
- const ciphertext = await crypto.subtle.encrypt(
966
- { name: ALGORITHM, iv: nonce },
967
- cryptoKey,
968
- new Uint8Array(keyToWrap)
969
- );
970
- const result = new Uint8Array(12 + ciphertext.byteLength);
971
- result.set(nonce, 0);
972
- result.set(new Uint8Array(ciphertext), 12);
973
- return result;
974
- }
975
- async function unwrapKey(wrappedKey, wrappingKey) {
976
- const cryptoKey = await crypto.subtle.importKey(
977
- "raw",
978
- new Uint8Array(wrappingKey),
979
- { name: ALGORITHM },
980
- false,
981
- ["decrypt"]
982
- );
983
- const nonce = wrappedKey.slice(0, 12);
984
- const ciphertext = wrappedKey.slice(12);
985
- const plaintext = await crypto.subtle.decrypt(
986
- { name: ALGORITHM, iv: nonce },
987
- cryptoKey,
988
- ciphertext
989
- );
990
- return new Uint8Array(plaintext);
991
- }
992
- async function decryptCrdtData(encryptedData, nonce, vaultKey) {
993
- const vaultKeyBuffer = new Uint8Array(vaultKey);
994
- const cryptoKey = await crypto.subtle.importKey(
995
- "raw",
996
- vaultKeyBuffer,
997
- { name: ALGORITHM },
998
- false,
999
- ["decrypt"]
1000
- );
1001
- const encryptedBuffer = base64ToArrayBuffer(encryptedData);
1002
- const nonceBuffer = base64ToArrayBuffer(nonce);
1003
- const encryptedDataBuffer = new Uint8Array(encryptedBuffer);
1004
- const iv = new Uint8Array(nonceBuffer);
1005
- const decryptedBuffer = await crypto.subtle.decrypt(
1006
- {
1007
- name: ALGORITHM,
1008
- iv
1009
- },
1010
- cryptoKey,
1011
- encryptedDataBuffer
1012
- );
1013
- const decoder = new TextDecoder();
1014
- const jsonString = decoder.decode(decryptedBuffer);
1015
- return JSON.parse(jsonString);
1016
- }
1017
- function arrayBufferToBase64(buffer) {
1018
- const bytes = buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer);
1019
- if (typeof Buffer !== "undefined") {
1020
- return Buffer.from(bytes).toString("base64");
947
+ setSettings: "localsend_set_settings",
948
+ // Discovery (desktop only)
949
+ /** Start device discovery via multicast UDP */
950
+ startDiscovery: "localsend_start_discovery",
951
+ /** Stop device discovery */
952
+ stopDiscovery: "localsend_stop_discovery",
953
+ /** Get list of discovered devices */
954
+ getDevices: "localsend_get_devices",
955
+ // Network scan (mobile only)
956
+ /** Scan network for devices via HTTP */
957
+ scanNetwork: "localsend_scan_network",
958
+ // Server (receiving files)
959
+ /** Start the HTTPS server for receiving files */
960
+ startServer: "localsend_start_server",
961
+ /** Stop the HTTPS server */
962
+ stopServer: "localsend_stop_server",
963
+ /** Get server status */
964
+ getServerStatus: "localsend_get_server_status",
965
+ /** Get pending incoming transfer requests */
966
+ getPendingTransfers: "localsend_get_pending_transfers",
967
+ /** Accept an incoming transfer */
968
+ acceptTransfer: "localsend_accept_transfer",
969
+ /** Reject an incoming transfer */
970
+ rejectTransfer: "localsend_reject_transfer",
971
+ // Client (sending files)
972
+ /** Prepare files for sending - collect metadata */
973
+ prepareFiles: "localsend_prepare_files",
974
+ /** Send files to a device */
975
+ sendFiles: "localsend_send_files",
976
+ /** Cancel an outgoing transfer */
977
+ cancelSend: "localsend_cancel_send"
978
+ };
979
+
980
+ // src/commands/spaces.ts
981
+ var SPACE_COMMANDS = {
982
+ /** Bulk assign rows to spaces */
983
+ assign: "extension_space_assign",
984
+ /** Bulk unassign rows from spaces */
985
+ unassign: "extension_space_unassign",
986
+ /** Get space assignments for a table */
987
+ getAssignments: "extension_space_get_assignments",
988
+ /** List all spaces the user is a member of (with decrypted names) */
989
+ list: "extension_space_list",
990
+ /** Create a new shared space */
991
+ create: "extension_space_create",
992
+ /** List available sync backends */
993
+ listBackends: "extension_space_list_backends"
994
+ };
995
+
996
+ // src/commands/index.ts
997
+ var TAURI_COMMANDS = {
998
+ database: DATABASE_COMMANDS,
999
+ permissions: PERMISSIONS_COMMANDS,
1000
+ web: WEB_COMMANDS,
1001
+ webStorage: WEB_STORAGE_COMMANDS,
1002
+ filesystem: FILESYSTEM_COMMANDS,
1003
+ externalBridge: EXTERNAL_BRIDGE_COMMANDS,
1004
+ extension: EXTENSION_COMMANDS,
1005
+ remoteStorage: REMOTE_STORAGE_COMMANDS,
1006
+ localsend: LOCALSEND_COMMANDS,
1007
+ spaces: SPACE_COMMANDS
1008
+ };
1009
+
1010
+ // src/api/storage.ts
1011
+ var StorageAPI = class {
1012
+ constructor(client) {
1013
+ this.client = client;
1021
1014
  }
1022
- let binary = "";
1023
- for (let i = 0; i < bytes.length; i++) {
1024
- const byte = bytes[i];
1025
- if (byte !== void 0) {
1026
- binary += String.fromCharCode(byte);
1027
- }
1015
+ async getItem(key) {
1016
+ return this.client.request(WEB_STORAGE_COMMANDS.getItem, { key });
1028
1017
  }
1029
- return btoa(binary);
1030
- }
1031
- function base64ToArrayBuffer(base64) {
1032
- if (typeof Buffer !== "undefined") {
1033
- return new Uint8Array(Buffer.from(base64, "base64"));
1018
+ async setItem(key, value) {
1019
+ await this.client.request(WEB_STORAGE_COMMANDS.setItem, { key, value });
1034
1020
  }
1035
- const binary = atob(base64);
1036
- const bytes = new Uint8Array(binary.length);
1037
- for (let i = 0; i < binary.length; i++) {
1038
- bytes[i] = binary.charCodeAt(i);
1021
+ async removeItem(key) {
1022
+ await this.client.request(WEB_STORAGE_COMMANDS.removeItem, { key });
1039
1023
  }
1040
- return bytes;
1041
- }
1024
+ async clear() {
1025
+ await this.client.request(WEB_STORAGE_COMMANDS.clear);
1026
+ }
1027
+ async keys() {
1028
+ return this.client.request(WEB_STORAGE_COMMANDS.keys);
1029
+ }
1030
+ };
1031
+
1032
+ // src/api/database.ts
1033
+ var DatabaseAPI = class {
1034
+ constructor(client) {
1035
+ this.client = client;
1036
+ }
1037
+ async query(query, params) {
1038
+ const result = await this.client.request(
1039
+ DATABASE_COMMANDS.query,
1040
+ {
1041
+ query,
1042
+ params: params || []
1043
+ }
1044
+ );
1045
+ return result.rows;
1046
+ }
1047
+ async queryOne(query, params) {
1048
+ const rows = await this.query(query, params);
1049
+ return rows.length > 0 ? rows[0] ?? null : null;
1050
+ }
1051
+ async execute(query, params) {
1052
+ return this.client.request(DATABASE_COMMANDS.execute, {
1053
+ query,
1054
+ params: params || []
1055
+ });
1056
+ }
1057
+ async transaction(statements) {
1058
+ await this.client.request(DATABASE_COMMANDS.transaction, {
1059
+ statements
1060
+ });
1061
+ }
1062
+ async createTable(tableName, columns) {
1063
+ const query = `CREATE TABLE IF NOT EXISTS ${tableName} (${columns})`;
1064
+ await this.execute(query);
1065
+ }
1066
+ async dropTable(tableName) {
1067
+ const query = `DROP TABLE IF EXISTS ${tableName}`;
1068
+ await this.execute(query);
1069
+ }
1070
+ /**
1071
+ * Registers and applies extension migrations with HaexVault
1072
+ *
1073
+ * HaexVault will:
1074
+ * 1. Validate all SQL statements (ensure only extension's own tables are accessed)
1075
+ * 2. Store migrations with applied_at = NULL
1076
+ * 3. Query pending migrations sorted by name
1077
+ * 4. Apply pending migrations and set up CRDT triggers
1078
+ * 5. Mark successful migrations with applied_at timestamp
1079
+ *
1080
+ * @param extensionVersion - The version of the extension
1081
+ * @param migrations - Array of migration objects with name and SQL content
1082
+ * @returns Promise with migration result (applied count, already applied count, applied migration names)
1083
+ */
1084
+ async registerMigrationsAsync(extensionVersion, migrations) {
1085
+ return this.client.request(
1086
+ DATABASE_COMMANDS.registerMigrations,
1087
+ {
1088
+ extensionVersion,
1089
+ migrations
1090
+ }
1091
+ );
1092
+ }
1093
+ async insert(tableName, data) {
1094
+ const keys = Object.keys(data);
1095
+ const values = Object.values(data);
1096
+ const placeholders = keys.map(() => "?").join(", ");
1097
+ const query = `INSERT INTO ${tableName} (${keys.join(
1098
+ ", "
1099
+ )}) VALUES (${placeholders})`;
1100
+ const result = await this.execute(query, values);
1101
+ return result.lastInsertId ?? -1;
1102
+ }
1103
+ async update(tableName, data, where, whereParams) {
1104
+ const keys = Object.keys(data);
1105
+ const values = Object.values(data);
1106
+ const setClause = keys.map((key) => `${key} = ?`).join(", ");
1107
+ const query = `UPDATE ${tableName} SET ${setClause} WHERE ${where}`;
1108
+ const result = await this.execute(query, [
1109
+ ...values,
1110
+ ...whereParams || []
1111
+ ]);
1112
+ return result.rowsAffected;
1113
+ }
1114
+ async delete(tableName, where, whereParams) {
1115
+ const query = `DELETE FROM ${tableName} WHERE ${where}`;
1116
+ const result = await this.execute(query, whereParams);
1117
+ return result.rowsAffected;
1118
+ }
1119
+ async count(tableName, where, whereParams) {
1120
+ const query = where ? `SELECT COUNT(*) as count FROM ${tableName} WHERE ${where}` : `SELECT COUNT(*) as count FROM ${tableName}`;
1121
+ const result = await this.queryOne(query, whereParams);
1122
+ return result?.count ?? 0;
1123
+ }
1124
+ };
1042
1125
 
1043
1126
  // src/api/filesystem.ts
1127
+ init_vaultKey();
1044
1128
  var FilesystemAPI = class {
1045
1129
  constructor(client) {
1046
1130
  this.client = client;
@@ -1426,6 +1510,7 @@ var PermissionsAPI = class {
1426
1510
  };
1427
1511
 
1428
1512
  // src/api/remoteStorage.ts
1513
+ init_vaultKey();
1429
1514
  var RemoteStorageAPI = class {
1430
1515
  constructor(client) {
1431
1516
  this.client = client;
@@ -2848,61 +2933,174 @@ async function verifyExtensionSignature(files, manifest) {
2848
2933
  }
2849
2934
  }
2850
2935
 
2851
- // src/crypto/userKeypair.ts
2852
- var SIGNING_ALGO = { name: "ECDSA", namedCurve: "P-256" };
2853
- var KEY_AGREEMENT_ALGO = { name: "ECDH", namedCurve: "P-256" };
2854
- async function generateUserKeypairAsync() {
2855
- const keypair = await crypto.subtle.generateKey(SIGNING_ALGO, true, ["sign", "verify"]);
2856
- return { publicKey: keypair.publicKey, privateKey: keypair.privateKey };
2857
- }
2858
- async function exportUserKeypairAsync(keypair) {
2859
- const pub = await crypto.subtle.exportKey("spki", keypair.publicKey);
2860
- const priv = await crypto.subtle.exportKey("pkcs8", keypair.privateKey);
2861
- return { publicKey: arrayBufferToBase64(pub), privateKey: arrayBufferToBase64(priv) };
2862
- }
2863
- async function importUserPublicKeyAsync(base64) {
2864
- return crypto.subtle.importKey("spki", base64ToArrayBuffer(base64), SIGNING_ALGO, true, ["verify"]);
2936
+ // src/index.ts
2937
+ init_vaultKey();
2938
+ init_userKeypair();
2939
+
2940
+ // src/crypto/didKey.ts
2941
+ init_userKeypair();
2942
+ init_vaultKey();
2943
+ var BASE58_ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
2944
+ function base58btcEncode(bytes) {
2945
+ let zeros = 0;
2946
+ for (const b of bytes) {
2947
+ if (b !== 0) break;
2948
+ zeros++;
2949
+ }
2950
+ const digits = [];
2951
+ for (const b of bytes) {
2952
+ let carry = b;
2953
+ for (let j = 0; j < digits.length; j++) {
2954
+ carry += digits[j] << 8;
2955
+ digits[j] = carry % 58;
2956
+ carry = carry / 58 | 0;
2957
+ }
2958
+ while (carry > 0) {
2959
+ digits.push(carry % 58);
2960
+ carry = carry / 58 | 0;
2961
+ }
2962
+ }
2963
+ return "1".repeat(zeros) + digits.reverse().map((d) => BASE58_ALPHABET[d]).join("");
2964
+ }
2965
+ function base58btcDecode(str) {
2966
+ let zeros = 0;
2967
+ for (const c of str) {
2968
+ if (c !== "1") break;
2969
+ zeros++;
2970
+ }
2971
+ const bytes = [];
2972
+ for (const c of str) {
2973
+ const value = BASE58_ALPHABET.indexOf(c);
2974
+ if (value === -1) throw new Error(`Invalid base58 character: ${c}`);
2975
+ let carry = value;
2976
+ for (let j = 0; j < bytes.length; j++) {
2977
+ carry += bytes[j] * 58;
2978
+ bytes[j] = carry & 255;
2979
+ carry >>= 8;
2980
+ }
2981
+ while (carry > 0) {
2982
+ bytes.push(carry & 255);
2983
+ carry >>= 8;
2984
+ }
2985
+ }
2986
+ const result = new Uint8Array(zeros + bytes.length);
2987
+ for (let i = 0; i < bytes.length; i++) {
2988
+ result[zeros + i] = bytes[bytes.length - 1 - i];
2989
+ }
2990
+ return result;
2865
2991
  }
2866
- async function importUserPrivateKeyAsync(base64) {
2867
- return crypto.subtle.importKey("pkcs8", base64ToArrayBuffer(base64), SIGNING_ALGO, true, ["sign"]);
2992
+ function compressP256Point(uncompressed) {
2993
+ if (uncompressed.length !== 65 || uncompressed[0] !== 4) {
2994
+ throw new Error("Expected 65-byte uncompressed P-256 point (0x04 prefix)");
2995
+ }
2996
+ const x = uncompressed.slice(1, 33);
2997
+ const yLastByte = uncompressed[64];
2998
+ const prefix = (yLastByte & 1) === 0 ? 2 : 3;
2999
+ const compressed = new Uint8Array(33);
3000
+ compressed[0] = prefix;
3001
+ compressed.set(x, 1);
3002
+ return compressed;
3003
+ }
3004
+ function decompressP256Point(compressed) {
3005
+ if (compressed.length !== 33 || compressed[0] !== 2 && compressed[0] !== 3) {
3006
+ throw new Error("Expected 33-byte compressed P-256 point");
3007
+ }
3008
+ const isOdd = compressed[0] === 3;
3009
+ const x = bytesToBigInt(compressed.slice(1));
3010
+ const p = BigInt("0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff");
3011
+ const b = BigInt("0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b");
3012
+ const a = p - 3n;
3013
+ const ySquared = (modPow(x, 3n, p) + a * x + b) % p;
3014
+ let y = modSqrt(ySquared, p);
3015
+ const yIsOdd = (y & 1n) === 1n;
3016
+ if (isOdd !== yIsOdd) {
3017
+ y = p - y;
3018
+ }
3019
+ const uncompressed = new Uint8Array(65);
3020
+ uncompressed[0] = 4;
3021
+ uncompressed.set(bigIntToBytes(x, 32), 1);
3022
+ uncompressed.set(bigIntToBytes(y, 32), 33);
3023
+ return uncompressed;
3024
+ }
3025
+ function bytesToBigInt(bytes) {
3026
+ let result = 0n;
3027
+ for (const b of bytes) {
3028
+ result = result << 8n | BigInt(b);
3029
+ }
3030
+ return result;
2868
3031
  }
2869
- async function importPublicKeyForKeyAgreementAsync(base64) {
2870
- return crypto.subtle.importKey("spki", base64ToArrayBuffer(base64), KEY_AGREEMENT_ALGO, true, []);
3032
+ function bigIntToBytes(n, length) {
3033
+ const bytes = new Uint8Array(length);
3034
+ let val = n;
3035
+ for (let i = length - 1; i >= 0; i--) {
3036
+ bytes[i] = Number(val & 0xffn);
3037
+ val >>= 8n;
3038
+ }
3039
+ return bytes;
2871
3040
  }
2872
- async function importPrivateKeyForKeyAgreementAsync(base64) {
2873
- return crypto.subtle.importKey("pkcs8", base64ToArrayBuffer(base64), KEY_AGREEMENT_ALGO, true, ["deriveBits"]);
3041
+ function modPow(base, exp, mod) {
3042
+ let result = 1n;
3043
+ base = base % mod;
3044
+ while (exp > 0n) {
3045
+ if (exp & 1n) result = result * base % mod;
3046
+ exp >>= 1n;
3047
+ base = base * base % mod;
3048
+ }
3049
+ return result;
2874
3050
  }
2875
- async function encryptPrivateKeyAsync(privateKeyBase64, password) {
2876
- const salt = crypto.getRandomValues(new Uint8Array(32));
2877
- const derivedKey = await deriveKeyFromPassword(password, salt);
2878
- const nonce = crypto.getRandomValues(new Uint8Array(12));
2879
- const encrypted = await crypto.subtle.encrypt(
2880
- { name: "AES-GCM", iv: nonce },
2881
- derivedKey,
2882
- new TextEncoder().encode(privateKeyBase64)
3051
+ function modSqrt(a, p) {
3052
+ return modPow(a, (p + 1n) / 4n, p);
3053
+ }
3054
+ var P256_MULTICODEC_PREFIX = new Uint8Array([128, 36]);
3055
+ async function publicKeyToDidKeyAsync(publicKeyBase64) {
3056
+ const cryptoKey = await importUserPublicKeyAsync(publicKeyBase64);
3057
+ const rawBytes = new Uint8Array(await crypto.subtle.exportKey("raw", cryptoKey));
3058
+ const compressed = compressP256Point(rawBytes);
3059
+ const multicodecBytes = new Uint8Array(P256_MULTICODEC_PREFIX.length + compressed.length);
3060
+ multicodecBytes.set(P256_MULTICODEC_PREFIX);
3061
+ multicodecBytes.set(compressed, P256_MULTICODEC_PREFIX.length);
3062
+ return `did:key:z${base58btcEncode(multicodecBytes)}`;
3063
+ }
3064
+ async function didKeyToPublicKeyAsync(did) {
3065
+ if (!did.startsWith("did:key:z")) {
3066
+ throw new Error("Only did:key with base58-btc multibase (z prefix) is supported");
3067
+ }
3068
+ const multicodecBytes = base58btcDecode(did.slice("did:key:z".length));
3069
+ if (multicodecBytes[0] !== P256_MULTICODEC_PREFIX[0] || multicodecBytes[1] !== P256_MULTICODEC_PREFIX[1]) {
3070
+ throw new Error("Unsupported key type in did:key (expected P-256)");
3071
+ }
3072
+ const compressed = multicodecBytes.slice(P256_MULTICODEC_PREFIX.length);
3073
+ const uncompressed = decompressP256Point(compressed);
3074
+ const cryptoKey = await crypto.subtle.importKey(
3075
+ "raw",
3076
+ uncompressed.buffer,
3077
+ { name: "ECDSA", namedCurve: "P-256" },
3078
+ true,
3079
+ ["verify"]
2883
3080
  );
3081
+ const spki = await crypto.subtle.exportKey("spki", cryptoKey);
3082
+ return arrayBufferToBase64(spki);
3083
+ }
3084
+ async function generateIdentityAsync() {
3085
+ const { generateUserKeypairAsync: generateUserKeypairAsync2, exportUserKeypairAsync: exportUserKeypairAsync2 } = await Promise.resolve().then(() => (init_userKeypair(), userKeypair_exports));
3086
+ const keypair = await generateUserKeypairAsync2();
3087
+ const exported = await exportUserKeypairAsync2(keypair);
3088
+ const did = await publicKeyToDidKeyAsync(exported.publicKey);
2884
3089
  return {
2885
- encryptedPrivateKey: arrayBufferToBase64(encrypted),
2886
- nonce: arrayBufferToBase64(nonce),
2887
- salt: arrayBufferToBase64(salt)
3090
+ did,
3091
+ publicKeyBase64: exported.publicKey,
3092
+ privateKeyBase64: exported.privateKey
2888
3093
  };
2889
3094
  }
2890
- async function decryptPrivateKeyAsync(encryptedPrivateKey, nonce, salt, password) {
2891
- const derivedKey = await deriveKeyFromPassword(password, base64ToArrayBuffer(salt));
2892
- const decrypted = await crypto.subtle.decrypt(
2893
- { name: "AES-GCM", iv: base64ToArrayBuffer(nonce) },
2894
- derivedKey,
2895
- base64ToArrayBuffer(encryptedPrivateKey)
2896
- );
2897
- return new TextDecoder().decode(decrypted);
2898
- }
2899
3095
 
2900
3096
  // src/crypto/spaceKey.ts
3097
+ init_userKeypair();
3098
+ init_vaultKey();
2901
3099
  function generateSpaceKey() {
2902
3100
  return generateVaultKey();
2903
3101
  }
2904
3102
  async function encryptSpaceKeyForRecipientAsync(spaceKey, recipientPublicKeyBase64) {
2905
- const ephemeral = await crypto.subtle.generateKey(KEY_AGREEMENT_ALGO, true, ["deriveBits"]);
3103
+ const ephemeral = await crypto.subtle.generateKey(exports.KEY_AGREEMENT_ALGO, true, ["deriveBits"]);
2906
3104
  const recipientKey = await importPublicKeyForKeyAgreementAsync(recipientPublicKeyBase64);
2907
3105
  const sharedBits = await crypto.subtle.deriveBits(
2908
3106
  { name: "ECDH", public: recipientKey },
@@ -2934,7 +3132,7 @@ async function decryptSpaceKeyAsync(encrypted, ownPrivateKeyBase64) {
2934
3132
  const ephPubKey = await crypto.subtle.importKey(
2935
3133
  "spki",
2936
3134
  base64ToArrayBuffer(encrypted.ephemeralPublicKey),
2937
- KEY_AGREEMENT_ALGO,
3135
+ exports.KEY_AGREEMENT_ALGO,
2938
3136
  true,
2939
3137
  []
2940
3138
  );
@@ -2985,7 +3183,45 @@ async function decryptSpaceNameAsync(spaceKey, encryptedName, nameNonce) {
2985
3183
  return decryptString(encryptedName, nameNonce, cryptoKey);
2986
3184
  }
2987
3185
 
3186
+ // src/crypto/claims.ts
3187
+ init_userKeypair();
3188
+ async function signClaimPresentationAsync(did, publicKeyBase64, claims, privateKeyBase64) {
3189
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
3190
+ const sortedEntries = Object.entries(claims).sort(([a], [b]) => a.localeCompare(b));
3191
+ const canonical = [did, timestamp, ...sortedEntries.map(([k, v]) => `${k}=${v}`)].join("\0");
3192
+ const privateKey = await importUserPrivateKeyAsync(privateKeyBase64);
3193
+ const data = new TextEncoder().encode(canonical);
3194
+ const sig = await crypto.subtle.sign(
3195
+ { name: "ECDSA", hash: "SHA-256" },
3196
+ privateKey,
3197
+ data
3198
+ );
3199
+ return {
3200
+ did,
3201
+ publicKey: publicKeyBase64,
3202
+ claims,
3203
+ timestamp,
3204
+ signature: btoa(String.fromCharCode(...new Uint8Array(sig)))
3205
+ };
3206
+ }
3207
+ async function verifyClaimPresentationAsync(presentation) {
3208
+ const { did, publicKey, claims, timestamp, signature } = presentation;
3209
+ const sortedEntries = Object.entries(claims).sort(([a], [b]) => a.localeCompare(b));
3210
+ const canonical = [did, timestamp, ...sortedEntries.map(([k, v]) => `${k}=${v}`)].join("\0");
3211
+ const pubKey = await importUserPublicKeyAsync(publicKey);
3212
+ const data = new TextEncoder().encode(canonical);
3213
+ const sigBytes = Uint8Array.from(atob(signature), (c) => c.charCodeAt(0));
3214
+ return crypto.subtle.verify(
3215
+ { name: "ECDSA", hash: "SHA-256" },
3216
+ pubKey,
3217
+ sigBytes,
3218
+ data
3219
+ );
3220
+ }
3221
+
2988
3222
  // src/crypto/recordSigning.ts
3223
+ init_userKeypair();
3224
+ init_vaultKey();
2989
3225
  function canonicalize(record) {
2990
3226
  const parts = [
2991
3227
  record.tableName,
@@ -3048,6 +3284,7 @@ async function verifySpaceChallengeAsync(spaceId, timestamp, signatureBase64, pu
3048
3284
  }
3049
3285
 
3050
3286
  // src/crypto/passkey.ts
3287
+ init_vaultKey();
3051
3288
  function toArrayBuffer(data) {
3052
3289
  if (data instanceof ArrayBuffer) {
3053
3290
  return data;
@@ -3229,14 +3466,12 @@ exports.HAEXSPACE_MESSAGE_TYPES = HAEXSPACE_MESSAGE_TYPES;
3229
3466
  exports.HAEXTENSION_EVENTS = HAEXTENSION_EVENTS;
3230
3467
  exports.HaexVaultSdk = HaexVaultSdk;
3231
3468
  exports.HaexVaultSdkError = HaexVaultSdkError;
3232
- exports.KEY_AGREEMENT_ALGO = KEY_AGREEMENT_ALGO;
3233
3469
  exports.LOCALSEND_EVENTS = LOCALSEND_EVENTS;
3234
3470
  exports.LocalSendAPI = LocalSendAPI;
3235
3471
  exports.PermissionErrorCode = PermissionErrorCode;
3236
3472
  exports.PermissionStatus = PermissionStatus;
3237
3473
  exports.PermissionsAPI = PermissionsAPI;
3238
3474
  exports.RemoteStorageAPI = RemoteStorageAPI;
3239
- exports.SIGNING_ALGO = SIGNING_ALGO;
3240
3475
  exports.SPACE_COMMANDS = SPACE_COMMANDS;
3241
3476
  exports.SpacesAPI = SpacesAPI;
3242
3477
  exports.TABLE_SEPARATOR = TABLE_SEPARATOR;
@@ -3254,6 +3489,7 @@ exports.decryptString = decryptString;
3254
3489
  exports.decryptVaultKey = decryptVaultKey;
3255
3490
  exports.decryptVaultName = decryptVaultName;
3256
3491
  exports.deriveKeyFromPassword = deriveKeyFromPassword;
3492
+ exports.didKeyToPublicKeyAsync = didKeyToPublicKeyAsync;
3257
3493
  exports.encryptCrdtData = encryptCrdtData;
3258
3494
  exports.encryptPrivateKeyAsync = encryptPrivateKeyAsync;
3259
3495
  exports.encryptSpaceKeyForRecipientAsync = encryptSpaceKeyForRecipientAsync;
@@ -3266,6 +3502,7 @@ exports.exportPublicKeyAsync = exportPublicKeyAsync;
3266
3502
  exports.exportPublicKeyCoseAsync = exportPublicKeyCoseAsync;
3267
3503
  exports.exportUserKeypairAsync = exportUserKeypairAsync;
3268
3504
  exports.generateCredentialId = generateCredentialId;
3505
+ exports.generateIdentityAsync = generateIdentityAsync;
3269
3506
  exports.generatePasskeyPairAsync = generatePasskeyPairAsync;
3270
3507
  exports.generateSpaceKey = generateSpaceKey;
3271
3508
  exports.generateUserKeypairAsync = generateUserKeypairAsync;
@@ -3288,11 +3525,14 @@ exports.isExternalClientConnected = isExternalClientConnected;
3288
3525
  exports.isPermissionDeniedError = isPermissionDeniedError;
3289
3526
  exports.isPermissionError = isPermissionError;
3290
3527
  exports.isPermissionPromptError = isPermissionPromptError;
3528
+ exports.publicKeyToDidKeyAsync = publicKeyToDidKeyAsync;
3529
+ exports.signClaimPresentationAsync = signClaimPresentationAsync;
3291
3530
  exports.signRecordAsync = signRecordAsync;
3292
3531
  exports.signSpaceChallengeAsync = signSpaceChallengeAsync;
3293
3532
  exports.signWithPasskeyAsync = signWithPasskeyAsync;
3294
3533
  exports.sortObjectKeysRecursively = sortObjectKeysRecursively;
3295
3534
  exports.unwrapKey = unwrapKey;
3535
+ exports.verifyClaimPresentationAsync = verifyClaimPresentationAsync;
3296
3536
  exports.verifyExtensionSignature = verifyExtensionSignature;
3297
3537
  exports.verifyRecordSignatureAsync = verifyRecordSignatureAsync;
3298
3538
  exports.verifySpaceChallengeAsync = verifySpaceChallengeAsync;