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