@haex-space/vault-sdk 2.3.8 → 2.3.12

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
@@ -373,7 +373,9 @@ var HAEXTENSION_EVENTS = {
373
373
  /** Context (theme, locale, platform) has changed */
374
374
  CONTEXT_CHANGED: "haextension:context:changed",
375
375
  /** Search request from HaexHub */
376
- SEARCH_REQUEST: "haextension:search:request"
376
+ SEARCH_REQUEST: "haextension:search:request",
377
+ /** External request from authorized client (browser extension, CLI, server, etc.) */
378
+ EXTERNAL_REQUEST: "haextension:external:request"
377
379
  };
378
380
 
379
381
  // src/methods.ts
@@ -816,6 +818,7 @@ var HaexVaultClient = class {
816
818
  constructor(config = {}) {
817
819
  this.pendingRequests = /* @__PURE__ */ new Map();
818
820
  this.eventListeners = /* @__PURE__ */ new Map();
821
+ this.externalRequestHandlers = /* @__PURE__ */ new Map();
819
822
  this.messageHandler = null;
820
823
  this.initialized = false;
821
824
  this.requestCounter = 0;
@@ -1078,6 +1081,40 @@ var HaexVaultClient = class {
1078
1081
  results
1079
1082
  });
1080
1083
  }
1084
+ /**
1085
+ * Register a handler for external requests (from browser extensions, CLI, servers, etc.)
1086
+ *
1087
+ * @param action - The action/method name to handle (e.g., "get-logins", "get-totp")
1088
+ * @param handler - Function that processes the request and returns a response
1089
+ * @returns Unsubscribe function to remove the handler
1090
+ *
1091
+ * @example
1092
+ * ```typescript
1093
+ * client.onExternalRequest("get-logins", async (request) => {
1094
+ * const entries = await getMatchingEntries(request.payload.url);
1095
+ * return {
1096
+ * requestId: request.requestId,
1097
+ * success: true,
1098
+ * data: { entries }
1099
+ * };
1100
+ * });
1101
+ * ```
1102
+ */
1103
+ onExternalRequest(action, handler) {
1104
+ this.externalRequestHandlers.set(action, handler);
1105
+ this.log(`[ExternalRequest] Registered handler for action: ${action}`);
1106
+ return () => {
1107
+ this.externalRequestHandlers.delete(action);
1108
+ this.log(`[ExternalRequest] Unregistered handler for action: ${action}`);
1109
+ };
1110
+ }
1111
+ /**
1112
+ * Send a response to an external request back to haex-vault
1113
+ * This is called internally after a handler processes a request
1114
+ */
1115
+ async respondToExternalRequest(response) {
1116
+ await this.request("external.respond", response);
1117
+ }
1081
1118
  async request(method, params = {}) {
1082
1119
  if (this.isNativeWindow && typeof window.__TAURI__ !== "undefined") {
1083
1120
  return this.invoke(method, params);
@@ -1175,6 +1212,13 @@ var HaexVaultClient = class {
1175
1212
  extensionVersion: params.extensionVersion,
1176
1213
  migrations: params.migrations
1177
1214
  });
1215
+ case "external.respond":
1216
+ return invoke("webview_extension_external_respond", {
1217
+ requestId: params.requestId,
1218
+ success: params.success,
1219
+ data: params.data,
1220
+ error: params.error
1221
+ });
1178
1222
  default:
1179
1223
  throw new HaexHubError(
1180
1224
  "METHOD_NOT_FOUND" /* METHOD_NOT_FOUND */,
@@ -1243,6 +1287,22 @@ var HaexVaultClient = class {
1243
1287
  console.error("[HaexSpace SDK] Failed to setup context change listener:", error);
1244
1288
  this.log("Failed to setup context change listener:", error);
1245
1289
  }
1290
+ try {
1291
+ await listen(HAEXTENSION_EVENTS.EXTERNAL_REQUEST, (event) => {
1292
+ this.log("Received external request event:", event);
1293
+ if (event.payload) {
1294
+ this.handleEvent({
1295
+ type: HAEXTENSION_EVENTS.EXTERNAL_REQUEST,
1296
+ data: event.payload,
1297
+ timestamp: Date.now()
1298
+ });
1299
+ }
1300
+ });
1301
+ console.log("[HaexSpace SDK] External request listener registered successfully");
1302
+ } catch (error) {
1303
+ console.error("[HaexSpace SDK] Failed to setup external request listener:", error);
1304
+ this.log("Failed to setup external request listener:", error);
1305
+ }
1246
1306
  this.resolveReady();
1247
1307
  return;
1248
1308
  }
@@ -1364,8 +1424,38 @@ postMessage error: ${e}`);
1364
1424
  this.log("Context updated:", this._context);
1365
1425
  this.notifySubscribers();
1366
1426
  }
1427
+ if (event.type === HAEXTENSION_EVENTS.EXTERNAL_REQUEST) {
1428
+ const externalEvent = event;
1429
+ this.handleExternalRequest(externalEvent.data);
1430
+ return;
1431
+ }
1367
1432
  this.emitEvent(event);
1368
1433
  }
1434
+ async handleExternalRequest(request) {
1435
+ this.log(`[ExternalRequest] Received request: ${request.action} from ${request.publicKey.substring(0, 20)}...`);
1436
+ const handler = this.externalRequestHandlers.get(request.action);
1437
+ if (!handler) {
1438
+ this.log(`[ExternalRequest] No handler for action: ${request.action}`);
1439
+ await this.respondToExternalRequest({
1440
+ requestId: request.requestId,
1441
+ success: false,
1442
+ error: `No handler registered for action: ${request.action}`
1443
+ });
1444
+ return;
1445
+ }
1446
+ try {
1447
+ const response = await handler(request);
1448
+ await this.respondToExternalRequest(response);
1449
+ this.log(`[ExternalRequest] Response sent for: ${request.action}`);
1450
+ } catch (error) {
1451
+ this.log(`[ExternalRequest] Handler error:`, error);
1452
+ await this.respondToExternalRequest({
1453
+ requestId: request.requestId,
1454
+ success: false,
1455
+ error: error instanceof Error ? error.message : String(error)
1456
+ });
1457
+ }
1458
+ }
1369
1459
  emitEvent(event) {
1370
1460
  this.log("Event received:", event);
1371
1461
  const listeners = this.eventListeners.get(event.type);
@@ -1526,11 +1616,193 @@ async function verifyExtensionSignature(files, manifest) {
1526
1616
  }
1527
1617
  }
1528
1618
 
1619
+ // src/crypto/vaultKey.ts
1620
+ var PBKDF2_ITERATIONS = 6e5;
1621
+ var KEY_LENGTH = 256;
1622
+ var ALGORITHM = "AES-GCM";
1623
+ async function deriveKeyFromPassword(password, salt) {
1624
+ const encoder = new TextEncoder();
1625
+ const passwordBuffer = encoder.encode(password);
1626
+ const saltBuffer = new Uint8Array(salt);
1627
+ const keyMaterial = await crypto.subtle.importKey(
1628
+ "raw",
1629
+ passwordBuffer,
1630
+ "PBKDF2",
1631
+ false,
1632
+ ["deriveKey"]
1633
+ );
1634
+ return await crypto.subtle.deriveKey(
1635
+ {
1636
+ name: "PBKDF2",
1637
+ salt: saltBuffer,
1638
+ iterations: PBKDF2_ITERATIONS,
1639
+ hash: "SHA-256"
1640
+ },
1641
+ keyMaterial,
1642
+ { name: ALGORITHM, length: KEY_LENGTH },
1643
+ false,
1644
+ // not extractable
1645
+ ["encrypt", "decrypt"]
1646
+ );
1647
+ }
1648
+ function generateVaultKey() {
1649
+ return crypto.getRandomValues(new Uint8Array(32));
1650
+ }
1651
+ async function encryptString(data, derivedKey) {
1652
+ const nonce = crypto.getRandomValues(new Uint8Array(12));
1653
+ const encoder = new TextEncoder();
1654
+ const dataBuffer = encoder.encode(data);
1655
+ const encryptedBuffer = await crypto.subtle.encrypt(
1656
+ {
1657
+ name: ALGORITHM,
1658
+ iv: nonce
1659
+ },
1660
+ derivedKey,
1661
+ dataBuffer
1662
+ );
1663
+ return {
1664
+ encryptedData: arrayBufferToBase64(encryptedBuffer),
1665
+ nonce: arrayBufferToBase64(nonce)
1666
+ };
1667
+ }
1668
+ async function decryptString(encryptedData, nonce, derivedKey) {
1669
+ const encryptedBuffer = base64ToArrayBuffer(encryptedData);
1670
+ const nonceBuffer = base64ToArrayBuffer(nonce);
1671
+ const encryptedDataBuffer = new Uint8Array(encryptedBuffer);
1672
+ const iv = new Uint8Array(nonceBuffer);
1673
+ const decryptedBuffer = await crypto.subtle.decrypt(
1674
+ {
1675
+ name: ALGORITHM,
1676
+ iv
1677
+ },
1678
+ derivedKey,
1679
+ encryptedDataBuffer
1680
+ );
1681
+ const decoder = new TextDecoder();
1682
+ return decoder.decode(decryptedBuffer);
1683
+ }
1684
+ async function encryptVaultKey(vaultKey, password) {
1685
+ const salt = crypto.getRandomValues(new Uint8Array(32));
1686
+ const derivedKey = await deriveKeyFromPassword(password, salt);
1687
+ const nonce = crypto.getRandomValues(new Uint8Array(12));
1688
+ const vaultKeyBuffer = new Uint8Array(vaultKey);
1689
+ const encryptedBuffer = await crypto.subtle.encrypt(
1690
+ {
1691
+ name: ALGORITHM,
1692
+ iv: nonce
1693
+ },
1694
+ derivedKey,
1695
+ vaultKeyBuffer
1696
+ );
1697
+ return {
1698
+ encryptedVaultKey: arrayBufferToBase64(encryptedBuffer),
1699
+ salt: arrayBufferToBase64(salt),
1700
+ vaultKeyNonce: arrayBufferToBase64(nonce)
1701
+ };
1702
+ }
1703
+ async function decryptVaultKey(encryptedVaultKey, salt, vaultKeyNonce, password) {
1704
+ const encryptedBuffer = base64ToArrayBuffer(encryptedVaultKey);
1705
+ const saltBuffer = base64ToArrayBuffer(salt);
1706
+ const nonceBuffer = base64ToArrayBuffer(vaultKeyNonce);
1707
+ const derivedKey = await deriveKeyFromPassword(password, saltBuffer);
1708
+ const encryptedData = new Uint8Array(encryptedBuffer);
1709
+ const iv = new Uint8Array(nonceBuffer);
1710
+ const decryptedBuffer = await crypto.subtle.decrypt(
1711
+ {
1712
+ name: ALGORITHM,
1713
+ iv
1714
+ },
1715
+ derivedKey,
1716
+ encryptedData
1717
+ );
1718
+ return new Uint8Array(decryptedBuffer);
1719
+ }
1720
+ async function decryptVaultName(encryptedVaultName, vaultNameNonce, vaultNameSalt, password) {
1721
+ const saltBuffer = base64ToArrayBuffer(vaultNameSalt);
1722
+ const derivedKey = await deriveKeyFromPassword(password, saltBuffer);
1723
+ return decryptString(encryptedVaultName, vaultNameNonce, derivedKey);
1724
+ }
1725
+ async function encryptCrdtData(data, vaultKey) {
1726
+ const vaultKeyBuffer = new Uint8Array(vaultKey);
1727
+ const cryptoKey = await crypto.subtle.importKey(
1728
+ "raw",
1729
+ vaultKeyBuffer,
1730
+ { name: ALGORITHM },
1731
+ false,
1732
+ ["encrypt"]
1733
+ );
1734
+ const nonce = crypto.getRandomValues(new Uint8Array(12));
1735
+ const encoder = new TextEncoder();
1736
+ const dataBuffer = encoder.encode(JSON.stringify(data));
1737
+ const encryptedBuffer = await crypto.subtle.encrypt(
1738
+ {
1739
+ name: ALGORITHM,
1740
+ iv: nonce
1741
+ },
1742
+ cryptoKey,
1743
+ dataBuffer
1744
+ );
1745
+ return {
1746
+ encryptedData: arrayBufferToBase64(encryptedBuffer),
1747
+ nonce: arrayBufferToBase64(nonce)
1748
+ };
1749
+ }
1750
+ async function decryptCrdtData(encryptedData, nonce, vaultKey) {
1751
+ const vaultKeyBuffer = new Uint8Array(vaultKey);
1752
+ const cryptoKey = await crypto.subtle.importKey(
1753
+ "raw",
1754
+ vaultKeyBuffer,
1755
+ { name: ALGORITHM },
1756
+ false,
1757
+ ["decrypt"]
1758
+ );
1759
+ const encryptedBuffer = base64ToArrayBuffer(encryptedData);
1760
+ const nonceBuffer = base64ToArrayBuffer(nonce);
1761
+ const encryptedDataBuffer = new Uint8Array(encryptedBuffer);
1762
+ const iv = new Uint8Array(nonceBuffer);
1763
+ const decryptedBuffer = await crypto.subtle.decrypt(
1764
+ {
1765
+ name: ALGORITHM,
1766
+ iv
1767
+ },
1768
+ cryptoKey,
1769
+ encryptedDataBuffer
1770
+ );
1771
+ const decoder = new TextDecoder();
1772
+ const jsonString = decoder.decode(decryptedBuffer);
1773
+ return JSON.parse(jsonString);
1774
+ }
1775
+ function arrayBufferToBase64(buffer) {
1776
+ const bytes = buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer);
1777
+ if (typeof Buffer !== "undefined") {
1778
+ return Buffer.from(bytes).toString("base64");
1779
+ }
1780
+ let binary = "";
1781
+ for (let i = 0; i < bytes.length; i++) {
1782
+ const byte = bytes[i];
1783
+ if (byte !== void 0) {
1784
+ binary += String.fromCharCode(byte);
1785
+ }
1786
+ }
1787
+ return btoa(binary);
1788
+ }
1789
+ function base64ToArrayBuffer(base64) {
1790
+ if (typeof Buffer !== "undefined") {
1791
+ return new Uint8Array(Buffer.from(base64, "base64"));
1792
+ }
1793
+ const binary = atob(base64);
1794
+ const bytes = new Uint8Array(binary.length);
1795
+ for (let i = 0; i < binary.length; i++) {
1796
+ bytes[i] = binary.charCodeAt(i);
1797
+ }
1798
+ return bytes;
1799
+ }
1800
+
1529
1801
  // src/index.ts
1530
1802
  function createHaexVaultClient(config = {}) {
1531
1803
  return new HaexVaultClient(config);
1532
1804
  }
1533
1805
 
1534
- export { DEFAULT_TIMEOUT, DatabaseAPI, ErrorCode, FilesystemAPI, HAEXSPACE_MESSAGE_TYPES, HAEXTENSION_EVENTS, HAEXTENSION_METHODS, HaexHubError, HaexVaultClient, PermissionStatus, PermissionsAPI, TABLE_SEPARATOR, WebAPI, createHaexVaultClient, getTableName, hexToBytes, installBaseTag, installCookiePolyfill, installHistoryPolyfill, installLocalStoragePolyfill, installPolyfills, installSessionStoragePolyfill, sortObjectKeysRecursively, verifyExtensionSignature };
1806
+ export { DEFAULT_TIMEOUT, DatabaseAPI, ErrorCode, FilesystemAPI, HAEXSPACE_MESSAGE_TYPES, HAEXTENSION_EVENTS, HAEXTENSION_METHODS, HaexHubError, HaexVaultClient, PermissionStatus, PermissionsAPI, TABLE_SEPARATOR, WebAPI, arrayBufferToBase64, base64ToArrayBuffer, createHaexVaultClient, decryptCrdtData, decryptString, decryptVaultKey, decryptVaultName, deriveKeyFromPassword, encryptCrdtData, encryptString, encryptVaultKey, generateVaultKey, getTableName, hexToBytes, installBaseTag, installCookiePolyfill, installHistoryPolyfill, installLocalStoragePolyfill, installPolyfills, installSessionStoragePolyfill, sortObjectKeysRecursively, verifyExtensionSignature };
1535
1807
  //# sourceMappingURL=index.mjs.map
1536
1808
  //# sourceMappingURL=index.mjs.map