@haex-space/vault-sdk 2.3.3 → 2.3.4

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.d.mts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { H as HaexVaultClient } from './client-BIiJwbdW.mjs';
2
2
  export { D as DatabaseAPI, F as FilesystemAPI, P as PermissionsAPI, W as WebAPI } from './client-BIiJwbdW.mjs';
3
- import { H as HaexHubConfig } from './types-FE9ewl3r.mjs';
4
- export { A as ApplicationContext, C as ContextChangedEvent, r as DEFAULT_TIMEOUT, m as DatabaseColumnInfo, k as DatabaseExecuteParams, i as DatabasePermission, d as DatabasePermissionRequest, j as DatabaseQueryParams, D as DatabaseQueryResult, l as DatabaseTableInfo, q as ErrorCode, e as EventCallback, a as ExtensionInfo, E as ExtensionManifest, u as HAEXTENSION_EVENTS, t as HaexHubError, h as HaexHubEvent, f as HaexHubRequest, g as HaexHubResponse, v as HaextensionEvent, P as PermissionResponse, p as PermissionStatus, n as SearchQuery, o as SearchRequestEvent, S as SearchResult, T as TABLE_SEPARATOR, W as WebRequestOptions, c as WebResponse, s as getTableName } from './types-FE9ewl3r.mjs';
3
+ import { E as ExtensionManifest, H as HaexHubConfig } from './types-FE9ewl3r.mjs';
4
+ export { A as ApplicationContext, C as ContextChangedEvent, r as DEFAULT_TIMEOUT, m as DatabaseColumnInfo, k as DatabaseExecuteParams, i as DatabasePermission, d as DatabasePermissionRequest, j as DatabaseQueryParams, D as DatabaseQueryResult, l as DatabaseTableInfo, q as ErrorCode, e as EventCallback, a as ExtensionInfo, u as HAEXTENSION_EVENTS, t as HaexHubError, h as HaexHubEvent, f as HaexHubRequest, g as HaexHubResponse, v as HaextensionEvent, P as PermissionResponse, p as PermissionStatus, n as SearchQuery, o as SearchRequestEvent, S as SearchResult, T as TABLE_SEPARATOR, W as WebRequestOptions, c as WebResponse, s as getTableName } from './types-FE9ewl3r.mjs';
5
5
  export { H as HaextensionConfig } from './config-D_HXjsEV.mjs';
6
6
  import 'drizzle-orm/sqlite-proxy';
7
7
 
@@ -136,6 +136,60 @@ declare const HAEXSPACE_MESSAGE_TYPES: {
136
136
  };
137
137
  type HaexspaceMessageType = (typeof HAEXSPACE_MESSAGE_TYPES)[keyof typeof HAEXSPACE_MESSAGE_TYPES];
138
138
 
139
+ interface VerifyResult {
140
+ valid: boolean;
141
+ error?: string;
142
+ }
143
+ interface ZipFileEntry {
144
+ path: string;
145
+ content: Uint8Array;
146
+ }
147
+ /**
148
+ * Sort object keys recursively for canonical JSON representation.
149
+ * Must match the signing implementation exactly.
150
+ */
151
+ declare function sortObjectKeysRecursively(obj: unknown): unknown;
152
+ /**
153
+ * Convert hex string to ArrayBuffer
154
+ * Returns ArrayBuffer directly to avoid type issues with Uint8Array.buffer
155
+ */
156
+ declare function hexToBytes(hex: string): ArrayBuffer;
157
+ /**
158
+ * Verify Ed25519 signature of an extension bundle.
159
+ *
160
+ * This function is browser-compatible and uses the Web Crypto API.
161
+ * It verifies that the extension bundle was signed with the private key
162
+ * corresponding to the public key in the manifest.
163
+ *
164
+ * @param files - Array of file entries from the ZIP archive
165
+ * @param manifest - The extension manifest (parsed from manifest.json)
166
+ * @returns Promise resolving to verification result
167
+ *
168
+ * @example
169
+ * ```typescript
170
+ * import JSZip from 'jszip';
171
+ * import { verifyExtensionSignature } from '@haex-space/vault-sdk';
172
+ *
173
+ * const zip = await JSZip.loadAsync(bundleFile);
174
+ * const manifestContent = await zip.file('haextension/manifest.json')?.async('string');
175
+ * const manifest = JSON.parse(manifestContent);
176
+ *
177
+ * // Collect all files from the ZIP
178
+ * const files = [];
179
+ * for (const [path, entry] of Object.entries(zip.files)) {
180
+ * if (!entry.dir) {
181
+ * files.push({ path, content: await entry.async('uint8array') });
182
+ * }
183
+ * }
184
+ *
185
+ * const result = await verifyExtensionSignature(files, manifest);
186
+ * if (!result.valid) {
187
+ * console.error('Signature verification failed:', result.error);
188
+ * }
189
+ * ```
190
+ */
191
+ declare function verifyExtensionSignature(files: ZipFileEntry[], manifest: ExtensionManifest): Promise<VerifyResult>;
192
+
139
193
  declare function createHaexVaultClient(config?: HaexHubConfig): HaexVaultClient;
140
194
 
141
- export { HAEXSPACE_MESSAGE_TYPES, HAEXTENSION_METHODS, HaexHubConfig, HaexVaultClient, type HaexspaceMessageType, type HaextensionMethod, createHaexVaultClient, installBaseTag, installCookiePolyfill, installHistoryPolyfill, installLocalStoragePolyfill, installPolyfills, installSessionStoragePolyfill };
195
+ export { ExtensionManifest, HAEXSPACE_MESSAGE_TYPES, HAEXTENSION_METHODS, HaexHubConfig, HaexVaultClient, type HaexspaceMessageType, type HaextensionMethod, type VerifyResult, type ZipFileEntry, createHaexVaultClient, hexToBytes, installBaseTag, installCookiePolyfill, installHistoryPolyfill, installLocalStoragePolyfill, installPolyfills, installSessionStoragePolyfill, sortObjectKeysRecursively, verifyExtensionSignature };
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { H as HaexVaultClient } from './client-D4hDL-PR.js';
2
2
  export { D as DatabaseAPI, F as FilesystemAPI, P as PermissionsAPI, W as WebAPI } from './client-D4hDL-PR.js';
3
- import { H as HaexHubConfig } from './types-FE9ewl3r.js';
4
- export { A as ApplicationContext, C as ContextChangedEvent, r as DEFAULT_TIMEOUT, m as DatabaseColumnInfo, k as DatabaseExecuteParams, i as DatabasePermission, d as DatabasePermissionRequest, j as DatabaseQueryParams, D as DatabaseQueryResult, l as DatabaseTableInfo, q as ErrorCode, e as EventCallback, a as ExtensionInfo, E as ExtensionManifest, u as HAEXTENSION_EVENTS, t as HaexHubError, h as HaexHubEvent, f as HaexHubRequest, g as HaexHubResponse, v as HaextensionEvent, P as PermissionResponse, p as PermissionStatus, n as SearchQuery, o as SearchRequestEvent, S as SearchResult, T as TABLE_SEPARATOR, W as WebRequestOptions, c as WebResponse, s as getTableName } from './types-FE9ewl3r.js';
3
+ import { E as ExtensionManifest, H as HaexHubConfig } from './types-FE9ewl3r.js';
4
+ export { A as ApplicationContext, C as ContextChangedEvent, r as DEFAULT_TIMEOUT, m as DatabaseColumnInfo, k as DatabaseExecuteParams, i as DatabasePermission, d as DatabasePermissionRequest, j as DatabaseQueryParams, D as DatabaseQueryResult, l as DatabaseTableInfo, q as ErrorCode, e as EventCallback, a as ExtensionInfo, u as HAEXTENSION_EVENTS, t as HaexHubError, h as HaexHubEvent, f as HaexHubRequest, g as HaexHubResponse, v as HaextensionEvent, P as PermissionResponse, p as PermissionStatus, n as SearchQuery, o as SearchRequestEvent, S as SearchResult, T as TABLE_SEPARATOR, W as WebRequestOptions, c as WebResponse, s as getTableName } from './types-FE9ewl3r.js';
5
5
  export { H as HaextensionConfig } from './config-D_HXjsEV.js';
6
6
  import 'drizzle-orm/sqlite-proxy';
7
7
 
@@ -136,6 +136,60 @@ declare const HAEXSPACE_MESSAGE_TYPES: {
136
136
  };
137
137
  type HaexspaceMessageType = (typeof HAEXSPACE_MESSAGE_TYPES)[keyof typeof HAEXSPACE_MESSAGE_TYPES];
138
138
 
139
+ interface VerifyResult {
140
+ valid: boolean;
141
+ error?: string;
142
+ }
143
+ interface ZipFileEntry {
144
+ path: string;
145
+ content: Uint8Array;
146
+ }
147
+ /**
148
+ * Sort object keys recursively for canonical JSON representation.
149
+ * Must match the signing implementation exactly.
150
+ */
151
+ declare function sortObjectKeysRecursively(obj: unknown): unknown;
152
+ /**
153
+ * Convert hex string to ArrayBuffer
154
+ * Returns ArrayBuffer directly to avoid type issues with Uint8Array.buffer
155
+ */
156
+ declare function hexToBytes(hex: string): ArrayBuffer;
157
+ /**
158
+ * Verify Ed25519 signature of an extension bundle.
159
+ *
160
+ * This function is browser-compatible and uses the Web Crypto API.
161
+ * It verifies that the extension bundle was signed with the private key
162
+ * corresponding to the public key in the manifest.
163
+ *
164
+ * @param files - Array of file entries from the ZIP archive
165
+ * @param manifest - The extension manifest (parsed from manifest.json)
166
+ * @returns Promise resolving to verification result
167
+ *
168
+ * @example
169
+ * ```typescript
170
+ * import JSZip from 'jszip';
171
+ * import { verifyExtensionSignature } from '@haex-space/vault-sdk';
172
+ *
173
+ * const zip = await JSZip.loadAsync(bundleFile);
174
+ * const manifestContent = await zip.file('haextension/manifest.json')?.async('string');
175
+ * const manifest = JSON.parse(manifestContent);
176
+ *
177
+ * // Collect all files from the ZIP
178
+ * const files = [];
179
+ * for (const [path, entry] of Object.entries(zip.files)) {
180
+ * if (!entry.dir) {
181
+ * files.push({ path, content: await entry.async('uint8array') });
182
+ * }
183
+ * }
184
+ *
185
+ * const result = await verifyExtensionSignature(files, manifest);
186
+ * if (!result.valid) {
187
+ * console.error('Signature verification failed:', result.error);
188
+ * }
189
+ * ```
190
+ */
191
+ declare function verifyExtensionSignature(files: ZipFileEntry[], manifest: ExtensionManifest): Promise<VerifyResult>;
192
+
139
193
  declare function createHaexVaultClient(config?: HaexHubConfig): HaexVaultClient;
140
194
 
141
- export { HAEXSPACE_MESSAGE_TYPES, HAEXTENSION_METHODS, HaexHubConfig, HaexVaultClient, type HaexspaceMessageType, type HaextensionMethod, createHaexVaultClient, installBaseTag, installCookiePolyfill, installHistoryPolyfill, installLocalStoragePolyfill, installPolyfills, installSessionStoragePolyfill };
195
+ export { ExtensionManifest, HAEXSPACE_MESSAGE_TYPES, HAEXTENSION_METHODS, HaexHubConfig, HaexVaultClient, type HaexspaceMessageType, type HaextensionMethod, type VerifyResult, type ZipFileEntry, createHaexVaultClient, hexToBytes, installBaseTag, installCookiePolyfill, installHistoryPolyfill, installLocalStoragePolyfill, installPolyfills, installSessionStoragePolyfill, sortObjectKeysRecursively, verifyExtensionSignature };
package/dist/index.js CHANGED
@@ -1432,6 +1432,98 @@ postMessage error: ${e}`);
1432
1432
  }
1433
1433
  };
1434
1434
 
1435
+ // src/crypto/verify.ts
1436
+ function sortObjectKeysRecursively(obj) {
1437
+ if (typeof obj !== "object" || obj === null) {
1438
+ return obj;
1439
+ }
1440
+ if (Array.isArray(obj)) {
1441
+ return obj.map((item) => sortObjectKeysRecursively(item));
1442
+ }
1443
+ return Object.keys(obj).sort().reduce((result, key) => {
1444
+ result[key] = sortObjectKeysRecursively(obj[key]);
1445
+ return result;
1446
+ }, {});
1447
+ }
1448
+ function hexToBytes(hex) {
1449
+ const bytes = new Uint8Array(hex.length / 2);
1450
+ for (let i = 0; i < hex.length; i += 2) {
1451
+ bytes[i / 2] = parseInt(hex.slice(i, i + 2), 16);
1452
+ }
1453
+ return bytes.buffer;
1454
+ }
1455
+ async function verifyExtensionSignature(files, manifest) {
1456
+ try {
1457
+ if (typeof crypto === "undefined" || !crypto.subtle) {
1458
+ return { valid: false, error: "WebCrypto API not available" };
1459
+ }
1460
+ const { publicKey: publicKeyHex, signature: signatureHex } = manifest;
1461
+ if (!publicKeyHex) {
1462
+ return { valid: false, error: "Missing publicKey in manifest" };
1463
+ }
1464
+ if (!signatureHex) {
1465
+ return { valid: false, error: "Missing signature in manifest" };
1466
+ }
1467
+ if (!/^[0-9a-fA-F]+$/.test(publicKeyHex)) {
1468
+ return { valid: false, error: "Invalid publicKey format (must be hex)" };
1469
+ }
1470
+ if (!/^[0-9a-fA-F]+$/.test(signatureHex)) {
1471
+ return { valid: false, error: "Invalid signature format (must be hex)" };
1472
+ }
1473
+ const publicKeyBuffer = hexToBytes(publicKeyHex);
1474
+ let publicKey;
1475
+ try {
1476
+ publicKey = await crypto.subtle.importKey(
1477
+ "raw",
1478
+ publicKeyBuffer,
1479
+ { name: "Ed25519", namedCurve: "Ed25519" },
1480
+ false,
1481
+ ["verify"]
1482
+ );
1483
+ } catch (err) {
1484
+ return {
1485
+ valid: false,
1486
+ error: `Failed to import public key: ${err instanceof Error ? err.message : "Ed25519 may not be supported in this browser"}`
1487
+ };
1488
+ }
1489
+ const manifestForHashing = sortObjectKeysRecursively({
1490
+ ...manifest,
1491
+ signature: ""
1492
+ });
1493
+ const manifestJson = JSON.stringify(manifestForHashing, null, 2);
1494
+ const manifestBytes = new TextEncoder().encode(manifestJson);
1495
+ const filesForHashing = files.map((file) => {
1496
+ if (file.path === "haextension/manifest.json") {
1497
+ return { path: file.path, content: manifestBytes };
1498
+ }
1499
+ return file;
1500
+ });
1501
+ filesForHashing.sort((a, b) => a.path.localeCompare(b.path));
1502
+ const totalLength = filesForHashing.reduce((sum, f) => sum + f.content.length, 0);
1503
+ const combined = new Uint8Array(totalLength);
1504
+ let offset = 0;
1505
+ for (const file of filesForHashing) {
1506
+ combined.set(file.content, offset);
1507
+ offset += file.content.length;
1508
+ }
1509
+ const hashBuffer = await crypto.subtle.digest("SHA-256", combined);
1510
+ const signatureBuffer = hexToBytes(signatureHex);
1511
+ const isValid = await crypto.subtle.verify(
1512
+ "Ed25519",
1513
+ publicKey,
1514
+ signatureBuffer,
1515
+ hashBuffer
1516
+ );
1517
+ return { valid: isValid };
1518
+ } catch (err) {
1519
+ console.error("Signature verification error:", err);
1520
+ return {
1521
+ valid: false,
1522
+ error: err instanceof Error ? err.message : "Unknown verification error"
1523
+ };
1524
+ }
1525
+ }
1526
+
1435
1527
  // src/index.ts
1436
1528
  function createHaexVaultClient(config = {}) {
1437
1529
  return new HaexVaultClient(config);
@@ -1452,11 +1544,14 @@ exports.TABLE_SEPARATOR = TABLE_SEPARATOR;
1452
1544
  exports.WebAPI = WebAPI;
1453
1545
  exports.createHaexVaultClient = createHaexVaultClient;
1454
1546
  exports.getTableName = getTableName;
1547
+ exports.hexToBytes = hexToBytes;
1455
1548
  exports.installBaseTag = installBaseTag;
1456
1549
  exports.installCookiePolyfill = installCookiePolyfill;
1457
1550
  exports.installHistoryPolyfill = installHistoryPolyfill;
1458
1551
  exports.installLocalStoragePolyfill = installLocalStoragePolyfill;
1459
1552
  exports.installPolyfills = installPolyfills;
1460
1553
  exports.installSessionStoragePolyfill = installSessionStoragePolyfill;
1554
+ exports.sortObjectKeysRecursively = sortObjectKeysRecursively;
1555
+ exports.verifyExtensionSignature = verifyExtensionSignature;
1461
1556
  //# sourceMappingURL=index.js.map
1462
1557
  //# sourceMappingURL=index.js.map