@p47h/vault-js 0.9.0
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/LICENSE +623 -0
- package/README.md +150 -0
- package/dist/index.d.ts +598 -0
- package/dist/index.js +36 -0
- package/dist/index.js.map +1 -0
- package/package.json +60 -0
- package/wasm/p47h_wasm_core.d.ts +259 -0
- package/wasm/p47h_wasm_core.js +1185 -0
- package/wasm/p47h_wasm_core_bg.wasm +0 -0
- package/wasm/p47h_wasm_core_bg.wasm.d.ts +40 -0
- package/wasm/package.json +24 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/domain/errors.ts","../src/adapters/WasmCryptoAdapter.ts","../src/adapters/IndexedDbStorage.ts","../src/logic/VaultService.ts"],"names":["VaultError","message","code","cause","InitializationError","AuthenticationError","NotAuthenticatedError","StorageError","CryptoError","WasmCryptoAdapter","wasmPath","licenseKey","wasmModule","error","response","blob","url","isCommercial","licensee","password","salt","data","encryptedData","wasm","e","wrappedSecret","sessionKey","length","BrowserStorage","req","resolve","reject","event","db","mode","callback","tx","store","key","RECOVERY_CODE_PREFIX","RECOVERY_CODE_BYTES","VaultService","storage","config","client","did","internalData","internalJson","internalBytes","encryptedMain","recoveryCode","encryptedRecovery","storageBlob","targetDid","keys","storedBlob","decryptedBytes","json","options","newPassword","rotateRecoveryCode","stored","newEncryptedMain","newRecoveryCode","newRecoveryBlob","newEncryptedRecovery","secret","decrypted","originalData","updatedBytes","bytes","hex","b","secrets","binString","x","base64","m"],"mappings":"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","file":"index.js","sourcesContent":["/**\r\n* Domain error definitions for P47H Vault JS.\r\n* Basis for handling typed exceptions.\r\n */\r\n\r\nexport class VaultError extends Error {\r\n constructor(message: string, public code: string, public cause?: unknown) {\r\n super(message);\r\n this.name = 'VaultError';\r\n }\r\n}\r\n\r\nexport class InitializationError extends VaultError {\r\n constructor(message: string, cause?: unknown) {\r\n super(message, 'VAULT_INIT_ERROR', cause);\r\n this.name = 'InitializationError';\r\n }\r\n}\r\n\r\nexport class AuthenticationError extends VaultError {\r\n constructor(message = 'Invalid password or corrupted vault') {\r\n super(message, 'AUTH_FAILED');\r\n this.name = 'AuthenticationError';\r\n }\r\n}\r\n\r\nexport class NotAuthenticatedError extends VaultError {\r\n constructor() {\r\n super('Vault is locked. Unlock it first.', 'VAULT_LOCKED');\r\n this.name = 'NotAuthenticatedError';\r\n }\r\n}\r\n\r\nexport class StorageError extends VaultError {\r\n constructor(message: string, cause?: unknown) {\r\n super(message, 'STORAGE_ERROR', cause);\r\n this.name = 'StorageError';\r\n }\r\n}\r\n\r\nexport class CryptoError extends VaultError {\r\n constructor(message: string, cause?: unknown) {\r\n super(message, 'CRYPTO_ERROR', cause);\r\n this.name = 'CryptoError';\r\n }\r\n}","/**\r\n * @fileoverview WASM Crypto Adapter for P47H Vault\r\n * \r\n * This module provides the bridge between TypeScript and the Rust/WASM\r\n * cryptographic core. It handles module loading, initialization, and\r\n * provides type-safe wrappers for all WASM operations.\r\n * \r\n * @module adapters/WasmCryptoAdapter\r\n * @license AGPL-3.0 OR Commercial\r\n */\r\n\r\nimport { InitializationError, CryptoError } from '../domain/errors';\r\n\r\n// ============================================================================\r\n// WASM Module Interface Types\r\n// ============================================================================\r\n\r\n/**\r\n * Internal interface for the WASM module exports.\r\n * @internal\r\n */\r\ninterface P47hWasmModule {\r\n readonly P47hClient: {\r\n new(): P47hClientInstance;\r\n from_wrapped_secret(wrapped: Uint8Array, sessionKey: Uint8Array): P47hClientInstance;\r\n };\r\n readonly VaultCrypto: {\r\n encrypt_vault(data: Uint8Array, password: string): Uint8Array;\r\n decrypt_vault(blob: Uint8Array, password: string): Uint8Array;\r\n derive_session_key(password: string, salt: Uint8Array): Uint8Array;\r\n };\r\n init?: (options?: unknown) => Promise<void> | void;\r\n default: (input?: RequestInfo | URL | { module_or_path: RequestInfo | URL | string }) => Promise<void>;\r\n \r\n // License verification functions (Commercial builds only)\r\n init_session?: (licenseKey: string | null) => boolean;\r\n is_commercial_license?: () => boolean;\r\n get_licensee?: () => string | null;\r\n}\r\n\r\n/**\r\n * Instance of a P47H cryptographic identity client.\r\n * Wraps an Ed25519 keypair in WASM memory.\r\n */\r\nexport interface P47hClientInstance {\r\n /** Returns the Decentralized Identifier (DID) for this identity */\r\n get_did(): string;\r\n /** Returns the raw Ed25519 public key bytes (32 bytes) */\r\n get_public_key(): Uint8Array;\r\n /** Exports the private key encrypted with session key */\r\n export_wrapped_secret(sessionKey: Uint8Array): Uint8Array;\r\n /** Signs arbitrary data with the private key */\r\n sign_data(data: Uint8Array): Uint8Array;\r\n /** Frees the WASM memory associated with this client */\r\n free(): void;\r\n}\r\n\r\n/**\r\n * License verification status returned after WASM initialization.\r\n */\r\nexport interface LicenseStatus {\r\n /** True if a valid commercial license was verified */\r\n readonly isCommercial: boolean;\r\n /** The licensed entity name, or null if AGPLv3 mode */\r\n readonly licensee: string | null;\r\n}\r\n\r\n// ============================================================================\r\n// WasmCryptoAdapter Class\r\n// ============================================================================\r\n\r\n/**\r\n * Adapter for P47H WASM cryptographic operations.\r\n * \r\n * This class handles:\r\n * - Loading the WASM module (with bundler and fetch fallbacks)\r\n * - License verification during initialization\r\n * - Key derivation using Argon2id\r\n * - Vault encryption/decryption using XChaCha20-Poly1305\r\n * - Identity creation and restoration using Ed25519\r\n * \r\n * @example\r\n * ```typescript\r\n * const adapter = new WasmCryptoAdapter('/wasm/p47h_wasm_core_bg.wasm');\r\n * const licenseStatus = await adapter.init('YOUR_LICENSE_KEY');\r\n * \r\n * if (licenseStatus.isCommercial) {\r\n * console.log(`Licensed to: ${licenseStatus.licensee}`);\r\n * }\r\n * ```\r\n */\r\nexport class WasmCryptoAdapter {\r\n private module: P47hWasmModule | null = null;\r\n private _licenseStatus: LicenseStatus = { isCommercial: false, licensee: null };\r\n private readonly _wasmPath: string;\r\n private _isInitialized = false;\r\n\r\n /**\r\n * Creates a new WasmCryptoAdapter instance.\r\n * \r\n * @param wasmPath - Path to the WASM binary file\r\n * @default '/wasm/p47h_wasm_core_bg.wasm'\r\n */\r\n constructor(wasmPath: string = '/wasm/p47h_wasm_core_bg.wasm') {\r\n this._wasmPath = wasmPath;\r\n }\r\n\r\n // ============================================================================\r\n // Initialization\r\n // ============================================================================\r\n\r\n /**\r\n * Initializes the WASM module with optional commercial license key.\r\n * \r\n * This method must be called before any other operations. It:\r\n * 1. Loads the WASM module (via bundler import or fetch fallback)\r\n * 2. Initializes the WASM instance with the binary\r\n * 3. Verifies the license key if provided\r\n * \r\n * @param licenseKey - Optional commercial license token (format: PAYLOAD_B64.SIGNATURE_B64)\r\n * @returns Promise resolving to the license status\r\n * @throws {InitializationError} If WASM loading fails\r\n * \r\n * @example\r\n * ```typescript\r\n * // AGPLv3 mode (no license)\r\n * await adapter.init();\r\n * \r\n * // Commercial mode\r\n * await adapter.init('eyJzdWI...signature');\r\n * ```\r\n */\r\n async init(licenseKey?: string): Promise<LicenseStatus> {\r\n // Idempotent: return cached status if already initialized\r\n if (this._isInitialized && this.module) {\r\n return this._licenseStatus;\r\n }\r\n\r\n try {\r\n const wasmModule = await this.loadWasmModule();\r\n await this.initializeWasmInstance(wasmModule);\r\n this.initializeLicenseSession(wasmModule, licenseKey);\r\n \r\n this.module = wasmModule;\r\n this._isInitialized = true;\r\n \r\n return this._licenseStatus;\r\n } catch (error) {\r\n throw new InitializationError('Failed to load P47H WASM core', error);\r\n }\r\n }\r\n\r\n /**\r\n * Loads the WASM JavaScript glue module.\r\n * Uses fetch to load from public path - does not use static imports.\r\n */\r\n private async loadWasmModule(): Promise<P47hWasmModule> {\r\n // Always use fetch to load from public path\r\n // This avoids bundler issues when SDK is consumed as external dependency\r\n const response = await fetch('/wasm/p47h_wasm_core.js');\r\n if (!response.ok) {\r\n throw new Error(\r\n `Failed to load WASM module: HTTP ${response.status}. ` +\r\n 'Ensure p47h_wasm_core.js is available at /wasm/p47h_wasm_core.js'\r\n );\r\n }\r\n \r\n const code = await response.text();\r\n const blob = new Blob([code], { type: 'application/javascript' });\r\n const url = URL.createObjectURL(blob);\r\n \r\n try {\r\n // Dynamic import using blob URL - no static path analysis\r\n const module = await import(/* @vite-ignore */ url);\r\n return module;\r\n } finally {\r\n URL.revokeObjectURL(url);\r\n }\r\n }\r\n\r\n /**\r\n * Initializes the WASM instance with the binary module.\r\n */\r\n private async initializeWasmInstance(wasmModule: P47hWasmModule): Promise<void> {\r\n // Try new wasm-bindgen format first, then legacy\r\n try {\r\n await wasmModule.default({ module_or_path: this._wasmPath });\r\n } catch {\r\n await wasmModule.default(this._wasmPath);\r\n }\r\n \r\n // Call optional init function (sets panic hook, etc.)\r\n if (typeof wasmModule.init === 'function') {\r\n wasmModule.init();\r\n }\r\n }\r\n\r\n /**\r\n * Initializes the license session in the WASM module.\r\n * Gracefully handles modules without license support (backwards compatibility).\r\n */\r\n private initializeLicenseSession(wasmModule: P47hWasmModule, licenseKey?: string): void {\r\n // Check if this WASM build has licensing support\r\n if (typeof wasmModule.init_session !== 'function') {\r\n // Legacy WASM without licensing - assume AGPLv3 mode\r\n this._licenseStatus = { isCommercial: false, licensee: null };\r\n return;\r\n }\r\n\r\n const isCommercial = wasmModule.init_session(licenseKey || null);\r\n \r\n let licensee: string | null = null;\r\n if (isCommercial && typeof wasmModule.get_licensee === 'function') {\r\n licensee = wasmModule.get_licensee() ?? null;\r\n }\r\n \r\n this._licenseStatus = Object.freeze({ isCommercial, licensee });\r\n }\r\n\r\n /**\r\n * Gets the loaded WASM module, throwing if not initialized.\r\n * @internal\r\n */\r\n private getModule(): P47hWasmModule {\r\n if (!this.module || !this._isInitialized) {\r\n throw new InitializationError(\r\n 'WasmCryptoAdapter not initialized. Call init() first.'\r\n );\r\n }\r\n return this.module;\r\n }\r\n\r\n // ============================================================================\r\n // Vault Operations (VaultCrypto)\r\n // ============================================================================\r\n\r\n /**\r\n * Derives a session key from a password using Argon2id.\r\n * \r\n * @param password - User password\r\n * @param salt - Random salt (16 bytes recommended)\r\n * @returns 32-byte session key\r\n * @throws {CryptoError} If key derivation fails\r\n */\r\n deriveSessionKey(password: string, salt: Uint8Array): Uint8Array {\r\n try {\r\n return this.getModule().VaultCrypto.derive_session_key(password, salt);\r\n } catch (e) {\r\n throw new CryptoError('Failed to derive session key', e);\r\n }\r\n }\r\n\r\n /**\r\n * Encrypts vault data using XChaCha20-Poly1305.\r\n * \r\n * @param data - Plaintext data to encrypt\r\n * @param password - Password for key derivation\r\n * @returns Encrypted blob (includes salt, nonce, ciphertext, tag)\r\n * @throws {CryptoError} If encryption fails\r\n */\r\n encryptVault(data: Uint8Array, password: string): Uint8Array {\r\n try {\r\n return this.getModule().VaultCrypto.encrypt_vault(data, password);\r\n } catch (e) {\r\n throw new CryptoError('Vault encryption failed', e);\r\n }\r\n }\r\n\r\n /**\r\n * Decrypts vault data using XChaCha20-Poly1305.\r\n * \r\n * @param encryptedData - Encrypted blob from encryptVault\r\n * @param password - Password used during encryption\r\n * @returns Decrypted plaintext data\r\n * @throws {CryptoError} If decryption fails (wrong password or corrupted data)\r\n */\r\n decryptVault(encryptedData: Uint8Array, password: string): Uint8Array {\r\n try {\r\n return this.getModule().VaultCrypto.decrypt_vault(encryptedData, password);\r\n } catch (e) {\r\n throw new CryptoError(\r\n 'Vault decryption failed: Invalid password or corrupted data',\r\n e\r\n );\r\n }\r\n }\r\n\r\n // ============================================================================\r\n // Identity Operations (P47hClient)\r\n // ============================================================================\r\n\r\n /**\r\n * Creates a new cryptographic identity (Ed25519 keypair).\r\n * \r\n * @returns New P47hClientInstance with generated keypair\r\n * @throws {CryptoError} If identity generation fails\r\n */\r\n createIdentity(): P47hClientInstance {\r\n try {\r\n const wasm = this.getModule();\r\n return new wasm.P47hClient();\r\n } catch (e) {\r\n throw new CryptoError('Failed to generate new identity', e);\r\n }\r\n }\r\n\r\n /**\r\n * Restores an identity from encrypted secret bytes.\r\n * \r\n * @param wrappedSecret - Encrypted private key from export_wrapped_secret\r\n * @param sessionKey - Session key used during encryption\r\n * @returns Restored P47hClientInstance\r\n * @throws {CryptoError} If restoration fails\r\n */\r\n restoreIdentity(wrappedSecret: Uint8Array, sessionKey: Uint8Array): P47hClientInstance {\r\n try {\r\n return this.getModule().P47hClient.from_wrapped_secret(wrappedSecret, sessionKey);\r\n } catch (e) {\r\n throw new CryptoError('Failed to restore identity from wrapped secret', e);\r\n }\r\n }\r\n\r\n // ============================================================================\r\n // Utilities\r\n // ============================================================================\r\n\r\n /**\r\n * Generates cryptographically secure random bytes.\r\n * \r\n * @param length - Number of random bytes to generate\r\n * @returns Uint8Array with random bytes\r\n */\r\n getRandomValues(length: number): Uint8Array {\r\n return crypto.getRandomValues(new Uint8Array(length));\r\n }\r\n\r\n /**\r\n * Returns the current license status.\r\n * @returns Immutable LicenseStatus object\r\n */\r\n getLicenseStatus(): LicenseStatus {\r\n return this._licenseStatus;\r\n }\r\n\r\n /**\r\n * Checks if running with a valid commercial license.\r\n * @returns True if commercial license is active\r\n */\r\n isCommercial(): boolean {\r\n return this._licenseStatus.isCommercial;\r\n }\r\n\r\n /**\r\n * Checks if the adapter has been initialized.\r\n * @returns True if init() has been called successfully\r\n */\r\n isInitialized(): boolean {\r\n return this._isInitialized;\r\n }\r\n}","import type { IStorage } from '../domain/IStorage';\r\nimport type { EncryptedVaultBlob } from '../domain/types';\r\nimport { StorageError } from '../domain/errors';\r\n\r\nexport class BrowserStorage implements IStorage {\r\n private readonly dbName = 'p47h-vault';\r\n private readonly storeName = 'keystores';\r\n private readonly version = 2;\r\n\r\n /**\r\n * Promisify IndexedDB request helper\r\n */\r\n private request<T>(req: IDBRequest<T>): Promise<T> {\r\n return new Promise((resolve, reject) => {\r\n req.onsuccess = () => resolve(req.result);\r\n req.onerror = () => reject(req.error);\r\n });\r\n }\r\n\r\n /**\r\n * Open database connection with migration logic\r\n */\r\n private async getDB(): Promise<IDBDatabase> {\r\n return new Promise((resolve, reject) => {\r\n // Check for support\r\n if (typeof indexedDB === 'undefined') {\r\n return reject(new StorageError('IndexedDB not supported in this environment'));\r\n }\r\n\r\n const req = indexedDB.open(this.dbName, this.version);\r\n\r\n req.onerror = () => reject(new StorageError('Failed to open database', req.error));\r\n\r\n req.onsuccess = () => resolve(req.result);\r\n\r\n req.onupgradeneeded = (event) => {\r\n const db = req.result;\r\n // Migration logic: Clear old stores if version changed radically or init\r\n if (event.oldVersion < 2) {\r\n if (db.objectStoreNames.contains(this.storeName)) {\r\n db.deleteObjectStore(this.storeName);\r\n }\r\n // Create store with 'did' as primary key\r\n db.createObjectStore(this.storeName, { keyPath: 'did' });\r\n }\r\n };\r\n });\r\n }\r\n\r\n /**\r\n * Execute a transaction\r\n */\r\n private async withStore<T>(\r\n mode: IDBTransactionMode,\r\n callback: (store: IDBObjectStore) => IDBRequest<T> | void\r\n ): Promise<T> {\r\n try {\r\n const db = await this.getDB();\r\n const tx = db.transaction(this.storeName, mode);\r\n const store = tx.objectStore(this.storeName);\r\n \r\n const req = callback(store);\r\n \r\n // Wait for transaction to complete\r\n return new Promise((resolve, reject) => {\r\n tx.oncomplete = () => {\r\n // If request returned a result, use it\r\n if (req instanceof IDBRequest) {\r\n resolve(req.result);\r\n } else {\r\n resolve(undefined as unknown as T);\r\n }\r\n };\r\n tx.onerror = () => reject(new StorageError('Transaction failed', tx.error));\r\n // Fallback for request errors that bubble up\r\n if (req instanceof IDBRequest) {\r\n req.onerror = () => reject(new StorageError('Request failed', req.error));\r\n }\r\n });\r\n } catch (error) {\r\n if (error instanceof StorageError) throw error;\r\n throw new StorageError('Database operation failed', error);\r\n }\r\n }\r\n\r\n // --- IStorage Implementation ---\r\n\r\n async save(key: string, data: EncryptedVaultBlob): Promise<void> {\r\n if (data.did !== key) {\r\n throw new StorageError(`Integrity check: Key ${key} does not match DID ${data.did}`);\r\n }\r\n await this.withStore('readwrite', (store) => store.put(data));\r\n }\r\n\r\n async get(key: string): Promise<EncryptedVaultBlob | null> {\r\n const result = await this.withStore<EncryptedVaultBlob>('readonly', (store) => store.get(key));\r\n return result || null;\r\n }\r\n\r\n async remove(key: string): Promise<void> {\r\n await this.withStore('readwrite', (store) => store.delete(key));\r\n }\r\n\r\n async listKeys(): Promise<string[]> {\r\n return this.withStore<string[]>('readonly', (store) => store.getAllKeys() as IDBRequest<string[]>);\r\n }\r\n\r\n async clear(): Promise<void> {\r\n await this.withStore('readwrite', (store) => store.clear());\r\n }\r\n}","/**\r\n * @fileoverview P47H Vault Service - Core Identity and Secret Management\r\n * \r\n * This is the main facade for the P47H Vault SDK. It provides a high-level,\r\n * type-safe API for:\r\n * - Creating and managing cryptographic identities (DIDs)\r\n * - Securely storing and retrieving encrypted secrets\r\n * - Emergency recovery using Recovery Codes (PUK)\r\n * - Session management with automatic memory cleanup\r\n * \r\n * @module logic/VaultService\r\n * @license AGPL-3.0 OR Commercial\r\n */\r\n\r\nimport type { IVault } from '../domain/IVault';\r\nimport type { IStorage } from '../domain/IStorage';\r\nimport type { \r\n VaultConfig, \r\n IdentityInfo, \r\n EncryptedVaultBlob,\r\n RegistrationResult,\r\n RecoveryOptions,\r\n RecoveryResult\r\n} from '../domain/types';\r\nimport { \r\n InitializationError, \r\n NotAuthenticatedError, \r\n AuthenticationError, \r\n VaultError \r\n} from '../domain/errors';\r\nimport { WasmCryptoAdapter, type P47hClientInstance } from '../adapters/WasmCryptoAdapter';\r\nimport { BrowserStorage } from '../adapters/IndexedDbStorage';\r\n\r\n// ============================================================================\r\n// Internal Types\r\n// ============================================================================\r\n\r\n/**\r\n * Internal structure of the encrypted vault JSON payload.\r\n * @internal\r\n */\r\ninterface VaultInternalData {\r\n readonly did: string;\r\n readonly wrappedSecret: string; // Base64 encoded\r\n readonly salt: string; // Base64 encoded\r\n secrets: Record<string, string>; // User secrets map\r\n createdAt: number;\r\n}\r\n\r\n// ============================================================================\r\n// Constants\r\n// ============================================================================\r\n\r\n/** Recovery code format: RK-XXXX-XXXX-XXXX-XXXX (16 bytes = 32 hex chars) */\r\nconst RECOVERY_CODE_PREFIX = 'RK';\r\nconst RECOVERY_CODE_BYTES = 16;\r\n\r\n// ============================================================================\r\n// VaultService Class\r\n// ============================================================================\r\n\r\n/**\r\n * P47H Vault Service - Secure local-first identity and secret management.\r\n * \r\n * This service provides:\r\n * - **Identity Management**: Create and restore Ed25519 cryptographic identities\r\n * - **Secret Storage**: Encrypt and persist arbitrary secrets locally\r\n * - **Emergency Recovery**: Recover access using Recovery Codes (like 1Password)\r\n * - **Memory Safety**: Automatic cleanup of sensitive data from RAM\r\n * - **Commercial Licensing**: Optional license key for proprietary use\r\n * \r\n * ## Security Model\r\n * \r\n * - All cryptographic operations are performed in WASM (Rust)\r\n * - Private keys never leave WASM memory as plaintext\r\n * - Session keys are derived using Argon2id (OWASP recommended)\r\n * - Data is encrypted using XChaCha20-Poly1305 (AEAD)\r\n * - Dual encryption: password + recovery code for emergency access\r\n * \r\n * @example\r\n * ```typescript\r\n * import { P47hVault } from '@p47h/vault-js';\r\n * \r\n * const vault = new P47hVault();\r\n * await vault.init({ wasmPath: '/wasm/p47h_wasm_core_bg.wasm' });\r\n * \r\n * // Create new identity - SAVE THE RECOVERY CODE!\r\n * const { did, recoveryCode } = await vault.register('my-secure-password');\r\n * console.log('Created:', did);\r\n * console.log('⚠️ Save this recovery code:', recoveryCode);\r\n * \r\n * // If password is forgotten:\r\n * await vault.recoverAccount({\r\n * recoveryCode: 'RK-A1B2C3D4...',\r\n * newPassword: 'new-secure-password'\r\n * });\r\n * ```\r\n * \r\n * @implements {IVault}\r\n */\r\nexport class VaultService implements IVault {\r\n // ============================================================================\r\n // Private State\r\n // ============================================================================\r\n\r\n private readonly _storage: IStorage;\r\n private _crypto: WasmCryptoAdapter;\r\n private _client: P47hClientInstance | null = null;\r\n private _sessionKey: Uint8Array | null = null;\r\n private _currentDid: string | null = null;\r\n private _secretsCache: Record<string, string> | null = null;\r\n private _passwordCache: string | null = null;\r\n private _isInitialized = false;\r\n private _isDisposed = false;\r\n\r\n // ============================================================================\r\n // Constructor\r\n // ============================================================================\r\n\r\n /**\r\n * Creates a new VaultService instance with default adapters.\r\n * \r\n * @param storage - Optional custom storage adapter (defaults to IndexedDB)\r\n */\r\n constructor(storage?: IStorage) {\r\n this._crypto = new WasmCryptoAdapter();\r\n this._storage = storage ?? new BrowserStorage();\r\n }\r\n\r\n // ============================================================================\r\n // Initialization\r\n // ============================================================================\r\n\r\n /**\r\n * Initializes the vault with WASM module and optional configuration.\r\n * \r\n * This method must be called before any other operations. It:\r\n * 1. Loads the WASM cryptographic core\r\n * 2. Verifies the commercial license (if provided)\r\n * 3. Prepares the storage adapter\r\n * \r\n * @param config - Optional configuration object\r\n * @returns Promise that resolves when initialization is complete\r\n * @throws {InitializationError} If WASM loading fails\r\n */\r\n async init(config?: VaultConfig): Promise<void> {\r\n this.ensureNotDisposed();\r\n \r\n if (this._isInitialized) {\r\n return; // Idempotent\r\n }\r\n\r\n // Apply custom WASM path if provided\r\n if (config?.wasmPath) {\r\n this._crypto = new WasmCryptoAdapter(config.wasmPath);\r\n }\r\n\r\n // Initialize WASM with optional license\r\n await this._crypto.init(config?.licenseKey);\r\n this._isInitialized = true;\r\n }\r\n\r\n // ============================================================================\r\n // License Status\r\n // ============================================================================\r\n\r\n /**\r\n * Checks if the vault is running with a valid commercial license.\r\n * \r\n * @returns True if commercial license is active, false if AGPLv3 mode\r\n */\r\n isCommercialLicense(): boolean {\r\n return this._crypto.isCommercial();\r\n }\r\n\r\n /**\r\n * Gets the name of the licensed entity.\r\n * \r\n * @returns The licensee name, or null if running in AGPLv3 mode\r\n */\r\n getLicensee(): string | null {\r\n return this._crypto.getLicenseStatus().licensee;\r\n }\r\n\r\n // ============================================================================\r\n // Identity Management\r\n // ============================================================================\r\n\r\n /**\r\n * Creates a new cryptographic identity and persists it encrypted.\r\n * \r\n * This method:\r\n * 1. Generates a new Ed25519 keypair in WASM\r\n * 2. Derives a session key from the password using Argon2id\r\n * 3. Generates a high-entropy Recovery Code\r\n * 4. Encrypts the vault twice: once with password, once with recovery code\r\n * 5. Persists both encrypted copies to storage\r\n * 6. Establishes an authenticated session\r\n * \r\n * **CRITICAL**: The returned `recoveryCode` is the ONLY way to recover\r\n * the vault if the password is lost. It must be stored securely by the user\r\n * (e.g., printed and stored in a safe, password manager, etc.).\r\n * \r\n * @param password - Master password for key derivation (min 8 chars recommended)\r\n * @returns Promise resolving to the DID and recovery code\r\n * @throws {InitializationError} If vault not initialized\r\n * @throws {CryptoError} If key generation fails\r\n * @throws {StorageError} If persistence fails\r\n * \r\n * @example\r\n * ```typescript\r\n * const { did, recoveryCode } = await vault.register('my-secure-password');\r\n * console.log('New identity:', did);\r\n * console.log('⚠️ SAVE THIS CODE:', recoveryCode);\r\n * // recoveryCode format: RK-A1B2C3D4-E5F6G7H8-I9J0K1L2-M3N4O5P6\r\n * ```\r\n */\r\n async register(password: string): Promise<RegistrationResult> {\r\n this.ensureInitialized();\r\n\r\n // 1. Generate identity in WASM\r\n const client = this._crypto.createIdentity();\r\n const did = client.get_did();\r\n\r\n // 2. Generate session key for password encryption\r\n const salt = this._crypto.getRandomValues(16);\r\n const sessionKey = this._crypto.deriveSessionKey(password, salt);\r\n\r\n // 3. Export wrapped (encrypted) private key\r\n const wrappedSecret = client.export_wrapped_secret(sessionKey);\r\n\r\n // 4. Prepare internal vault data\r\n const internalData: VaultInternalData = {\r\n did,\r\n wrappedSecret: this.toBase64(wrappedSecret),\r\n salt: this.toBase64(salt),\r\n secrets: {},\r\n createdAt: Date.now(),\r\n };\r\n\r\n // 5. Serialize internal data\r\n const internalJson = JSON.stringify(internalData);\r\n const internalBytes = new TextEncoder().encode(internalJson);\r\n\r\n // 6. ENCRYPT WITH PASSWORD (primary access)\r\n const encryptedMain = this._crypto.encryptVault(internalBytes, password);\r\n\r\n // 7. GENERATE RECOVERY CODE (Emergency Kit)\r\n const recoveryCode = this.generateRecoveryCode();\r\n\r\n // 8. ENCRYPT WITH RECOVERY CODE (backup access)\r\n const encryptedRecovery = this._crypto.encryptVault(internalBytes, recoveryCode);\r\n\r\n // 9. Persist to storage with BOTH encrypted copies\r\n const storageBlob: EncryptedVaultBlob = {\r\n version: 1,\r\n did,\r\n salt: this.toBase64(salt),\r\n wrappedData: this.toBase64(encryptedMain),\r\n recoveryBlob: this.toBase64(encryptedRecovery),\r\n updatedAt: Date.now()\r\n };\r\n\r\n await this._storage.save(did, storageBlob);\r\n\r\n // 10. Establish session\r\n this.setSession(client, sessionKey, did, password, {});\r\n\r\n return { did, recoveryCode };\r\n }\r\n\r\n /**\r\n * Unlocks an existing identity with the master password.\r\n * \r\n * This method:\r\n * 1. Retrieves the encrypted identity from storage\r\n * 2. Decrypts and validates the vault data\r\n * 3. Restores the Ed25519 keypair in WASM\r\n * 4. Establishes an authenticated session\r\n * \r\n * @param password - Master password used during registration\r\n * @param did - Optional specific DID to unlock (uses first found if omitted)\r\n * @returns Promise resolving to the identity info\r\n * @throws {InitializationError} If vault not initialized\r\n * @throws {AuthenticationError} If password is wrong or identity not found\r\n * @throws {VaultError} If vault data is corrupted\r\n * \r\n * @example\r\n * ```typescript\r\n * try {\r\n * const identity = await vault.login('my-password');\r\n * console.log('Unlocked:', identity.did);\r\n * } catch (e) {\r\n * if (e instanceof AuthenticationError) {\r\n * console.error('Wrong password - use recovery code?');\r\n * }\r\n * }\r\n * ```\r\n */\r\n async login(password: string, did?: string): Promise<IdentityInfo> {\r\n this.ensureInitialized();\r\n\r\n // 1. Resolve target DID\r\n let targetDid = did;\r\n if (!targetDid) {\r\n const keys = await this._storage.listKeys();\r\n if (keys.length === 0) {\r\n throw new AuthenticationError('No identities found in storage');\r\n }\r\n targetDid = keys[0];\r\n }\r\n\r\n // 2. Retrieve encrypted blob\r\n const storedBlob = await this._storage.get(targetDid);\r\n if (!storedBlob) {\r\n throw new AuthenticationError(`Identity ${targetDid} not found`);\r\n }\r\n\r\n // 3. Decrypt outer blob\r\n let decryptedBytes: Uint8Array;\r\n try {\r\n decryptedBytes = this._crypto.decryptVault(\r\n this.fromBase64(storedBlob.wrappedData),\r\n password\r\n );\r\n } catch {\r\n throw new AuthenticationError('Invalid password or corrupted vault');\r\n }\r\n\r\n // 4. Parse internal data\r\n let internalData: VaultInternalData;\r\n try {\r\n const json = new TextDecoder().decode(decryptedBytes);\r\n internalData = JSON.parse(json);\r\n } catch {\r\n throw new VaultError('Vault data corruption: Invalid JSON', 'CORRUPT_DATA');\r\n }\r\n\r\n // 5. Integrity check\r\n if (internalData.did !== targetDid) {\r\n throw new VaultError('Integrity error: DID mismatch inside vault', 'INTEGRITY_ERROR');\r\n }\r\n\r\n // 6. Restore WASM client\r\n const salt = this.fromBase64(internalData.salt);\r\n const sessionKey = this._crypto.deriveSessionKey(password, salt);\r\n const wrappedSecret = this.fromBase64(internalData.wrappedSecret);\r\n\r\n const client = this._crypto.restoreIdentity(wrappedSecret, sessionKey);\r\n\r\n // 7. Establish session\r\n this.setSession(client, sessionKey, targetDid, password, internalData.secrets);\r\n\r\n return {\r\n did: targetDid,\r\n publicKey: client.get_public_key()\r\n };\r\n }\r\n\r\n /**\r\n * Recovers account access using the emergency recovery code.\r\n * \r\n * Use this when the user has forgotten their password but has their\r\n * Recovery Code (Emergency Kit). This will:\r\n * 1. Decrypt the vault using the recovery code\r\n * 2. Re-encrypt with the new password\r\n * 3. Optionally generate a new recovery code (recommended)\r\n * 4. Auto-login with the new credentials\r\n * \r\n * @param options - Recovery options including recovery code and new password\r\n * @returns Recovery result with optional new recovery code\r\n * @throws {AuthenticationError} If recovery code is invalid\r\n * @throws {VaultError} If recovery is not available for this identity\r\n * \r\n * @example\r\n * ```typescript\r\n * // Basic recovery\r\n * const result = await vault.recoverAccount({\r\n * recoveryCode: 'RK-A1B2C3D4-E5F6G7H8-I9J0K1L2-M3N4O5P6',\r\n * newPassword: 'my-new-secure-password'\r\n * });\r\n * \r\n * // Recovery with code rotation (recommended)\r\n * const result = await vault.recoverAccount({\r\n * recoveryCode: 'RK-A1B2C3D4-...',\r\n * newPassword: 'my-new-secure-password',\r\n * rotateRecoveryCode: true\r\n * });\r\n * console.log('⚠️ NEW recovery code:', result.newRecoveryCode);\r\n * ```\r\n */\r\n async recoverAccount(options: RecoveryOptions): Promise<RecoveryResult> {\r\n this.ensureInitialized();\r\n\r\n const { recoveryCode, newPassword, did, rotateRecoveryCode = false } = options;\r\n\r\n // 1. Resolve target DID\r\n let targetDid = did;\r\n if (!targetDid) {\r\n const keys = await this._storage.listKeys();\r\n if (keys.length === 0) {\r\n throw new AuthenticationError('No vaults found');\r\n }\r\n targetDid = keys[0];\r\n }\r\n\r\n // 2. Get stored blob\r\n const stored = await this._storage.get(targetDid);\r\n if (!stored) {\r\n throw new AuthenticationError(`Identity ${targetDid} not found`);\r\n }\r\n \r\n if (!stored.recoveryBlob) {\r\n throw new VaultError(\r\n 'Recovery not available for this identity. It may have been created with an older SDK version.',\r\n 'RECOVERY_UNAVAILABLE'\r\n );\r\n }\r\n\r\n // 3. Decrypt using recovery code\r\n let decryptedBytes: Uint8Array;\r\n try {\r\n decryptedBytes = this._crypto.decryptVault(\r\n this.fromBase64(stored.recoveryBlob),\r\n recoveryCode\r\n );\r\n } catch {\r\n throw new AuthenticationError('Invalid Recovery Code');\r\n }\r\n\r\n // 4. Parse internal data\r\n let internalData: VaultInternalData;\r\n try {\r\n const json = new TextDecoder().decode(decryptedBytes);\r\n internalData = JSON.parse(json);\r\n } catch {\r\n throw new VaultError('Vault data corruption during recovery', 'CORRUPT_DATA');\r\n }\r\n\r\n // 5. Re-encrypt with new password\r\n const newEncryptedMain = this._crypto.encryptVault(decryptedBytes, newPassword);\r\n\r\n // 6. Handle recovery code rotation\r\n let newRecoveryCode: string | undefined;\r\n let newRecoveryBlob: string;\r\n\r\n if (rotateRecoveryCode) {\r\n // Generate new recovery code\r\n newRecoveryCode = this.generateRecoveryCode();\r\n const newEncryptedRecovery = this._crypto.encryptVault(decryptedBytes, newRecoveryCode);\r\n newRecoveryBlob = this.toBase64(newEncryptedRecovery);\r\n } else {\r\n // Keep existing recovery blob\r\n newRecoveryBlob = stored.recoveryBlob;\r\n }\r\n\r\n // 7. Update storage\r\n stored.wrappedData = this.toBase64(newEncryptedMain);\r\n stored.recoveryBlob = newRecoveryBlob;\r\n stored.updatedAt = Date.now();\r\n\r\n await this._storage.save(targetDid, stored);\r\n\r\n // 8. Auto-login with new password\r\n await this.login(newPassword, targetDid);\r\n\r\n return {\r\n did: targetDid,\r\n newRecoveryCode\r\n };\r\n }\r\n\r\n /**\r\n * Locks the vault and clears all sensitive data from memory.\r\n * \r\n * This method:\r\n * 1. Frees WASM memory holding the private key\r\n * 2. Clears the session key from JavaScript heap\r\n * 3. Clears the password cache\r\n * 4. Clears the secrets cache\r\n * \r\n * Always call this when the user logs out or the app is backgrounded.\r\n */\r\n lock(): void {\r\n if (this._client) {\r\n try {\r\n this._client.free();\r\n } catch {\r\n // Ignore free errors (already freed)\r\n }\r\n this._client = null;\r\n }\r\n \r\n // Clear sensitive data\r\n this._sessionKey = null;\r\n this._currentDid = null;\r\n this._secretsCache = null;\r\n this._passwordCache = null;\r\n }\r\n\r\n /**\r\n * Checks if the vault is currently unlocked with an active session.\r\n * \r\n * @returns True if an identity is loaded and session is active\r\n */\r\n isAuthenticated(): boolean {\r\n return this._client !== null && !this._isDisposed;\r\n }\r\n\r\n /**\r\n * Gets the DID of the currently authenticated identity.\r\n * \r\n * @returns The current Decentralized Identifier\r\n * @throws {NotAuthenticatedError} If vault is locked\r\n */\r\n getDid(): string {\r\n this.ensureAuthenticated();\r\n return this._currentDid!;\r\n }\r\n\r\n /**\r\n * Returns a list of DIDs (identities) that exist in local storage.\r\n * Useful for UI to decide whether to show Login or Register.\r\n * \r\n * @returns Promise resolving to array of DID strings\r\n * @throws {InitializationError} If vault not initialized\r\n */\r\n async getStoredIdentities(): Promise<string[]> {\r\n this.ensureInitialized();\r\n return this._storage.listKeys();\r\n }\r\n\r\n // ============================================================================\r\n // Cryptographic Operations\r\n // ============================================================================\r\n\r\n /**\r\n * Signs arbitrary data with the current identity's private key.\r\n * \r\n * Uses Ed25519 signatures. The private key never leaves WASM memory.\r\n * \r\n * @param data - Data to sign\r\n * @returns Promise resolving to the 64-byte Ed25519 signature\r\n * @throws {NotAuthenticatedError} If vault is locked\r\n */\r\n async sign(data: Uint8Array): Promise<Uint8Array> {\r\n this.ensureAuthenticated();\r\n return this._client!.sign_data(data);\r\n }\r\n\r\n // ============================================================================\r\n // Secret Management\r\n // ============================================================================\r\n\r\n /**\r\n * Saves an encrypted secret to the vault.\r\n * \r\n * The secret is:\r\n * 1. Stored in the in-memory cache\r\n * 2. Re-encrypted with the vault's master key\r\n * 3. Persisted to storage (both password and recovery copies)\r\n * \r\n * @param key - Unique identifier for the secret\r\n * @param secret - The secret value to store\r\n * @throws {NotAuthenticatedError} If vault is locked\r\n * @throws {VaultError} If storage operation fails\r\n */\r\n async saveSecret(key: string, secret: string): Promise<void> {\r\n this.ensureAuthenticated();\r\n\r\n if (!this._secretsCache || !this._passwordCache || !this._currentDid) {\r\n throw new NotAuthenticatedError();\r\n }\r\n\r\n // Update in-memory cache\r\n this._secretsCache[key] = secret;\r\n\r\n // Retrieve and update persisted blob\r\n const stored = await this._storage.get(this._currentDid);\r\n if (!stored) {\r\n throw new VaultError('Storage corruption during save', 'STORAGE_ERROR');\r\n }\r\n \r\n // Decrypt, update, re-encrypt\r\n const decrypted = this._crypto.decryptVault(\r\n this.fromBase64(stored.wrappedData), \r\n this._passwordCache\r\n );\r\n const originalData = JSON.parse(new TextDecoder().decode(decrypted)) as VaultInternalData;\r\n \r\n originalData.secrets = { ...this._secretsCache };\r\n originalData.createdAt = Date.now();\r\n \r\n const updatedBytes = new TextEncoder().encode(JSON.stringify(originalData));\r\n \r\n // Re-encrypt both copies\r\n const newEncryptedMain = this._crypto.encryptVault(updatedBytes, this._passwordCache);\r\n stored.wrappedData = this.toBase64(newEncryptedMain);\r\n \r\n // Also update recovery blob if it exists\r\n if (stored.recoveryBlob) {\r\n // We need the recovery code to re-encrypt, but we don't have it\r\n // Instead, we decrypt with recovery code and re-encrypt\r\n // But we don't store the recovery code...\r\n // \r\n // SOLUTION: The recovery blob contains the same internal data\r\n // When saving secrets, we need to update BOTH blobs\r\n // But we can't re-encrypt the recovery blob without the recovery code!\r\n //\r\n // DESIGN DECISION: Recovery blob is a snapshot at registration time.\r\n // If secrets are added later, they won't be in the recovery blob.\r\n // This is acceptable because:\r\n // 1. Recovery is for IDENTITY, not for secrets\r\n // 2. Secrets can be re-added after recovery\r\n // 3. For enterprise, we can add \"recovery escrow\" that stores codes\r\n //\r\n // Alternative: Store recovery code in memory during session\r\n // But that's a security risk.\r\n //\r\n // For now, we don't update recoveryBlob on secret changes.\r\n }\r\n \r\n stored.updatedAt = Date.now();\r\n await this._storage.save(this._currentDid, stored);\r\n }\r\n\r\n /**\r\n * Retrieves a decrypted secret from the vault.\r\n * \r\n * @param key - The secret identifier\r\n * @returns The decrypted secret value, or null if not found\r\n * @throws {NotAuthenticatedError} If vault is locked\r\n */\r\n async getSecret(key: string): Promise<string | null> {\r\n this.ensureAuthenticated();\r\n return this._secretsCache?.[key] ?? null;\r\n }\r\n\r\n // ============================================================================\r\n // Lifecycle Management\r\n // ============================================================================\r\n\r\n /**\r\n * Disposes of the vault and releases all resources.\r\n * \r\n * After calling dispose():\r\n * - All sensitive data is cleared from memory\r\n * - The vault cannot be used again\r\n * - A new VaultService instance must be created\r\n */\r\n dispose(): void {\r\n if (this._isDisposed) return;\r\n \r\n this.lock();\r\n this._isInitialized = false;\r\n this._isDisposed = true;\r\n }\r\n\r\n // ============================================================================\r\n // Private Helpers\r\n // ============================================================================\r\n\r\n /**\r\n * Generates a high-entropy recovery code.\r\n * Format: RK-XXXXXXXX-XXXXXXXX-XXXXXXXX-XXXXXXXX (32 hex chars)\r\n */\r\n private generateRecoveryCode(): string {\r\n const bytes = this._crypto.getRandomValues(RECOVERY_CODE_BYTES);\r\n const hex = Array.from(bytes)\r\n .map(b => b.toString(16).padStart(2, '0').toUpperCase())\r\n .join('');\r\n \r\n // Format: RK-XXXXXXXX-XXXXXXXX-XXXXXXXX-XXXXXXXX\r\n return `${RECOVERY_CODE_PREFIX}-${hex.slice(0, 8)}-${hex.slice(8, 16)}-${hex.slice(16, 24)}-${hex.slice(24, 32)}`;\r\n }\r\n\r\n private ensureNotDisposed(): void {\r\n if (this._isDisposed) {\r\n throw new VaultError('VaultService has been disposed', 'DISPOSED');\r\n }\r\n }\r\n\r\n private ensureInitialized(): void {\r\n this.ensureNotDisposed();\r\n if (!this._isInitialized) {\r\n throw new InitializationError('VaultService not initialized. Call init() first.');\r\n }\r\n }\r\n\r\n private ensureAuthenticated(): void {\r\n this.ensureInitialized();\r\n if (!this._client) {\r\n throw new NotAuthenticatedError();\r\n }\r\n }\r\n\r\n private setSession(\r\n client: P47hClientInstance, \r\n sessionKey: Uint8Array, \r\n did: string, \r\n password: string,\r\n secrets: Record<string, string>\r\n ): void {\r\n this._client = client;\r\n this._sessionKey = sessionKey;\r\n this._currentDid = did;\r\n this._passwordCache = password;\r\n this._secretsCache = { ...secrets };\r\n }\r\n\r\n private toBase64(bytes: Uint8Array): string {\r\n const binString = Array.from(bytes, (x) => String.fromCharCode(x)).join('');\r\n return btoa(binString);\r\n }\r\n\r\n private fromBase64(base64: string): Uint8Array {\r\n const binString = atob(base64);\r\n return Uint8Array.from(binString, (m) => m.codePointAt(0)!);\r\n }\r\n}"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@p47h/vault-js",
|
|
3
|
+
"version": "0.9.0",
|
|
4
|
+
"description": "Secure, local-first cryptographic storage for browser environments. Argon2id + XChaCha20Poly1305 + Ed25519 backed by WASM.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"security",
|
|
7
|
+
"encryption",
|
|
8
|
+
"wasm",
|
|
9
|
+
"vault",
|
|
10
|
+
"indexeddb",
|
|
11
|
+
"ed25519",
|
|
12
|
+
"argon2",
|
|
13
|
+
"privacy",
|
|
14
|
+
"local-first"
|
|
15
|
+
],
|
|
16
|
+
"author": "P47H Team <support@p47h.com>",
|
|
17
|
+
"license": "AGPL-3.0-or-later",
|
|
18
|
+
"homepage": "https://p47h.com",
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "git+https://github.com/p47h-org/p47h-vault-js.git"
|
|
22
|
+
},
|
|
23
|
+
"type": "module",
|
|
24
|
+
"main": "./dist/index.js",
|
|
25
|
+
"module": "./dist/index.js",
|
|
26
|
+
"types": "./dist/index.d.ts",
|
|
27
|
+
"exports": {
|
|
28
|
+
".": {
|
|
29
|
+
"types": "./dist/index.d.ts",
|
|
30
|
+
"import": "./dist/index.js"
|
|
31
|
+
},
|
|
32
|
+
"./wasm": "./wasm/p47h_wasm_core_bg.wasm"
|
|
33
|
+
},
|
|
34
|
+
"files": [
|
|
35
|
+
"dist",
|
|
36
|
+
"wasm",
|
|
37
|
+
"LICENSE",
|
|
38
|
+
"README.md"
|
|
39
|
+
],
|
|
40
|
+
"scripts": {
|
|
41
|
+
"dev": "tsup --watch",
|
|
42
|
+
"build": "tsup",
|
|
43
|
+
"test": "tsx --test tests/**/*.test.ts",
|
|
44
|
+
"test:watch": "tsx --test --watch tests/**/*.test.ts",
|
|
45
|
+
"typecheck": "tsc --noEmit",
|
|
46
|
+
"lint": "eslint src/",
|
|
47
|
+
"postinstall": "node scripts/postinstall.js",
|
|
48
|
+
"prepublishOnly": "npm run build"
|
|
49
|
+
},
|
|
50
|
+
"dependencies": {},
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"@types/node": "^20.0.0",
|
|
53
|
+
"tsup": "^8.0.0",
|
|
54
|
+
"tsx": "^4.7.0",
|
|
55
|
+
"typescript": "^5.3.0"
|
|
56
|
+
},
|
|
57
|
+
"engines": {
|
|
58
|
+
"node": ">=18.0.0"
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
/* tslint:disable */
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
|
|
4
|
+
export class P47hClient {
|
|
5
|
+
free(): void;
|
|
6
|
+
[Symbol.dispose](): void;
|
|
7
|
+
/**
|
|
8
|
+
* Generates a new cryptographic identity using browser's secure random source
|
|
9
|
+
*/
|
|
10
|
+
constructor();
|
|
11
|
+
/**
|
|
12
|
+
* Reconstructs identity from previously exported secret bytes
|
|
13
|
+
*/
|
|
14
|
+
static from_secret(secret_bytes: Uint8Array): P47hClient;
|
|
15
|
+
/**
|
|
16
|
+
* Exports the private key encrypted with ChaCha20Poly1305
|
|
17
|
+
*
|
|
18
|
+
* # Security
|
|
19
|
+
*
|
|
20
|
+
* This method encrypts the private key using ChaCha20Poly1305 AEAD cipher
|
|
21
|
+
* before exporting it. The caller must provide a 32-byte session key.
|
|
22
|
+
*
|
|
23
|
+
* # Arguments
|
|
24
|
+
*
|
|
25
|
+
* * `session_key` - A 32-byte key derived from user password or other secure source
|
|
26
|
+
*
|
|
27
|
+
* # Returns
|
|
28
|
+
*
|
|
29
|
+
* Returns a byte array containing: [nonce(12 bytes) || ciphertext || tag(16 bytes)]
|
|
30
|
+
*
|
|
31
|
+
* # Example
|
|
32
|
+
*
|
|
33
|
+
* ```javascript
|
|
34
|
+
* // Derive session key from password using PBKDF2 or similar
|
|
35
|
+
* const sessionKey = await deriveKey(password);
|
|
36
|
+
* const wrapped = client.export_wrapped_secret(sessionKey);
|
|
37
|
+
* // Store wrapped securely in IndexedDB
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export_wrapped_secret(session_key: Uint8Array): Uint8Array;
|
|
41
|
+
/**
|
|
42
|
+
* Imports identity from encrypted secret
|
|
43
|
+
*
|
|
44
|
+
* # Arguments
|
|
45
|
+
*
|
|
46
|
+
* * `wrapped` - The encrypted secret from `export_wrapped_secret`
|
|
47
|
+
* * `session_key` - The same 32-byte key used for encryption
|
|
48
|
+
*
|
|
49
|
+
* # Returns
|
|
50
|
+
*
|
|
51
|
+
* Returns a new `P47hClient` instance with the decrypted identity
|
|
52
|
+
*
|
|
53
|
+
* # Example
|
|
54
|
+
*
|
|
55
|
+
* ```javascript
|
|
56
|
+
* const sessionKey = await deriveKey(password);
|
|
57
|
+
* const client = P47hClient.from_wrapped_secret(wrapped, sessionKey);
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
static from_wrapped_secret(wrapped: Uint8Array, session_key: Uint8Array): P47hClient;
|
|
61
|
+
/**
|
|
62
|
+
* Returns the Decentralized Identifier (DID) for this identity
|
|
63
|
+
*/
|
|
64
|
+
get_did(): string;
|
|
65
|
+
/**
|
|
66
|
+
* Returns the raw public key bytes (for advanced use cases)
|
|
67
|
+
*/
|
|
68
|
+
get_public_key(): Uint8Array;
|
|
69
|
+
/**
|
|
70
|
+
* Signs a challenge for authentication with the server
|
|
71
|
+
*/
|
|
72
|
+
sign_challenge(challenge: Uint8Array): Uint8Array;
|
|
73
|
+
/**
|
|
74
|
+
* Signs arbitrary data (for advanced use cases)
|
|
75
|
+
*/
|
|
76
|
+
sign_data(data: Uint8Array): Uint8Array;
|
|
77
|
+
/**
|
|
78
|
+
* Evaluates a policy request locally without server round-trip
|
|
79
|
+
*/
|
|
80
|
+
evaluate_request(policy_toml: string, resource: string, action: string): any;
|
|
81
|
+
/**
|
|
82
|
+
* Batch evaluation of multiple requests (more efficient)
|
|
83
|
+
*/
|
|
84
|
+
evaluate_batch(policy_toml: string, requests_json: string): any;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export class VaultCrypto {
|
|
88
|
+
private constructor();
|
|
89
|
+
free(): void;
|
|
90
|
+
[Symbol.dispose](): void;
|
|
91
|
+
/**
|
|
92
|
+
* Encrypts data using XChaCha20Poly1305 with a key derived from Argon2id
|
|
93
|
+
* Output format: [MAGIC_BYTES (13)] [SALT (16)] [NONCE (24)] [CIPHERTEXT]
|
|
94
|
+
*/
|
|
95
|
+
static encrypt_vault(data: Uint8Array, password: string): Uint8Array;
|
|
96
|
+
/**
|
|
97
|
+
* Decrypts a vault blob
|
|
98
|
+
*/
|
|
99
|
+
static decrypt_vault(blob: Uint8Array, password: string): Uint8Array;
|
|
100
|
+
/**
|
|
101
|
+
* Derives a session key from password and salt
|
|
102
|
+
*/
|
|
103
|
+
static derive_session_key(password: string, salt: Uint8Array): Uint8Array;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export class WasmIdentity {
|
|
107
|
+
free(): void;
|
|
108
|
+
[Symbol.dispose](): void;
|
|
109
|
+
/**
|
|
110
|
+
* Generate a new identity
|
|
111
|
+
*/
|
|
112
|
+
constructor();
|
|
113
|
+
/**
|
|
114
|
+
* Get the public key hash as hex string
|
|
115
|
+
*/
|
|
116
|
+
publicKeyHash(): string;
|
|
117
|
+
/**
|
|
118
|
+
* Get the DID (Decentralized Identifier)
|
|
119
|
+
*/
|
|
120
|
+
getDid(): string;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export class WasmPolicy {
|
|
124
|
+
free(): void;
|
|
125
|
+
[Symbol.dispose](): void;
|
|
126
|
+
/**
|
|
127
|
+
* Create a new policy
|
|
128
|
+
*/
|
|
129
|
+
constructor(name: string, ttl_seconds: bigint);
|
|
130
|
+
/**
|
|
131
|
+
* Add a rule to the policy
|
|
132
|
+
*/
|
|
133
|
+
addRule(peer_id: string, action: string, resource: string): void;
|
|
134
|
+
/**
|
|
135
|
+
* Get number of rules
|
|
136
|
+
*/
|
|
137
|
+
ruleCount(): number;
|
|
138
|
+
/**
|
|
139
|
+
* Get the Merkle root hash of the policy
|
|
140
|
+
*
|
|
141
|
+
* Calculates the hash of the canonical TOML representation of the policy.
|
|
142
|
+
* This serves as the Merkle root for synchronization verification.
|
|
143
|
+
*/
|
|
144
|
+
getRootHash(): string;
|
|
145
|
+
/**
|
|
146
|
+
* Get policy name
|
|
147
|
+
*/
|
|
148
|
+
readonly name: string;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Gets the current licensee name (if commercial license is active).
|
|
153
|
+
*/
|
|
154
|
+
export function get_licensee(): string | undefined;
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Initialize the WASM module (sets panic hook for debugging)
|
|
158
|
+
*/
|
|
159
|
+
export function init(): void;
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Initializes the licensing system with an optional license key.
|
|
163
|
+
*
|
|
164
|
+
* This function should be called during WASM initialization.
|
|
165
|
+
* If a valid license is provided, commercial features are unlocked.
|
|
166
|
+
* If no license or invalid license is provided, nagware mode is activated.
|
|
167
|
+
*
|
|
168
|
+
* # Arguments
|
|
169
|
+
*
|
|
170
|
+
* * `license_key` - Optional license token in format `PAYLOAD_B64.SIGNATURE_B64`
|
|
171
|
+
*
|
|
172
|
+
* # Returns
|
|
173
|
+
*
|
|
174
|
+
* `true` if commercial license is active, `false` if running in AGPLv3 mode.
|
|
175
|
+
*/
|
|
176
|
+
export function init_session(license_key?: string | null): boolean;
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Checks if a commercial license is currently active.
|
|
180
|
+
*/
|
|
181
|
+
export function is_commercial_license(): boolean;
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Validates a policy TOML string
|
|
185
|
+
*
|
|
186
|
+
* Checks if the provided string is a valid P47H policy.
|
|
187
|
+
* Returns Ok(()) if valid, or an error message if invalid.
|
|
188
|
+
*/
|
|
189
|
+
export function validate_policy(policy_toml: string): void;
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Validates a policy TOML string with precise error reporting
|
|
193
|
+
*/
|
|
194
|
+
export function validate_policy_detailed(policy_toml: string): any;
|
|
195
|
+
|
|
196
|
+
export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
|
|
197
|
+
|
|
198
|
+
export interface InitOutput {
|
|
199
|
+
readonly memory: WebAssembly.Memory;
|
|
200
|
+
readonly __wbg_p47hclient_free: (a: number, b: number) => void;
|
|
201
|
+
readonly p47hclient_generate_new: (a: number) => void;
|
|
202
|
+
readonly p47hclient_from_secret: (a: number, b: number, c: number) => void;
|
|
203
|
+
readonly p47hclient_export_wrapped_secret: (a: number, b: number, c: number, d: number) => void;
|
|
204
|
+
readonly p47hclient_from_wrapped_secret: (a: number, b: number, c: number, d: number, e: number) => void;
|
|
205
|
+
readonly p47hclient_get_did: (a: number, b: number) => void;
|
|
206
|
+
readonly p47hclient_get_public_key: (a: number, b: number) => void;
|
|
207
|
+
readonly p47hclient_sign_challenge: (a: number, b: number, c: number, d: number) => void;
|
|
208
|
+
readonly p47hclient_evaluate_request: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number) => void;
|
|
209
|
+
readonly p47hclient_evaluate_batch: (a: number, b: number, c: number, d: number, e: number, f: number) => void;
|
|
210
|
+
readonly init_session: (a: number, b: number) => number;
|
|
211
|
+
readonly is_commercial_license: () => number;
|
|
212
|
+
readonly get_licensee: (a: number) => void;
|
|
213
|
+
readonly validate_policy: (a: number, b: number, c: number) => void;
|
|
214
|
+
readonly validate_policy_detailed: (a: number, b: number, c: number) => void;
|
|
215
|
+
readonly __wbg_vaultcrypto_free: (a: number, b: number) => void;
|
|
216
|
+
readonly vaultcrypto_encrypt_vault: (a: number, b: number, c: number, d: number, e: number) => void;
|
|
217
|
+
readonly vaultcrypto_decrypt_vault: (a: number, b: number, c: number, d: number, e: number) => void;
|
|
218
|
+
readonly vaultcrypto_derive_session_key: (a: number, b: number, c: number, d: number, e: number) => void;
|
|
219
|
+
readonly wasmidentity_new: (a: number) => void;
|
|
220
|
+
readonly wasmidentity_publicKeyHash: (a: number, b: number) => void;
|
|
221
|
+
readonly wasmidentity_getDid: (a: number, b: number) => void;
|
|
222
|
+
readonly __wbg_wasmpolicy_free: (a: number, b: number) => void;
|
|
223
|
+
readonly wasmpolicy_new: (a: number, b: number, c: number, d: bigint) => void;
|
|
224
|
+
readonly wasmpolicy_addRule: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number) => void;
|
|
225
|
+
readonly wasmpolicy_name: (a: number, b: number) => void;
|
|
226
|
+
readonly wasmpolicy_ruleCount: (a: number) => number;
|
|
227
|
+
readonly wasmpolicy_getRootHash: (a: number, b: number) => void;
|
|
228
|
+
readonly init: () => void;
|
|
229
|
+
readonly p47hclient_sign_data: (a: number, b: number, c: number, d: number) => void;
|
|
230
|
+
readonly __wbg_wasmidentity_free: (a: number, b: number) => void;
|
|
231
|
+
readonly __wbindgen_export: (a: number, b: number) => number;
|
|
232
|
+
readonly __wbindgen_export2: (a: number, b: number, c: number, d: number) => number;
|
|
233
|
+
readonly __wbindgen_export3: (a: number) => void;
|
|
234
|
+
readonly __wbindgen_export4: (a: number, b: number, c: number) => void;
|
|
235
|
+
readonly __wbindgen_add_to_stack_pointer: (a: number) => number;
|
|
236
|
+
readonly __wbindgen_start: () => void;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
export type SyncInitInput = BufferSource | WebAssembly.Module;
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Instantiates the given `module`, which can either be bytes or
|
|
243
|
+
* a precompiled `WebAssembly.Module`.
|
|
244
|
+
*
|
|
245
|
+
* @param {{ module: SyncInitInput }} module - Passing `SyncInitInput` directly is deprecated.
|
|
246
|
+
*
|
|
247
|
+
* @returns {InitOutput}
|
|
248
|
+
*/
|
|
249
|
+
export function initSync(module: { module: SyncInitInput } | SyncInitInput): InitOutput;
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* If `module_or_path` is {RequestInfo} or {URL}, makes a request and
|
|
253
|
+
* for everything else, calls `WebAssembly.instantiate` directly.
|
|
254
|
+
*
|
|
255
|
+
* @param {{ module_or_path: InitInput | Promise<InitInput> }} module_or_path - Passing `InitInput` directly is deprecated.
|
|
256
|
+
*
|
|
257
|
+
* @returns {Promise<InitOutput>}
|
|
258
|
+
*/
|
|
259
|
+
export default function __wbg_init (module_or_path?: { module_or_path: InitInput | Promise<InitInput> } | InitInput | Promise<InitInput>): Promise<InitOutput>;
|