7c8afffef1f29816edee052bc0d1048aa3cebcead7b4dc7566917ac633a97c09.json raw

   1  {"ast":null,"code":"import _asyncToGenerator from \"/home/mleku/src/orly.dev/next/signer/node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js\";\n/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { BrowserSyncFlow, CryptoHelper, NostrHelper, deriveKeyArgon2 } from '@common';\nimport { FirefoxMetaHandler } from './app/common/data/firefox-meta-handler';\nimport { finalizeEvent, nip04, nip44 } from 'nostr-tools';\nimport { Buffer } from 'buffer';\nimport browser from 'webextension-polyfill';\nexport const debug = function (message) {\n  const dateString = new Date().toISOString();\n  console.log(`[Smesh Signer - ${dateString}]: ${JSON.stringify(message)}`);\n};\nexport const getBrowserSessionData = /*#__PURE__*/function () {\n  var _ref = _asyncToGenerator(function* () {\n    const browserSessionData = yield browser.storage.session.get(null);\n    // Check for required vault session keys, not just any key existing.\n    // Stray keys in session storage (e.g. profile cache) must not cause\n    // the vault to appear unlocked.\n    if (!browserSessionData || !browserSessionData['iv'] || !browserSessionData['identities']) {\n      return undefined;\n    }\n    return browserSessionData;\n  });\n  return function getBrowserSessionData() {\n    return _ref.apply(this, arguments);\n  };\n}();\nexport const getSignerMetaData = /*#__PURE__*/function () {\n  var _ref2 = _asyncToGenerator(function* () {\n    const signerMetaHandler = new FirefoxMetaHandler();\n    return yield signerMetaHandler.loadFullData();\n  });\n  return function getSignerMetaData() {\n    return _ref2.apply(this, arguments);\n  };\n}();\n/**\n * Check if reckless mode should auto-approve the request.\n * Returns true if should auto-approve, false if should use normal permission flow.\n *\n * Logic:\n * - If reckless mode is OFF → return false (use normal flow)\n * - If reckless mode is ON and whitelist is empty → return true (approve all)\n * - If reckless mode is ON and whitelist has entries → return true only if host is in whitelist\n */\nexport const shouldRecklessModeApprove = /*#__PURE__*/function () {\n  var _ref3 = _asyncToGenerator(function* (host) {\n    const signerMetaData = yield getSignerMetaData();\n    debug(`shouldRecklessModeApprove: recklessMode=${signerMetaData.recklessMode}, host=${host}`);\n    debug(`Full signerMetaData: ${JSON.stringify(signerMetaData)}`);\n    if (!signerMetaData.recklessMode) {\n      return false;\n    }\n    const whitelistedHosts = signerMetaData.whitelistedHosts ?? [];\n    if (whitelistedHosts.length === 0) {\n      // Reckless mode ON, no whitelist → approve all\n      return true;\n    }\n    // Reckless mode ON, whitelist has entries → only approve if host is whitelisted\n    return whitelistedHosts.includes(host);\n  });\n  return function shouldRecklessModeApprove(_x) {\n    return _ref3.apply(this, arguments);\n  };\n}();\nexport const getBrowserSyncData = /*#__PURE__*/function () {\n  var _ref4 = _asyncToGenerator(function* () {\n    const signerMetaHandler = new FirefoxMetaHandler();\n    const signerMetaData = yield signerMetaHandler.loadFullData();\n    let browserSyncData;\n    if (signerMetaData.syncFlow === BrowserSyncFlow.NO_SYNC) {\n      browserSyncData = yield browser.storage.local.get(null);\n    } else if (signerMetaData.syncFlow === BrowserSyncFlow.BROWSER_SYNC) {\n      browserSyncData = yield browser.storage.sync.get(null);\n    }\n    return browserSyncData;\n  });\n  return function getBrowserSyncData() {\n    return _ref4.apply(this, arguments);\n  };\n}();\nexport const savePermissionsToBrowserSyncStorage = /*#__PURE__*/function () {\n  var _ref5 = _asyncToGenerator(function* (permissions) {\n    const signerMetaHandler = new FirefoxMetaHandler();\n    const signerMetaData = yield signerMetaHandler.loadFullData();\n    if (signerMetaData.syncFlow === BrowserSyncFlow.NO_SYNC) {\n      yield browser.storage.local.set({\n        permissions\n      });\n    } else if (signerMetaData.syncFlow === BrowserSyncFlow.BROWSER_SYNC) {\n      yield browser.storage.sync.set({\n        permissions\n      });\n    }\n  });\n  return function savePermissionsToBrowserSyncStorage(_x2) {\n    return _ref5.apply(this, arguments);\n  };\n}();\nexport const checkPermissions = function (browserSessionData, identity, host, method, params) {\n  const permissions = browserSessionData.permissions.filter(x => x.identityId === identity.id && x.host === host && x.method === method);\n  if (permissions.length === 0) {\n    return undefined;\n  }\n  if (method === 'getPublicKey') {\n    // No evaluation of params required.\n    return permissions.every(x => x.methodPolicy === 'allow');\n  }\n  if (method === 'getRelays') {\n    // No evaluation of params required.\n    return permissions.every(x => x.methodPolicy === 'allow');\n  }\n  if (method === 'signEvent') {\n    // Evaluate params.\n    const eventTemplate = params;\n    if (permissions.find(x => x.methodPolicy === 'allow' && typeof x.kind === 'undefined')) {\n      return true;\n    }\n    if (permissions.some(x => x.methodPolicy === 'allow' && x.kind === eventTemplate.kind)) {\n      return true;\n    }\n    if (permissions.some(x => x.methodPolicy === 'deny' && x.kind === eventTemplate.kind)) {\n      return false;\n    }\n    return undefined;\n  }\n  if (method === 'nip04.encrypt') {\n    // No evaluation of params required.\n    return permissions.every(x => x.methodPolicy === 'allow');\n  }\n  if (method === 'nip44.encrypt') {\n    // No evaluation of params required.\n    return permissions.every(x => x.methodPolicy === 'allow');\n  }\n  if (method === 'nip04.decrypt') {\n    // No evaluation of params required.\n    return permissions.every(x => x.methodPolicy === 'allow');\n  }\n  if (method === 'nip44.decrypt') {\n    // No evaluation of params required.\n    return permissions.every(x => x.methodPolicy === 'allow');\n  }\n  // MLS methods — treated as a single permission group ('mls.*').\n  if (method.startsWith('mls.')) {\n    const mlsPerms = browserSessionData.permissions.filter(x => x.identityId === identity.id && x.host === host && x.method === 'mls.*');\n    if (mlsPerms.length === 0) return undefined;\n    return mlsPerms.every(x => x.methodPolicy === 'allow');\n  }\n  return undefined;\n};\n/**\n * Check if a method is a WebLN method\n */\nexport const isWeblnMethod = function (method) {\n  return method.startsWith('webln.');\n};\n/**\n * Check WebLN permissions for a host.\n * Note: WebLN permissions are NOT tied to identities since the wallet is global.\n * For sendPayment, always returns undefined (require user prompt for security).\n */\nexport const checkWeblnPermissions = function (browserSessionData, host, method) {\n  // sendPayment ALWAYS requires user approval (security-critical, irreversible)\n  if (method === 'webln.sendPayment') {\n    return undefined;\n  }\n  // keysend also requires approval\n  if (method === 'webln.keysend') {\n    return undefined;\n  }\n  // For other WebLN methods, check stored permissions\n  // WebLN permissions use 'webln' as the identityId\n  const permissions = browserSessionData.permissions.filter(x => x.identityId === 'webln' && x.host === host && x.method === method);\n  if (permissions.length === 0) {\n    return undefined;\n  }\n  return permissions.every(x => x.methodPolicy === 'allow');\n};\nexport const storePermission = /*#__PURE__*/function () {\n  var _ref6 = _asyncToGenerator(function* (browserSessionData, identity, host, method, methodPolicy, kind) {\n    const browserSyncData = yield getBrowserSyncData();\n    if (!browserSyncData) {\n      throw new Error(`Could not retrieve sync data`);\n    }\n    // For WebLN methods, use 'webln' as identityId since wallet is global\n    const identityId = identity?.id ?? 'webln';\n    const permission = {\n      id: crypto.randomUUID(),\n      identityId,\n      host,\n      method: method,\n      // Cast for storage compatibility\n      methodPolicy,\n      kind\n    };\n    // Store session data\n    yield browser.storage.session.set({\n      permissions: [...browserSessionData.permissions, permission]\n    });\n    // Encrypt permission to store in sync storage (depending on sync flow).\n    const encryptedPermission = yield encryptPermission(permission, browserSessionData);\n    yield savePermissionsToBrowserSyncStorage([...browserSyncData.permissions, encryptedPermission]);\n  });\n  return function storePermission(_x3, _x4, _x5, _x6, _x7, _x8) {\n    return _ref6.apply(this, arguments);\n  };\n}();\nexport const getPosition = /*#__PURE__*/function () {\n  var _ref7 = _asyncToGenerator(function* (width, height) {\n    let left = 0;\n    let top = 0;\n    try {\n      const lastFocused = yield browser.windows.getLastFocused();\n      if (lastFocused && lastFocused.top !== undefined && lastFocused.left !== undefined && lastFocused.width !== undefined && lastFocused.height !== undefined) {\n        // Position window in the center of the lastFocused window\n        top = Math.round(lastFocused.top + (lastFocused.height - height) / 2);\n        left = Math.round(lastFocused.left + (lastFocused.width - width) / 2);\n      } else {\n        console.error('Last focused window properties are undefined.');\n      }\n    } catch (error) {\n      console.error('Error getting window position:', error);\n    }\n    return {\n      top,\n      left\n    };\n  });\n  return function getPosition(_x9, _x0) {\n    return _ref7.apply(this, arguments);\n  };\n}();\nexport const signEvent = function (eventTemplate, privkey) {\n  return finalizeEvent(eventTemplate, NostrHelper.hex2bytes(privkey));\n};\nexport const nip04Encrypt = /*#__PURE__*/function () {\n  var _ref8 = _asyncToGenerator(function* (privkey, peerPubkey, plaintext) {\n    return yield nip04.encrypt(NostrHelper.hex2bytes(privkey), peerPubkey, plaintext);\n  });\n  return function nip04Encrypt(_x1, _x10, _x11) {\n    return _ref8.apply(this, arguments);\n  };\n}();\nexport const nip44Encrypt = /*#__PURE__*/function () {\n  var _ref9 = _asyncToGenerator(function* (privkey, peerPubkey, plaintext) {\n    const key = nip44.v2.utils.getConversationKey(NostrHelper.hex2bytes(privkey), peerPubkey);\n    return nip44.v2.encrypt(plaintext, key);\n  });\n  return function nip44Encrypt(_x12, _x13, _x14) {\n    return _ref9.apply(this, arguments);\n  };\n}();\nexport const nip04Decrypt = /*#__PURE__*/function () {\n  var _ref0 = _asyncToGenerator(function* (privkey, peerPubkey, ciphertext) {\n    return yield nip04.decrypt(NostrHelper.hex2bytes(privkey), peerPubkey, ciphertext);\n  });\n  return function nip04Decrypt(_x15, _x16, _x17) {\n    return _ref0.apply(this, arguments);\n  };\n}();\nexport const nip44Decrypt = /*#__PURE__*/function () {\n  var _ref1 = _asyncToGenerator(function* (privkey, peerPubkey, ciphertext) {\n    const key = nip44.v2.utils.getConversationKey(NostrHelper.hex2bytes(privkey), peerPubkey);\n    return nip44.v2.decrypt(ciphertext, key);\n  });\n  return function nip44Decrypt(_x18, _x19, _x20) {\n    return _ref1.apply(this, arguments);\n  };\n}();\nconst encryptPermission = /*#__PURE__*/function () {\n  var _ref10 = _asyncToGenerator(function* (permission, sessionData) {\n    const encryptedPermission = {\n      id: yield encrypt(permission.id, sessionData),\n      identityId: yield encrypt(permission.identityId, sessionData),\n      host: yield encrypt(permission.host, sessionData),\n      method: yield encrypt(permission.method, sessionData),\n      methodPolicy: yield encrypt(permission.methodPolicy, sessionData)\n    };\n    if (typeof permission.kind !== 'undefined') {\n      encryptedPermission.kind = yield encrypt(permission.kind.toString(), sessionData);\n    }\n    return encryptedPermission;\n  });\n  return function encryptPermission(_x21, _x22) {\n    return _ref10.apply(this, arguments);\n  };\n}();\nconst encrypt = /*#__PURE__*/function () {\n  var _ref11 = _asyncToGenerator(function* (value, sessionData) {\n    // v2: Use pre-derived key with AES-GCM directly\n    if (sessionData.vaultKey) {\n      const keyBytes = Buffer.from(sessionData.vaultKey, 'base64');\n      const iv = Buffer.from(sessionData.iv, 'base64');\n      const key = yield crypto.subtle.importKey('raw', keyBytes, {\n        name: 'AES-GCM'\n      }, false, ['encrypt']);\n      const cipherText = yield crypto.subtle.encrypt({\n        name: 'AES-GCM',\n        iv\n      }, key, new TextEncoder().encode(value));\n      return Buffer.from(cipherText).toString('base64');\n    }\n    // v1: Use password with PBKDF2\n    return yield CryptoHelper.encrypt(value, sessionData.iv, sessionData.vaultPassword);\n  });\n  return function encrypt(_x23, _x24) {\n    return _ref11.apply(this, arguments);\n  };\n}();\n// ==========================================\n// Unlock Vault Logic (for background script)\n// ==========================================\n/**\n * Decrypt a value using AES-GCM with pre-derived key (v2)\n */\nfunction decryptV2(_x25, _x26, _x27) {\n  return _decryptV.apply(this, arguments);\n}\n/**\n * Decrypt a value using PBKDF2 (v1)\n */\nfunction _decryptV() {\n  _decryptV = _asyncToGenerator(function* (encryptedBase64, ivBase64, keyBase64) {\n    const keyBytes = Buffer.from(keyBase64, 'base64');\n    const iv = Buffer.from(ivBase64, 'base64');\n    const cipherText = Buffer.from(encryptedBase64, 'base64');\n    const key = yield crypto.subtle.importKey('raw', keyBytes, {\n      name: 'AES-GCM'\n    }, false, ['decrypt']);\n    const decrypted = yield crypto.subtle.decrypt({\n      name: 'AES-GCM',\n      iv\n    }, key, cipherText);\n    return new TextDecoder().decode(decrypted);\n  });\n  return _decryptV.apply(this, arguments);\n}\nfunction decryptV1(_x28, _x29, _x30) {\n  return _decryptV2.apply(this, arguments);\n}\n/**\n * Generic decrypt function that handles both v1 and v2\n */\nfunction _decryptV2() {\n  _decryptV2 = _asyncToGenerator(function* (encryptedBase64, ivBase64, password) {\n    return CryptoHelper.decrypt(encryptedBase64, ivBase64, password);\n  });\n  return _decryptV2.apply(this, arguments);\n}\nfunction decryptValue(_x31, _x32, _x33, _x34) {\n  return _decryptValue.apply(this, arguments);\n}\n/**\n * Parse decrypted value to the desired type\n */\nfunction _decryptValue() {\n  _decryptValue = _asyncToGenerator(function* (encrypted, iv, keyOrPassword, isV2) {\n    if (isV2) {\n      return decryptV2(encrypted, iv, keyOrPassword);\n    }\n    return decryptV1(encrypted, iv, keyOrPassword);\n  });\n  return _decryptValue.apply(this, arguments);\n}\nfunction parseValue(value, type) {\n  switch (type) {\n    case 'number':\n      return parseInt(value);\n    case 'boolean':\n      return value === 'true';\n    default:\n      return value;\n  }\n}\n/**\n * Decrypt an identity\n */\nfunction decryptIdentity(_x35, _x36, _x37, _x38) {\n  return _decryptIdentity.apply(this, arguments);\n}\n/**\n * Decrypt a permission\n */\nfunction _decryptIdentity() {\n  _decryptIdentity = _asyncToGenerator(function* (identity, iv, keyOrPassword, isV2) {\n    return {\n      id: yield decryptValue(identity.id, iv, keyOrPassword, isV2),\n      nick: yield decryptValue(identity.nick, iv, keyOrPassword, isV2),\n      createdAt: yield decryptValue(identity.createdAt, iv, keyOrPassword, isV2),\n      privkey: yield decryptValue(identity.privkey, iv, keyOrPassword, isV2)\n    };\n  });\n  return _decryptIdentity.apply(this, arguments);\n}\nfunction decryptPermission(_x39, _x40, _x41, _x42) {\n  return _decryptPermission.apply(this, arguments);\n}\n/**\n * Decrypt a relay\n */\nfunction _decryptPermission() {\n  _decryptPermission = _asyncToGenerator(function* (permission, iv, keyOrPassword, isV2) {\n    const decrypted = {\n      id: yield decryptValue(permission.id, iv, keyOrPassword, isV2),\n      identityId: yield decryptValue(permission.identityId, iv, keyOrPassword, isV2),\n      host: yield decryptValue(permission.host, iv, keyOrPassword, isV2),\n      method: yield decryptValue(permission.method, iv, keyOrPassword, isV2),\n      methodPolicy: yield decryptValue(permission.methodPolicy, iv, keyOrPassword, isV2)\n    };\n    if (permission.kind) {\n      decrypted.kind = parseValue(yield decryptValue(permission.kind, iv, keyOrPassword, isV2), 'number');\n    }\n    return decrypted;\n  });\n  return _decryptPermission.apply(this, arguments);\n}\nfunction decryptRelay(_x43, _x44, _x45, _x46) {\n  return _decryptRelay.apply(this, arguments);\n}\n/**\n * Decrypt an NWC connection\n */\nfunction _decryptRelay() {\n  _decryptRelay = _asyncToGenerator(function* (relay, iv, keyOrPassword, isV2) {\n    return {\n      id: yield decryptValue(relay.id, iv, keyOrPassword, isV2),\n      identityId: yield decryptValue(relay.identityId, iv, keyOrPassword, isV2),\n      url: yield decryptValue(relay.url, iv, keyOrPassword, isV2),\n      read: parseValue(yield decryptValue(relay.read, iv, keyOrPassword, isV2), 'boolean'),\n      write: parseValue(yield decryptValue(relay.write, iv, keyOrPassword, isV2), 'boolean')\n    };\n  });\n  return _decryptRelay.apply(this, arguments);\n}\nfunction decryptNwcConnection(_x47, _x48, _x49, _x50) {\n  return _decryptNwcConnection.apply(this, arguments);\n}\n/**\n * Decrypt a Cashu mint\n */\nfunction _decryptNwcConnection() {\n  _decryptNwcConnection = _asyncToGenerator(function* (nwc, iv, keyOrPassword, isV2) {\n    const decrypted = {\n      id: yield decryptValue(nwc.id, iv, keyOrPassword, isV2),\n      name: yield decryptValue(nwc.name, iv, keyOrPassword, isV2),\n      connectionUrl: yield decryptValue(nwc.connectionUrl, iv, keyOrPassword, isV2),\n      walletPubkey: yield decryptValue(nwc.walletPubkey, iv, keyOrPassword, isV2),\n      relayUrl: yield decryptValue(nwc.relayUrl, iv, keyOrPassword, isV2),\n      secret: yield decryptValue(nwc.secret, iv, keyOrPassword, isV2),\n      createdAt: yield decryptValue(nwc.createdAt, iv, keyOrPassword, isV2)\n    };\n    if (nwc.lud16) {\n      decrypted.lud16 = yield decryptValue(nwc.lud16, iv, keyOrPassword, isV2);\n    }\n    if (nwc.cachedBalance) {\n      decrypted.cachedBalance = parseValue(yield decryptValue(nwc.cachedBalance, iv, keyOrPassword, isV2), 'number');\n    }\n    if (nwc.cachedBalanceAt) {\n      decrypted.cachedBalanceAt = yield decryptValue(nwc.cachedBalanceAt, iv, keyOrPassword, isV2);\n    }\n    return decrypted;\n  });\n  return _decryptNwcConnection.apply(this, arguments);\n}\nfunction decryptCashuMint(_x51, _x52, _x53, _x54) {\n  return _decryptCashuMint.apply(this, arguments);\n}\n/**\n * Handle an unlock request from the unlock popup\n */\nfunction _decryptCashuMint() {\n  _decryptCashuMint = _asyncToGenerator(function* (mint, iv, keyOrPassword, isV2) {\n    const proofsJson = yield decryptValue(mint.proofs, iv, keyOrPassword, isV2);\n    const decrypted = {\n      id: yield decryptValue(mint.id, iv, keyOrPassword, isV2),\n      name: yield decryptValue(mint.name, iv, keyOrPassword, isV2),\n      mintUrl: yield decryptValue(mint.mintUrl, iv, keyOrPassword, isV2),\n      unit: yield decryptValue(mint.unit, iv, keyOrPassword, isV2),\n      createdAt: yield decryptValue(mint.createdAt, iv, keyOrPassword, isV2),\n      proofs: JSON.parse(proofsJson)\n    };\n    if (mint.cachedBalance) {\n      decrypted.cachedBalance = parseValue(yield decryptValue(mint.cachedBalance, iv, keyOrPassword, isV2), 'number');\n    }\n    if (mint.cachedBalanceAt) {\n      decrypted.cachedBalanceAt = yield decryptValue(mint.cachedBalanceAt, iv, keyOrPassword, isV2);\n    }\n    return decrypted;\n  });\n  return _decryptCashuMint.apply(this, arguments);\n}\nexport function handleUnlockRequest(_x55) {\n  return _handleUnlockRequest.apply(this, arguments);\n}\n/**\n * Open the unlock popup window\n */\nfunction _handleUnlockRequest() {\n  _handleUnlockRequest = _asyncToGenerator(function* (password) {\n    try {\n      debug('handleUnlockRequest: Starting unlock...');\n      // Check if already unlocked\n      const existingSession = yield getBrowserSessionData();\n      if (existingSession) {\n        debug('handleUnlockRequest: Already unlocked');\n        return {\n          success: true\n        };\n      }\n      // Get sync data\n      const browserSyncData = yield getBrowserSyncData();\n      if (!browserSyncData) {\n        return {\n          success: false,\n          error: 'No vault data found'\n        };\n      }\n      // Verify password\n      const passwordHash = yield CryptoHelper.hash(password);\n      if (passwordHash !== browserSyncData.vaultHash) {\n        return {\n          success: false,\n          error: 'Invalid password'\n        };\n      }\n      debug('handleUnlockRequest: Password verified');\n      // Detect vault version\n      const isV2 = !!browserSyncData.salt;\n      debug(`handleUnlockRequest: Vault version: ${isV2 ? 'v2' : 'v1'}`);\n      let keyOrPassword;\n      let vaultKey;\n      let vaultPassword;\n      if (isV2) {\n        // v2: Derive key with Argon2id (~3 seconds)\n        debug('handleUnlockRequest: Deriving Argon2id key...');\n        const saltBytes = Buffer.from(browserSyncData.salt, 'base64');\n        const keyBytes = yield deriveKeyArgon2(password, saltBytes);\n        vaultKey = Buffer.from(keyBytes).toString('base64');\n        keyOrPassword = vaultKey;\n        debug('handleUnlockRequest: Key derived');\n      } else {\n        // v1: Use password directly\n        vaultPassword = password;\n        keyOrPassword = password;\n      }\n      // Decrypt identities\n      debug('handleUnlockRequest: Decrypting identities...');\n      const decryptedIdentities = [];\n      for (const identity of browserSyncData.identities) {\n        const decrypted = yield decryptIdentity(identity, browserSyncData.iv, keyOrPassword, isV2);\n        decryptedIdentities.push(decrypted);\n      }\n      debug(`handleUnlockRequest: Decrypted ${decryptedIdentities.length} identities`);\n      // Decrypt permissions\n      debug('handleUnlockRequest: Decrypting permissions...');\n      const decryptedPermissions = [];\n      for (const permission of browserSyncData.permissions) {\n        try {\n          const decrypted = yield decryptPermission(permission, browserSyncData.iv, keyOrPassword, isV2);\n          decryptedPermissions.push(decrypted);\n        } catch (e) {\n          debug(`handleUnlockRequest: Skipping corrupted permission: ${e}`);\n        }\n      }\n      debug(`handleUnlockRequest: Decrypted ${decryptedPermissions.length} permissions`);\n      // Decrypt relays\n      debug('handleUnlockRequest: Decrypting relays...');\n      const decryptedRelays = [];\n      for (const relay of browserSyncData.relays) {\n        const decrypted = yield decryptRelay(relay, browserSyncData.iv, keyOrPassword, isV2);\n        decryptedRelays.push(decrypted);\n      }\n      debug(`handleUnlockRequest: Decrypted ${decryptedRelays.length} relays`);\n      // Decrypt NWC connections\n      debug('handleUnlockRequest: Decrypting NWC connections...');\n      const decryptedNwcConnections = [];\n      for (const nwc of browserSyncData.nwcConnections ?? []) {\n        const decrypted = yield decryptNwcConnection(nwc, browserSyncData.iv, keyOrPassword, isV2);\n        decryptedNwcConnections.push(decrypted);\n      }\n      debug(`handleUnlockRequest: Decrypted ${decryptedNwcConnections.length} NWC connections`);\n      // Decrypt Cashu mints\n      debug('handleUnlockRequest: Decrypting Cashu mints...');\n      const decryptedCashuMints = [];\n      for (const mint of browserSyncData.cashuMints ?? []) {\n        const decrypted = yield decryptCashuMint(mint, browserSyncData.iv, keyOrPassword, isV2);\n        decryptedCashuMints.push(decrypted);\n      }\n      debug(`handleUnlockRequest: Decrypted ${decryptedCashuMints.length} Cashu mints`);\n      // Decrypt selectedIdentityId\n      let decryptedSelectedIdentityId = null;\n      if (browserSyncData.selectedIdentityId !== null) {\n        decryptedSelectedIdentityId = yield decryptValue(browserSyncData.selectedIdentityId, browserSyncData.iv, keyOrPassword, isV2);\n      }\n      debug(`handleUnlockRequest: selectedIdentityId: ${decryptedSelectedIdentityId}`);\n      // Build session data\n      const browserSessionData = {\n        vaultPassword: isV2 ? undefined : vaultPassword,\n        vaultKey: isV2 ? vaultKey : undefined,\n        iv: browserSyncData.iv,\n        salt: browserSyncData.salt,\n        permissions: decryptedPermissions,\n        identities: decryptedIdentities,\n        selectedIdentityId: decryptedSelectedIdentityId,\n        relays: decryptedRelays,\n        nwcConnections: decryptedNwcConnections,\n        cashuMints: decryptedCashuMints\n      };\n      // Save session data\n      debug('handleUnlockRequest: Saving session data...');\n      yield browser.storage.session.set(browserSessionData);\n      debug('handleUnlockRequest: Unlock complete!');\n      return {\n        success: true\n      };\n    } catch (error) {\n      debug(`handleUnlockRequest: Error: ${error.message}`);\n      return {\n        success: false,\n        error: error.message || 'Unlock failed'\n      };\n    }\n  });\n  return _handleUnlockRequest.apply(this, arguments);\n}\nexport function openUnlockPopup(_x56) {\n  return _openUnlockPopup.apply(this, arguments);\n}\nfunction _openUnlockPopup() {\n  _openUnlockPopup = _asyncToGenerator(function* (host) {\n    const width = 375;\n    const height = 500;\n    const {\n      top,\n      left\n    } = yield getPosition(width, height);\n    const id = crypto.randomUUID();\n    let url = `unlock.html?id=${id}`;\n    if (host) {\n      url += `&host=${encodeURIComponent(host)}`;\n    }\n    const win = yield browser.windows.create({\n      type: 'popup',\n      url,\n      height,\n      width,\n      top,\n      left\n    });\n    return win.id;\n  });\n  return _openUnlockPopup.apply(this, arguments);\n}","map":null,"metadata":{},"sourceType":"module","externalDependencies":[]}