@happyvertical/secrets 0.74.8
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/AGENT.md +33 -0
- package/LICENSE +7 -0
- package/README.md +220 -0
- package/dist/adapters/database.d.ts +74 -0
- package/dist/adapters/database.d.ts.map +1 -0
- package/dist/cli/claude-context.d.ts +3 -0
- package/dist/cli/claude-context.d.ts.map +1 -0
- package/dist/cli/claude-context.js +21 -0
- package/dist/cli/claude-context.js.map +1 -0
- package/dist/index.d.ts +45 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +736 -0
- package/dist/index.js.map +1 -0
- package/dist/shared/envelope.d.ts +143 -0
- package/dist/shared/envelope.d.ts.map +1 -0
- package/dist/shared/errors.d.ts +61 -0
- package/dist/shared/errors.d.ts.map +1 -0
- package/dist/shared/factory.d.ts +44 -0
- package/dist/shared/factory.d.ts.map +1 -0
- package/dist/shared/types.d.ts +243 -0
- package/dist/shared/types.d.ts.map +1 -0
- package/metadata.json +29 -0
- package/package.json +63 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/shared/envelope.ts","../src/shared/errors.ts","../src/adapters/database.ts","../src/shared/factory.ts","../src/index.ts"],"sourcesContent":["import * as crypto from 'node:crypto';\nimport type { EncryptedEnvelope } from './types.js';\n\n/**\n * Core envelope encryption primitives using AES-256-GCM\n *\n * This class provides the cryptographic operations for envelope encryption:\n * - Generate data encryption keys (DEKs)\n * - Wrap/unwrap DEKs with a master key\n * - Encrypt/decrypt data with DEKs\n *\n * @example\n * ```typescript\n * // Generate a new data key\n * const dataKey = EnvelopeEncryption.generateDataKey();\n *\n * // Wrap the data key with an AMK\n * const wrapped = EnvelopeEncryption.wrapKey(dataKey, amk);\n *\n * // Encrypt data with the data key\n * const encrypted = EnvelopeEncryption.encryptData('secret', dataKey);\n *\n * // Later: unwrap and decrypt\n * const unwrappedKey = EnvelopeEncryption.unwrapKey(wrapped.wrappedKey, wrapped.iv, wrapped.authTag, amk);\n * const plaintext = EnvelopeEncryption.decryptData(encrypted.ciphertext, encrypted.iv, encrypted.authTag, unwrappedKey);\n * ```\n */\nexport class EnvelopeEncryption {\n private static readonly ALGORITHM = 'aes-256-gcm' as const;\n private static readonly KEY_LENGTH = 32; // 256 bits\n private static readonly IV_LENGTH = 12; // 96 bits for GCM (recommended)\n private static readonly AUTH_TAG_LENGTH = 16; // 128 bits\n\n /**\n * Generate a new random data encryption key\n *\n * @returns A 32-byte (256-bit) random key\n */\n static generateDataKey(): Buffer {\n return crypto.randomBytes(EnvelopeEncryption.KEY_LENGTH);\n }\n\n /**\n * Generate a random IV for encryption\n *\n * @returns A 12-byte (96-bit) random IV\n */\n static generateIV(): Buffer {\n return crypto.randomBytes(EnvelopeEncryption.IV_LENGTH);\n }\n\n /**\n * Wrap (encrypt) a data encryption key with a master key\n *\n * @param dataKey - The data key to wrap (32 bytes)\n * @param masterKey - The master key to wrap with (32 bytes)\n * @returns Object containing wrapped key, IV, and auth tag (all base64-encoded)\n */\n static wrapKey(\n dataKey: Buffer,\n masterKey: Buffer,\n ): { wrappedKey: string; iv: string; authTag: string } {\n EnvelopeEncryption.validateKeyLength(dataKey);\n EnvelopeEncryption.validateKeyLength(masterKey);\n const iv = EnvelopeEncryption.generateIV();\n const cipher = crypto.createCipheriv(\n EnvelopeEncryption.ALGORITHM,\n masterKey,\n iv,\n );\n\n const encrypted = Buffer.concat([cipher.update(dataKey), cipher.final()]);\n const authTag = cipher.getAuthTag();\n\n return {\n wrappedKey: encrypted.toString('base64'),\n iv: iv.toString('base64'),\n authTag: authTag.toString('base64'),\n };\n }\n\n /**\n * Unwrap (decrypt) a data encryption key with a master key\n *\n * @param wrappedKey - Base64-encoded wrapped key\n * @param iv - Base64-encoded IV\n * @param authTag - Base64-encoded authentication tag\n * @param masterKey - The master key to unwrap with (32 bytes)\n * @returns The unwrapped data key (32 bytes)\n * @throws Error if decryption fails (invalid key, tampered data, etc.)\n */\n static unwrapKey(\n wrappedKey: string,\n iv: string,\n authTag: string,\n masterKey: Buffer,\n ): Buffer {\n EnvelopeEncryption.validateKeyLength(masterKey);\n const decipher = crypto.createDecipheriv(\n EnvelopeEncryption.ALGORITHM,\n masterKey,\n Buffer.from(iv, 'base64'),\n );\n decipher.setAuthTag(Buffer.from(authTag, 'base64'));\n\n return Buffer.concat([\n decipher.update(Buffer.from(wrappedKey, 'base64')),\n decipher.final(),\n ]);\n }\n\n /**\n * Encrypt data with a data encryption key\n *\n * @param plaintext - The plaintext string to encrypt\n * @param dataKey - The data encryption key (32 bytes)\n * @returns Object containing ciphertext, IV, and auth tag (all base64-encoded)\n */\n static encryptData(\n plaintext: string,\n dataKey: Buffer,\n ): { ciphertext: string; iv: string; authTag: string } {\n EnvelopeEncryption.validateKeyLength(dataKey);\n const iv = EnvelopeEncryption.generateIV();\n const cipher = crypto.createCipheriv(\n EnvelopeEncryption.ALGORITHM,\n dataKey,\n iv,\n );\n\n const encrypted = Buffer.concat([\n cipher.update(plaintext, 'utf8'),\n cipher.final(),\n ]);\n const authTag = cipher.getAuthTag();\n\n return {\n ciphertext: encrypted.toString('base64'),\n iv: iv.toString('base64'),\n authTag: authTag.toString('base64'),\n };\n }\n\n /**\n * Decrypt data with a data encryption key\n *\n * @param ciphertext - Base64-encoded ciphertext\n * @param iv - Base64-encoded IV\n * @param authTag - Base64-encoded authentication tag\n * @param dataKey - The data encryption key (32 bytes)\n * @returns The decrypted plaintext string\n * @throws Error if decryption fails (invalid key, tampered data, etc.)\n */\n static decryptData(\n ciphertext: string,\n iv: string,\n authTag: string,\n dataKey: Buffer,\n ): string {\n EnvelopeEncryption.validateKeyLength(dataKey);\n const decipher = crypto.createDecipheriv(\n EnvelopeEncryption.ALGORITHM,\n dataKey,\n Buffer.from(iv, 'base64'),\n );\n decipher.setAuthTag(Buffer.from(authTag, 'base64'));\n\n return Buffer.concat([\n decipher.update(Buffer.from(ciphertext, 'base64')),\n decipher.final(),\n ]).toString('utf8');\n }\n\n /**\n * Create a full encrypted envelope\n *\n * This combines key wrapping and data encryption into a single envelope\n * that can be stored and later decrypted.\n *\n * @param plaintext - The plaintext string to encrypt\n * @param dataKey - The data encryption key (32 bytes)\n * @param wrappedKeyInfo - The wrapped key info (from wrapKey)\n * @param amkKeyId - The ID of the AMK used to wrap the key\n * @param metadata - Optional metadata to include in the envelope\n * @returns A complete encrypted envelope\n */\n static createEnvelope(\n plaintext: string,\n dataKey: Buffer,\n wrappedKeyInfo: { wrappedKey: string; iv: string; authTag: string },\n amkKeyId: string,\n metadata?: Record<string, string>,\n ): EncryptedEnvelope {\n const encrypted = EnvelopeEncryption.encryptData(plaintext, dataKey);\n\n // Combine wrapped key info into a single string: wrappedKey:iv:authTag\n const combinedWrappedKey = `${wrappedKeyInfo.wrappedKey}:${wrappedKeyInfo.iv}:${wrappedKeyInfo.authTag}`;\n\n return {\n version: 1,\n algorithm: 'aes-256-gcm',\n wrappedKey: combinedWrappedKey,\n amkKeyId,\n iv: encrypted.iv,\n authTag: encrypted.authTag,\n ciphertext: encrypted.ciphertext,\n createdAt: new Date().toISOString(),\n metadata,\n };\n }\n\n /**\n * Parse a combined wrapped key string\n *\n * @param combinedWrappedKey - The combined wrapped key string (wrappedKey:iv:authTag)\n * @returns Object with wrappedKey, iv, and authTag\n */\n static parseWrappedKey(combinedWrappedKey: string): {\n wrappedKey: string;\n iv: string;\n authTag: string;\n } {\n const parts = combinedWrappedKey.split(':');\n if (parts.length !== 3) {\n throw new Error(\n 'Invalid wrapped key format: expected wrappedKey:iv:authTag',\n );\n }\n const [wrappedKey, iv, authTag] = parts;\n // Validate that all parts are non-empty\n if (!wrappedKey || !iv || !authTag) {\n throw new Error(\n 'Invalid wrapped key format: wrappedKey, iv, and authTag must all be non-empty',\n );\n }\n return { wrappedKey, iv, authTag };\n }\n\n /**\n * Decrypt a full envelope\n *\n * @param envelope - The encrypted envelope\n * @param masterKey - The master key to unwrap the data key\n * @returns The decrypted plaintext string\n */\n static decryptEnvelope(\n envelope: EncryptedEnvelope,\n masterKey: Buffer,\n ): string {\n // Parse the wrapped key\n const {\n wrappedKey,\n iv: keyIv,\n authTag: keyAuthTag,\n } = EnvelopeEncryption.parseWrappedKey(envelope.wrappedKey);\n\n // Unwrap the data key\n const dataKey = EnvelopeEncryption.unwrapKey(\n wrappedKey,\n keyIv,\n keyAuthTag,\n masterKey,\n );\n\n // Decrypt the data\n return EnvelopeEncryption.decryptData(\n envelope.ciphertext,\n envelope.iv,\n envelope.authTag,\n dataKey,\n );\n }\n\n /**\n * Validate that a key is the correct length\n *\n * @param key - The key to validate\n * @param expectedLength - Expected length in bytes (default: 32)\n * @throws Error if key length is invalid\n */\n static validateKeyLength(\n key: Buffer,\n expectedLength: number = EnvelopeEncryption.KEY_LENGTH,\n ): void {\n if (key.length !== expectedLength) {\n throw new Error(\n `Invalid key length: expected ${expectedLength} bytes, got ${key.length} bytes`,\n );\n }\n }\n\n /**\n * Parse a hex-encoded key from string\n *\n * @param hexKey - Hex-encoded key string (64 chars for 32 bytes)\n * @returns The key as a Buffer\n * @throws Error if the hex string is invalid\n */\n static parseHexKey(hexKey: string): Buffer {\n if (!/^[0-9a-fA-F]+$/.test(hexKey)) {\n throw new Error('Invalid hex key: contains non-hex characters');\n }\n\n const key = Buffer.from(hexKey, 'hex');\n EnvelopeEncryption.validateKeyLength(key);\n\n return key;\n }\n}\n","/**\n * Base error class for secret operations\n */\nexport class SecretError extends Error {\n readonly code: string;\n readonly adapterType?: string;\n readonly cause?: Error;\n\n constructor(\n message: string,\n code: string,\n options?: { adapterType?: string; cause?: Error },\n ) {\n super(message);\n this.name = 'SecretError';\n this.code = code;\n this.adapterType = options?.adapterType;\n this.cause = options?.cause;\n }\n}\n\n/**\n * Error thrown when a key is not found\n */\nexport class KeyNotFoundError extends SecretError {\n constructor(keyId: string, adapterType?: string) {\n super(`Key not found: ${keyId}`, 'KEY_NOT_FOUND', { adapterType });\n this.name = 'KeyNotFoundError';\n }\n}\n\n/**\n * Error thrown when decryption fails\n */\nexport class DecryptionError extends SecretError {\n constructor(message: string, adapterType?: string, cause?: Error) {\n super(message, 'DECRYPTION_FAILED', { adapterType, cause });\n this.name = 'DecryptionError';\n }\n}\n\n/**\n * Error thrown when encryption fails\n */\nexport class EncryptionError extends SecretError {\n constructor(message: string, adapterType?: string, cause?: Error) {\n super(message, 'ENCRYPTION_FAILED', { adapterType, cause });\n this.name = 'EncryptionError';\n }\n}\n\n/**\n * Error thrown when key rotation fails\n */\nexport class KeyRotationError extends SecretError {\n constructor(message: string, adapterType?: string, cause?: Error) {\n super(message, 'KEY_ROTATION_FAILED', { adapterType, cause });\n this.name = 'KeyRotationError';\n }\n}\n\n/**\n * Error thrown when a tenant's encryption key is missing\n */\nexport class TenantKeyMissingError extends SecretError {\n constructor(tenantId: string) {\n super(\n `No active encryption key for tenant: ${tenantId}`,\n 'TENANT_KEY_MISSING',\n );\n this.name = 'TenantKeyMissingError';\n }\n}\n\n/**\n * Error thrown when the Application Master Key is unavailable\n */\nexport class AMKUnavailableError extends SecretError {\n constructor(message: string) {\n super(message, 'AMK_UNAVAILABLE');\n this.name = 'AMKUnavailableError';\n }\n}\n\n/**\n * Error thrown when the store is not initialized\n */\nexport class StoreNotInitializedError extends SecretError {\n constructor(adapterType?: string) {\n super('Secret store not initialized', 'STORE_NOT_INITIALIZED', {\n adapterType,\n });\n this.name = 'StoreNotInitializedError';\n }\n}\n\n/**\n * Error thrown when an invalid key format is encountered\n */\nexport class InvalidKeyFormatError extends SecretError {\n constructor(message: string, adapterType?: string) {\n super(message, 'INVALID_KEY_FORMAT', { adapterType });\n this.name = 'InvalidKeyFormatError';\n }\n}\n","import { type DatabaseInterface, syncSchema } from '@happyvertical/sql';\nimport { createId } from '@happyvertical/utils';\nimport { EnvelopeEncryption } from '../shared/envelope.js';\nimport {\n AMKUnavailableError,\n DecryptionError,\n EncryptionError,\n KeyRotationError,\n StoreNotInitializedError,\n TenantKeyMissingError,\n} from '../shared/errors.js';\nimport type {\n ApplicationMasterKey,\n DatabaseSecretStoreOptions,\n DecryptedSecret,\n EncryptedEnvelope,\n EncryptOptions,\n SecretStore,\n SecretStoreEvent,\n SecretStoreEventListener,\n TenantDataEncryptionKey,\n Unsubscribe,\n} from '../shared/types.js';\n\n/**\n * Default rotation period in milliseconds (90 days)\n */\nconst DEFAULT_ROTATION_PERIOD_MS = 90 * 24 * 60 * 60 * 1000;\n\n/**\n * Database-backed secret store\n *\n * Uses envelope encryption with AES-256-GCM:\n * - Application Master Key (AMK) from environment variable\n * - Per-tenant Data Encryption Keys (TDEKs) wrapped by AMK\n * - Secrets encrypted by unwrapped TDEKs\n *\n * @example\n * ```typescript\n * const store = new DatabaseSecretStore({\n * type: 'database',\n * db,\n * amk: {\n * provider: 'env',\n * keyEnvVar: 'SECRET_MASTER_KEY',\n * keyId: 'amk-v1'\n * }\n * });\n *\n * await store.initialize();\n *\n * // Encrypt a secret for a tenant\n * const envelope = await store.encrypt('tenant-123', 'api-key', 'sk_live_xxx');\n *\n * // Decrypt\n * const { value } = await store.decrypt('tenant-123', envelope);\n * ```\n */\nexport class DatabaseSecretStore implements SecretStore {\n private db: DatabaseInterface;\n private keysTable: string;\n private amkConfig: DatabaseSecretStoreOptions['amk'];\n private cachedAmk: Buffer | null = null;\n private initialized = false;\n private listeners: SecretStoreEventListener[] = [];\n\n constructor(options: DatabaseSecretStoreOptions) {\n this.db = options.db;\n\n // Validate table name to prevent SQL injection via identifier interpolation\n const tableName = options.keysTable ?? 'tenant_encryption_keys';\n if (!/^[A-Za-z0-9_]+$/.test(tableName)) {\n throw new Error(\n `Invalid keysTable name \"${tableName}\". Table name must contain only alphanumeric characters and underscores.`,\n );\n }\n this.keysTable = tableName;\n\n this.amkConfig = options.amk;\n }\n\n /**\n * Initialize the store (create schema if needed)\n */\n async initialize(): Promise<void> {\n if (this.initialized) return;\n\n // Create the tenant keys table\n const schema = `\n CREATE TABLE IF NOT EXISTS \"${this.keysTable}\" (\n id TEXT PRIMARY KEY,\n tenant_id TEXT NOT NULL,\n wrapped_key TEXT NOT NULL,\n amk_key_id TEXT NOT NULL,\n status TEXT NOT NULL DEFAULT 'active',\n version INTEGER NOT NULL DEFAULT 1,\n rotate_after TEXT,\n retired_at TEXT,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL\n );\n\n CREATE INDEX IF NOT EXISTS \"idx_${this.keysTable}_tenant_status\"\n ON \"${this.keysTable}\" (tenant_id, status);\n\n CREATE INDEX IF NOT EXISTS \"idx_${this.keysTable}_rotate_after\"\n ON \"${this.keysTable}\" (rotate_after)\n WHERE status = 'active';\n `;\n\n await syncSchema({ db: this.db, schema });\n\n this.initialized = true;\n }\n\n /**\n * Get the Application Master Key from environment\n */\n private getAMK(): Buffer {\n if (this.cachedAmk) {\n return this.cachedAmk;\n }\n\n const keyHex = process.env[this.amkConfig.keyEnvVar];\n if (!keyHex) {\n throw new AMKUnavailableError(\n `Application Master Key not found in environment variable: ${this.amkConfig.keyEnvVar}`,\n );\n }\n\n try {\n const key = EnvelopeEncryption.parseHexKey(keyHex);\n this.cachedAmk = key;\n return key;\n } catch (error) {\n throw new AMKUnavailableError(\n `Invalid AMK in ${this.amkConfig.keyEnvVar}: ${(error as Error).message}`,\n );\n }\n }\n\n /**\n * Ensure the store is initialized\n */\n private ensureInitialized(): void {\n if (!this.initialized) {\n throw new StoreNotInitializedError('database');\n }\n }\n\n /**\n * Emit an event to all listeners\n */\n private async emitEvent(event: SecretStoreEvent): Promise<void> {\n for (const listener of this.listeners) {\n await listener(event);\n }\n }\n\n /**\n * Subscribe to store events\n */\n subscribe(listener: SecretStoreEventListener): Unsubscribe {\n this.listeners.push(listener);\n return () => {\n const index = this.listeners.indexOf(listener);\n if (index !== -1) {\n this.listeners.splice(index, 1);\n }\n };\n }\n\n async encrypt(\n tenantId: string,\n secretName: string,\n plaintext: string,\n options?: EncryptOptions,\n ): Promise<EncryptedEnvelope> {\n this.ensureInitialized();\n\n // Input validation\n if (typeof tenantId !== 'string' || tenantId.trim().length === 0) {\n throw new EncryptionError(\n 'Invalid tenantId provided for encryption',\n 'database',\n );\n }\n if (typeof secretName !== 'string' || secretName.trim().length === 0) {\n throw new EncryptionError(\n 'Invalid secretName provided for encryption',\n 'database',\n );\n }\n\n let dataKey: Buffer | null = null;\n try {\n // Get or create tenant's data encryption key\n let tenantKey = await this.getTenantKey(tenantId);\n if (!tenantKey) {\n tenantKey = await this.createTenantKey(tenantId);\n }\n\n // Get AMK and unwrap the TDEK\n const amk = this.getAMK();\n const {\n wrappedKey,\n iv: keyIv,\n authTag: keyAuthTag,\n } = EnvelopeEncryption.parseWrappedKey(tenantKey.wrappedKey);\n dataKey = EnvelopeEncryption.unwrapKey(\n wrappedKey,\n keyIv,\n keyAuthTag,\n amk,\n );\n\n // Create the envelope using the unwrapped TDEK\n const envelope = EnvelopeEncryption.createEnvelope(\n plaintext,\n dataKey,\n { wrappedKey, iv: keyIv, authTag: keyAuthTag },\n tenantKey.amkKeyId,\n options?.metadata,\n );\n\n // Emit event\n await this.emitEvent({\n type: 'secret.encrypted',\n tenantId,\n keyId: tenantKey.keyId,\n secretName,\n timestamp: new Date(),\n });\n\n return envelope;\n } catch (error) {\n if (\n error instanceof AMKUnavailableError ||\n error instanceof TenantKeyMissingError\n ) {\n throw error;\n }\n throw new EncryptionError(\n `Failed to encrypt secret '${secretName}' for tenant ${tenantId}: ${(error as Error).message}`,\n 'database',\n error instanceof Error ? error : undefined,\n );\n } finally {\n // Zero out the data key buffer to prevent key material from remaining in memory\n if (dataKey && Buffer.isBuffer(dataKey)) {\n dataKey.fill(0);\n }\n }\n }\n\n async decrypt(\n tenantId: string,\n envelope: EncryptedEnvelope,\n ): Promise<DecryptedSecret> {\n this.ensureInitialized();\n\n // Input validation\n if (typeof tenantId !== 'string' || tenantId.trim().length === 0) {\n throw new DecryptionError(\n 'Invalid tenantId provided for decryption',\n 'database',\n );\n }\n\n // Get all key versions for this tenant (including retired keys for decryption)\n const tenantKeys = await this.listKeyVersions(tenantId);\n if (tenantKeys.length === 0) {\n throw new TenantKeyMissingError(tenantId);\n }\n\n // Verify that the envelope's wrapped key belongs to this tenant\n // Extract the wrapped key portion from the envelope (format: wrappedKey:iv:authTag)\n const envelopeWrappedKeyParts = envelope.wrappedKey.split(':');\n const envelopeWrappedKey = envelopeWrappedKeyParts[0];\n\n const matchingKey = tenantKeys.find((key) => {\n const keyParts = key.wrappedKey.split(':');\n return keyParts[0] === envelopeWrappedKey;\n });\n\n if (!matchingKey) {\n throw new DecryptionError(\n `Envelope was not encrypted with a key belonging to tenant ${tenantId}`,\n 'database',\n );\n }\n\n try {\n // Get AMK and decrypt the envelope\n const amk = this.getAMK();\n const plaintext = EnvelopeEncryption.decryptEnvelope(envelope, amk);\n\n // Emit event\n await this.emitEvent({\n type: 'secret.decrypted',\n tenantId,\n keyId: matchingKey.keyId,\n timestamp: new Date(),\n });\n\n return {\n value: plaintext,\n keyId: matchingKey.keyId,\n createdAt: new Date(envelope.createdAt),\n metadata: envelope.metadata,\n };\n } catch (error) {\n if (error instanceof AMKUnavailableError) {\n throw error;\n }\n throw new DecryptionError(\n `Failed to decrypt secret for tenant ${tenantId}: ${(error as Error).message}`,\n 'database',\n error instanceof Error ? error : undefined,\n );\n }\n }\n\n async getTenantKey(\n tenantId: string,\n ): Promise<TenantDataEncryptionKey | null> {\n this.ensureInitialized();\n\n const row = await this.db.get(this.keysTable, {\n tenant_id: tenantId,\n status: 'active',\n });\n\n if (!row) return null;\n\n return this.parseKeyRow(row as Record<string, unknown>);\n }\n\n async createTenantKey(tenantId: string): Promise<TenantDataEncryptionKey> {\n this.ensureInitialized();\n\n // Generate and wrap a new data key\n const amk = this.getAMK();\n const dataKey = EnvelopeEncryption.generateDataKey();\n const wrapped = EnvelopeEncryption.wrapKey(dataKey, amk);\n\n const keyId = createId();\n const wrappedKeyStr = `${wrapped.wrappedKey}:${wrapped.iv}:${wrapped.authTag}`;\n const now = new Date();\n const rotateAfter = new Date(now.getTime() + DEFAULT_ROTATION_PERIOD_MS);\n\n await this.db.insert(this.keysTable, {\n id: keyId,\n tenant_id: tenantId,\n wrapped_key: wrappedKeyStr,\n amk_key_id: this.amkConfig.keyId,\n status: 'active',\n version: 1,\n rotate_after: rotateAfter.toISOString(),\n created_at: now.toISOString(),\n updated_at: now.toISOString(),\n });\n\n // Emit event\n await this.emitEvent({\n type: 'key.created',\n tenantId,\n keyId,\n timestamp: now,\n });\n\n return {\n keyId,\n tenantId,\n wrappedKey: wrappedKeyStr,\n amkKeyId: this.amkConfig.keyId,\n status: 'active',\n version: 1,\n createdAt: now,\n rotateAfter,\n };\n }\n\n async rotateTenantKey(tenantId: string): Promise<TenantDataEncryptionKey> {\n this.ensureInitialized();\n\n const currentKey = await this.getTenantKey(tenantId);\n if (!currentKey) {\n throw new TenantKeyMissingError(tenantId);\n }\n\n const now = new Date();\n\n try {\n // Mark current key as rotating\n await this.db.update(\n this.keysTable,\n { id: currentKey.keyId },\n { status: 'rotating', updated_at: now.toISOString() },\n );\n\n // Create new key with incremented version\n const amk = this.getAMK();\n const dataKey = EnvelopeEncryption.generateDataKey();\n const wrapped = EnvelopeEncryption.wrapKey(dataKey, amk);\n\n const newKeyId = createId();\n const wrappedKeyStr = `${wrapped.wrappedKey}:${wrapped.iv}:${wrapped.authTag}`;\n const rotateAfter = new Date(now.getTime() + DEFAULT_ROTATION_PERIOD_MS);\n\n await this.db.insert(this.keysTable, {\n id: newKeyId,\n tenant_id: tenantId,\n wrapped_key: wrappedKeyStr,\n amk_key_id: this.amkConfig.keyId,\n status: 'active',\n version: currentKey.version + 1,\n rotate_after: rotateAfter.toISOString(),\n created_at: now.toISOString(),\n updated_at: now.toISOString(),\n });\n\n // Mark old key as retired\n await this.db.update(\n this.keysTable,\n { id: currentKey.keyId },\n {\n status: 'retired',\n retired_at: now.toISOString(),\n updated_at: now.toISOString(),\n },\n );\n\n // Emit event\n await this.emitEvent({\n type: 'key.rotated',\n tenantId,\n keyId: newKeyId,\n timestamp: now,\n });\n\n return {\n keyId: newKeyId,\n tenantId,\n wrappedKey: wrappedKeyStr,\n amkKeyId: this.amkConfig.keyId,\n status: 'active',\n version: currentKey.version + 1,\n createdAt: now,\n rotateAfter,\n };\n } catch (error) {\n throw new KeyRotationError(\n `Failed to rotate key for tenant ${tenantId}: ${(error as Error).message}`,\n 'database',\n error instanceof Error ? error : undefined,\n );\n }\n }\n\n async retireTenantKey(tenantId: string, keyId: string): Promise<void> {\n this.ensureInitialized();\n\n const now = new Date();\n\n await this.db.update(\n this.keysTable,\n { id: keyId, tenant_id: tenantId },\n {\n status: 'retired',\n retired_at: now.toISOString(),\n updated_at: now.toISOString(),\n },\n );\n\n // Emit event\n await this.emitEvent({\n type: 'key.retired',\n tenantId,\n keyId,\n timestamp: now,\n });\n }\n\n async getActiveAMK(): Promise<ApplicationMasterKey> {\n // Validate that the AMK is accessible\n this.getAMK();\n\n return {\n keyId: this.amkConfig.keyId,\n description: `AMK from env var ${this.amkConfig.keyEnvVar}`,\n status: 'active',\n provider: 'env',\n keyReference: this.amkConfig.keyEnvVar,\n createdAt: new Date(),\n };\n }\n\n async rewrapTenantKey(\n _tenantId: string,\n _newAmkKeyId: string,\n ): Promise<TenantDataEncryptionKey> {\n // For env-based AMK, this would require:\n // 1. Having both old and new AMK available\n // 2. Unwrapping with old AMK\n // 3. Rewrapping with new AMK\n // This is complex and risky for env-based keys\n throw new Error(\n 'AMK rotation not supported for env-based keys. ' +\n 'Use AWS KMS, Vault, or Azure Key Vault for AMK rotation support.',\n );\n }\n\n async listKeyVersions(tenantId: string): Promise<TenantDataEncryptionKey[]> {\n this.ensureInitialized();\n\n const { rows } = await this.db.query(\n `SELECT * FROM \"${this.keysTable}\" WHERE tenant_id = ? ORDER BY version DESC`,\n tenantId,\n );\n\n return rows.map((row: Record<string, unknown>) => this.parseKeyRow(row));\n }\n\n /**\n * Parse a database row into a TenantDataEncryptionKey\n */\n private parseKeyRow(row: Record<string, unknown>): TenantDataEncryptionKey {\n return {\n keyId: row.id as string,\n tenantId: row.tenant_id as string,\n wrappedKey: row.wrapped_key as string,\n amkKeyId: row.amk_key_id as string,\n status: row.status as TenantDataEncryptionKey['status'],\n version: row.version as number,\n createdAt: new Date(row.created_at as string),\n rotateAfter: row.rotate_after\n ? new Date(row.rotate_after as string)\n : undefined,\n retiredAt: row.retired_at\n ? new Date(row.retired_at as string)\n : undefined,\n };\n }\n}\n\nexport default DatabaseSecretStore;\n","import type {\n AWSKMSSecretStoreOptions,\n AzureKeyVaultSecretStoreOptions,\n DatabaseSecretStoreOptions,\n GetSecretStoreOptions,\n SecretStore,\n VaultSecretStoreOptions,\n} from './types.js';\n\n/**\n * Type guard for database options\n */\nexport function isDatabaseOptions(\n opts: GetSecretStoreOptions,\n): opts is DatabaseSecretStoreOptions {\n return opts.type === 'database';\n}\n\n/**\n * Type guard for AWS KMS options\n */\nexport function isAWSKMSOptions(\n opts: GetSecretStoreOptions,\n): opts is AWSKMSSecretStoreOptions {\n return opts.type === 'aws-kms';\n}\n\n/**\n * Type guard for Vault options\n */\nexport function isVaultOptions(\n opts: GetSecretStoreOptions,\n): opts is VaultSecretStoreOptions {\n return opts.type === 'vault';\n}\n\n/**\n * Type guard for Azure Key Vault options\n */\nexport function isAzureKeyVaultOptions(\n opts: GetSecretStoreOptions,\n): opts is AzureKeyVaultSecretStoreOptions {\n return opts.type === 'azure-keyvault';\n}\n\n/**\n * Factory function to create secret store instances\n *\n * Uses lazy imports to avoid loading unnecessary adapters and their dependencies.\n *\n * @example\n * ```typescript\n * // Database-backed store with env-based AMK\n * const store = await getSecretStore({\n * type: 'database',\n * db,\n * amk: {\n * provider: 'env',\n * keyEnvVar: 'SECRET_MASTER_KEY',\n * keyId: 'amk-v1'\n * }\n * });\n *\n * // Encrypt a secret\n * const envelope = await store.encrypt('tenant-123', 'api-key', 'sk_live_xxx');\n *\n * // Decrypt\n * const decrypted = await store.decrypt('tenant-123', envelope);\n * ```\n */\nexport async function getSecretStore(\n options: GetSecretStoreOptions,\n): Promise<SecretStore> {\n if (isDatabaseOptions(options)) {\n const { DatabaseSecretStore } = await import('../adapters/database.js');\n const store = new DatabaseSecretStore(options);\n await store.initialize();\n return store;\n }\n\n if (isAWSKMSOptions(options)) {\n // Phase 2: AWS KMS adapter\n throw new Error(\n 'AWS KMS adapter not yet implemented. Coming in a future release.',\n );\n }\n\n if (isVaultOptions(options)) {\n // Phase 2: HashiCorp Vault adapter\n throw new Error(\n 'HashiCorp Vault adapter not yet implemented. Coming in a future release.',\n );\n }\n\n if (isAzureKeyVaultOptions(options)) {\n // Phase 2: Azure Key Vault adapter\n throw new Error(\n 'Azure Key Vault adapter not yet implemented. Coming in a future release.',\n );\n }\n\n throw new Error(\n `Unsupported secret store type: ${(options as { type: string }).type}`,\n );\n}\n","/**\n * @happyvertical/secrets\n *\n * Envelope encryption for per-tenant secret management with pluggable backends.\n *\n * @example\n * ```typescript\n * import { getSecretStore } from '@happyvertical/secrets';\n * import { getDatabase } from '@happyvertical/sql';\n *\n * // Get a database connection\n * const db = await getDatabase({ type: 'sqlite', url: ':memory:' });\n *\n * // Create a secret store\n * const store = await getSecretStore({\n * type: 'database',\n * db,\n * amk: {\n * provider: 'env',\n * keyEnvVar: 'SECRET_MASTER_KEY', // 64 hex chars (32 bytes)\n * keyId: 'amk-v1'\n * }\n * });\n *\n * // Encrypt a secret for a tenant\n * const envelope = await store.encrypt('tenant-123', 'api-key', 'sk_live_xxx');\n *\n * // Decrypt the secret\n * const { value } = await store.decrypt('tenant-123', envelope);\n * console.log(value); // 'sk_live_xxx'\n *\n * // Rotate tenant's encryption key\n * await store.rotateTenantKey('tenant-123');\n * ```\n *\n * @packageDocumentation\n */\n\n// Direct adapter exports (for advanced usage)\nexport { DatabaseSecretStore } from './adapters/database.js';\n// Envelope encryption primitives\nexport { EnvelopeEncryption } from './shared/envelope.js';\n// Error classes\nexport {\n AMKUnavailableError,\n DecryptionError,\n EncryptionError,\n InvalidKeyFormatError,\n KeyNotFoundError,\n KeyRotationError,\n SecretError,\n StoreNotInitializedError,\n TenantKeyMissingError,\n} from './shared/errors.js';\n\n// Factory function\nexport {\n getSecretStore,\n isAWSKMSOptions,\n isAzureKeyVaultOptions,\n isDatabaseOptions,\n isVaultOptions,\n} from './shared/factory.js';\n// Core types\nexport type {\n // Adapter options\n AMKConfig,\n ApplicationMasterKey,\n AWSKMSSecretStoreOptions,\n AzureKeyVaultSecretStoreOptions,\n DatabaseSecretStoreOptions,\n DecryptedSecret,\n EncryptedEnvelope,\n EncryptOptions,\n GetSecretStoreOptions,\n SecretAdapterType,\n SecretStore,\n SecretStoreEvent,\n SecretStoreEventListener,\n SecretStoreEventType,\n TenantDataEncryptionKey,\n Unsubscribe,\n VaultSecretStoreOptions,\n} from './shared/types.js';\n\n/** @internal */\nexport const PACKAGE_VERSION_INITIALIZED = true;\n"],"names":["DatabaseSecretStore"],"mappings":"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"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { EncryptedEnvelope } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Core envelope encryption primitives using AES-256-GCM
|
|
4
|
+
*
|
|
5
|
+
* This class provides the cryptographic operations for envelope encryption:
|
|
6
|
+
* - Generate data encryption keys (DEKs)
|
|
7
|
+
* - Wrap/unwrap DEKs with a master key
|
|
8
|
+
* - Encrypt/decrypt data with DEKs
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* // Generate a new data key
|
|
13
|
+
* const dataKey = EnvelopeEncryption.generateDataKey();
|
|
14
|
+
*
|
|
15
|
+
* // Wrap the data key with an AMK
|
|
16
|
+
* const wrapped = EnvelopeEncryption.wrapKey(dataKey, amk);
|
|
17
|
+
*
|
|
18
|
+
* // Encrypt data with the data key
|
|
19
|
+
* const encrypted = EnvelopeEncryption.encryptData('secret', dataKey);
|
|
20
|
+
*
|
|
21
|
+
* // Later: unwrap and decrypt
|
|
22
|
+
* const unwrappedKey = EnvelopeEncryption.unwrapKey(wrapped.wrappedKey, wrapped.iv, wrapped.authTag, amk);
|
|
23
|
+
* const plaintext = EnvelopeEncryption.decryptData(encrypted.ciphertext, encrypted.iv, encrypted.authTag, unwrappedKey);
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export declare class EnvelopeEncryption {
|
|
27
|
+
private static readonly ALGORITHM;
|
|
28
|
+
private static readonly KEY_LENGTH;
|
|
29
|
+
private static readonly IV_LENGTH;
|
|
30
|
+
private static readonly AUTH_TAG_LENGTH;
|
|
31
|
+
/**
|
|
32
|
+
* Generate a new random data encryption key
|
|
33
|
+
*
|
|
34
|
+
* @returns A 32-byte (256-bit) random key
|
|
35
|
+
*/
|
|
36
|
+
static generateDataKey(): Buffer;
|
|
37
|
+
/**
|
|
38
|
+
* Generate a random IV for encryption
|
|
39
|
+
*
|
|
40
|
+
* @returns A 12-byte (96-bit) random IV
|
|
41
|
+
*/
|
|
42
|
+
static generateIV(): Buffer;
|
|
43
|
+
/**
|
|
44
|
+
* Wrap (encrypt) a data encryption key with a master key
|
|
45
|
+
*
|
|
46
|
+
* @param dataKey - The data key to wrap (32 bytes)
|
|
47
|
+
* @param masterKey - The master key to wrap with (32 bytes)
|
|
48
|
+
* @returns Object containing wrapped key, IV, and auth tag (all base64-encoded)
|
|
49
|
+
*/
|
|
50
|
+
static wrapKey(dataKey: Buffer, masterKey: Buffer): {
|
|
51
|
+
wrappedKey: string;
|
|
52
|
+
iv: string;
|
|
53
|
+
authTag: string;
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* Unwrap (decrypt) a data encryption key with a master key
|
|
57
|
+
*
|
|
58
|
+
* @param wrappedKey - Base64-encoded wrapped key
|
|
59
|
+
* @param iv - Base64-encoded IV
|
|
60
|
+
* @param authTag - Base64-encoded authentication tag
|
|
61
|
+
* @param masterKey - The master key to unwrap with (32 bytes)
|
|
62
|
+
* @returns The unwrapped data key (32 bytes)
|
|
63
|
+
* @throws Error if decryption fails (invalid key, tampered data, etc.)
|
|
64
|
+
*/
|
|
65
|
+
static unwrapKey(wrappedKey: string, iv: string, authTag: string, masterKey: Buffer): Buffer;
|
|
66
|
+
/**
|
|
67
|
+
* Encrypt data with a data encryption key
|
|
68
|
+
*
|
|
69
|
+
* @param plaintext - The plaintext string to encrypt
|
|
70
|
+
* @param dataKey - The data encryption key (32 bytes)
|
|
71
|
+
* @returns Object containing ciphertext, IV, and auth tag (all base64-encoded)
|
|
72
|
+
*/
|
|
73
|
+
static encryptData(plaintext: string, dataKey: Buffer): {
|
|
74
|
+
ciphertext: string;
|
|
75
|
+
iv: string;
|
|
76
|
+
authTag: string;
|
|
77
|
+
};
|
|
78
|
+
/**
|
|
79
|
+
* Decrypt data with a data encryption key
|
|
80
|
+
*
|
|
81
|
+
* @param ciphertext - Base64-encoded ciphertext
|
|
82
|
+
* @param iv - Base64-encoded IV
|
|
83
|
+
* @param authTag - Base64-encoded authentication tag
|
|
84
|
+
* @param dataKey - The data encryption key (32 bytes)
|
|
85
|
+
* @returns The decrypted plaintext string
|
|
86
|
+
* @throws Error if decryption fails (invalid key, tampered data, etc.)
|
|
87
|
+
*/
|
|
88
|
+
static decryptData(ciphertext: string, iv: string, authTag: string, dataKey: Buffer): string;
|
|
89
|
+
/**
|
|
90
|
+
* Create a full encrypted envelope
|
|
91
|
+
*
|
|
92
|
+
* This combines key wrapping and data encryption into a single envelope
|
|
93
|
+
* that can be stored and later decrypted.
|
|
94
|
+
*
|
|
95
|
+
* @param plaintext - The plaintext string to encrypt
|
|
96
|
+
* @param dataKey - The data encryption key (32 bytes)
|
|
97
|
+
* @param wrappedKeyInfo - The wrapped key info (from wrapKey)
|
|
98
|
+
* @param amkKeyId - The ID of the AMK used to wrap the key
|
|
99
|
+
* @param metadata - Optional metadata to include in the envelope
|
|
100
|
+
* @returns A complete encrypted envelope
|
|
101
|
+
*/
|
|
102
|
+
static createEnvelope(plaintext: string, dataKey: Buffer, wrappedKeyInfo: {
|
|
103
|
+
wrappedKey: string;
|
|
104
|
+
iv: string;
|
|
105
|
+
authTag: string;
|
|
106
|
+
}, amkKeyId: string, metadata?: Record<string, string>): EncryptedEnvelope;
|
|
107
|
+
/**
|
|
108
|
+
* Parse a combined wrapped key string
|
|
109
|
+
*
|
|
110
|
+
* @param combinedWrappedKey - The combined wrapped key string (wrappedKey:iv:authTag)
|
|
111
|
+
* @returns Object with wrappedKey, iv, and authTag
|
|
112
|
+
*/
|
|
113
|
+
static parseWrappedKey(combinedWrappedKey: string): {
|
|
114
|
+
wrappedKey: string;
|
|
115
|
+
iv: string;
|
|
116
|
+
authTag: string;
|
|
117
|
+
};
|
|
118
|
+
/**
|
|
119
|
+
* Decrypt a full envelope
|
|
120
|
+
*
|
|
121
|
+
* @param envelope - The encrypted envelope
|
|
122
|
+
* @param masterKey - The master key to unwrap the data key
|
|
123
|
+
* @returns The decrypted plaintext string
|
|
124
|
+
*/
|
|
125
|
+
static decryptEnvelope(envelope: EncryptedEnvelope, masterKey: Buffer): string;
|
|
126
|
+
/**
|
|
127
|
+
* Validate that a key is the correct length
|
|
128
|
+
*
|
|
129
|
+
* @param key - The key to validate
|
|
130
|
+
* @param expectedLength - Expected length in bytes (default: 32)
|
|
131
|
+
* @throws Error if key length is invalid
|
|
132
|
+
*/
|
|
133
|
+
static validateKeyLength(key: Buffer, expectedLength?: number): void;
|
|
134
|
+
/**
|
|
135
|
+
* Parse a hex-encoded key from string
|
|
136
|
+
*
|
|
137
|
+
* @param hexKey - Hex-encoded key string (64 chars for 32 bytes)
|
|
138
|
+
* @returns The key as a Buffer
|
|
139
|
+
* @throws Error if the hex string is invalid
|
|
140
|
+
*/
|
|
141
|
+
static parseHexKey(hexKey: string): Buffer;
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=envelope.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"envelope.d.ts","sourceRoot":"","sources":["../../src/shared/envelope.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAA0B;IAC3D,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAM;IACxC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAM;IACvC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAM;IAE7C;;;;OAIG;IACH,MAAM,CAAC,eAAe,IAAI,MAAM;IAIhC;;;;OAIG;IACH,MAAM,CAAC,UAAU,IAAI,MAAM;IAI3B;;;;;;OAMG;IACH,MAAM,CAAC,OAAO,CACZ,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,GAChB;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE;IAoBtD;;;;;;;;;OASG;IACH,MAAM,CAAC,SAAS,CACd,UAAU,EAAE,MAAM,EAClB,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,GAChB,MAAM;IAeT;;;;;;OAMG;IACH,MAAM,CAAC,WAAW,CAChB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,GACd;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE;IAsBtD;;;;;;;;;OASG;IACH,MAAM,CAAC,WAAW,CAChB,UAAU,EAAE,MAAM,EAClB,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,GACd,MAAM;IAeT;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,cAAc,CACnB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,cAAc,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,EACnE,QAAQ,EAAE,MAAM,EAChB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAChC,iBAAiB;IAmBpB;;;;;OAKG;IACH,MAAM,CAAC,eAAe,CAAC,kBAAkB,EAAE,MAAM,GAAG;QAClD,UAAU,EAAE,MAAM,CAAC;QACnB,EAAE,EAAE,MAAM,CAAC;QACX,OAAO,EAAE,MAAM,CAAC;KACjB;IAiBD;;;;;;OAMG;IACH,MAAM,CAAC,eAAe,CACpB,QAAQ,EAAE,iBAAiB,EAC3B,SAAS,EAAE,MAAM,GAChB,MAAM;IAyBT;;;;;;OAMG;IACH,MAAM,CAAC,iBAAiB,CACtB,GAAG,EAAE,MAAM,EACX,cAAc,GAAE,MAAsC,GACrD,IAAI;IAQP;;;;;;OAMG;IACH,MAAM,CAAC,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;CAU3C"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base error class for secret operations
|
|
3
|
+
*/
|
|
4
|
+
export declare class SecretError extends Error {
|
|
5
|
+
readonly code: string;
|
|
6
|
+
readonly adapterType?: string;
|
|
7
|
+
readonly cause?: Error;
|
|
8
|
+
constructor(message: string, code: string, options?: {
|
|
9
|
+
adapterType?: string;
|
|
10
|
+
cause?: Error;
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Error thrown when a key is not found
|
|
15
|
+
*/
|
|
16
|
+
export declare class KeyNotFoundError extends SecretError {
|
|
17
|
+
constructor(keyId: string, adapterType?: string);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Error thrown when decryption fails
|
|
21
|
+
*/
|
|
22
|
+
export declare class DecryptionError extends SecretError {
|
|
23
|
+
constructor(message: string, adapterType?: string, cause?: Error);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Error thrown when encryption fails
|
|
27
|
+
*/
|
|
28
|
+
export declare class EncryptionError extends SecretError {
|
|
29
|
+
constructor(message: string, adapterType?: string, cause?: Error);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Error thrown when key rotation fails
|
|
33
|
+
*/
|
|
34
|
+
export declare class KeyRotationError extends SecretError {
|
|
35
|
+
constructor(message: string, adapterType?: string, cause?: Error);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Error thrown when a tenant's encryption key is missing
|
|
39
|
+
*/
|
|
40
|
+
export declare class TenantKeyMissingError extends SecretError {
|
|
41
|
+
constructor(tenantId: string);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Error thrown when the Application Master Key is unavailable
|
|
45
|
+
*/
|
|
46
|
+
export declare class AMKUnavailableError extends SecretError {
|
|
47
|
+
constructor(message: string);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Error thrown when the store is not initialized
|
|
51
|
+
*/
|
|
52
|
+
export declare class StoreNotInitializedError extends SecretError {
|
|
53
|
+
constructor(adapterType?: string);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Error thrown when an invalid key format is encountered
|
|
57
|
+
*/
|
|
58
|
+
export declare class InvalidKeyFormatError extends SecretError {
|
|
59
|
+
constructor(message: string, adapterType?: string);
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/shared/errors.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,WAAY,SAAQ,KAAK;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC;gBAGrB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,KAAK,CAAA;KAAE;CAQpD;AAED;;GAEG;AACH,qBAAa,gBAAiB,SAAQ,WAAW;gBACnC,KAAK,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM;CAIhD;AAED;;GAEG;AACH,qBAAa,eAAgB,SAAQ,WAAW;gBAClC,OAAO,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK;CAIjE;AAED;;GAEG;AACH,qBAAa,eAAgB,SAAQ,WAAW;gBAClC,OAAO,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK;CAIjE;AAED;;GAEG;AACH,qBAAa,gBAAiB,SAAQ,WAAW;gBACnC,OAAO,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK;CAIjE;AAED;;GAEG;AACH,qBAAa,qBAAsB,SAAQ,WAAW;gBACxC,QAAQ,EAAE,MAAM;CAO7B;AAED;;GAEG;AACH,qBAAa,mBAAoB,SAAQ,WAAW;gBACtC,OAAO,EAAE,MAAM;CAI5B;AAED;;GAEG;AACH,qBAAa,wBAAyB,SAAQ,WAAW;gBAC3C,WAAW,CAAC,EAAE,MAAM;CAMjC;AAED;;GAEG;AACH,qBAAa,qBAAsB,SAAQ,WAAW;gBACxC,OAAO,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM;CAIlD"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { AWSKMSSecretStoreOptions, AzureKeyVaultSecretStoreOptions, DatabaseSecretStoreOptions, GetSecretStoreOptions, SecretStore, VaultSecretStoreOptions } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Type guard for database options
|
|
4
|
+
*/
|
|
5
|
+
export declare function isDatabaseOptions(opts: GetSecretStoreOptions): opts is DatabaseSecretStoreOptions;
|
|
6
|
+
/**
|
|
7
|
+
* Type guard for AWS KMS options
|
|
8
|
+
*/
|
|
9
|
+
export declare function isAWSKMSOptions(opts: GetSecretStoreOptions): opts is AWSKMSSecretStoreOptions;
|
|
10
|
+
/**
|
|
11
|
+
* Type guard for Vault options
|
|
12
|
+
*/
|
|
13
|
+
export declare function isVaultOptions(opts: GetSecretStoreOptions): opts is VaultSecretStoreOptions;
|
|
14
|
+
/**
|
|
15
|
+
* Type guard for Azure Key Vault options
|
|
16
|
+
*/
|
|
17
|
+
export declare function isAzureKeyVaultOptions(opts: GetSecretStoreOptions): opts is AzureKeyVaultSecretStoreOptions;
|
|
18
|
+
/**
|
|
19
|
+
* Factory function to create secret store instances
|
|
20
|
+
*
|
|
21
|
+
* Uses lazy imports to avoid loading unnecessary adapters and their dependencies.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```typescript
|
|
25
|
+
* // Database-backed store with env-based AMK
|
|
26
|
+
* const store = await getSecretStore({
|
|
27
|
+
* type: 'database',
|
|
28
|
+
* db,
|
|
29
|
+
* amk: {
|
|
30
|
+
* provider: 'env',
|
|
31
|
+
* keyEnvVar: 'SECRET_MASTER_KEY',
|
|
32
|
+
* keyId: 'amk-v1'
|
|
33
|
+
* }
|
|
34
|
+
* });
|
|
35
|
+
*
|
|
36
|
+
* // Encrypt a secret
|
|
37
|
+
* const envelope = await store.encrypt('tenant-123', 'api-key', 'sk_live_xxx');
|
|
38
|
+
*
|
|
39
|
+
* // Decrypt
|
|
40
|
+
* const decrypted = await store.decrypt('tenant-123', envelope);
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export declare function getSecretStore(options: GetSecretStoreOptions): Promise<SecretStore>;
|
|
44
|
+
//# sourceMappingURL=factory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/shared/factory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,wBAAwB,EACxB,+BAA+B,EAC/B,0BAA0B,EAC1B,qBAAqB,EACrB,WAAW,EACX,uBAAuB,EACxB,MAAM,YAAY,CAAC;AAEpB;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,qBAAqB,GAC1B,IAAI,IAAI,0BAA0B,CAEpC;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,qBAAqB,GAC1B,IAAI,IAAI,wBAAwB,CAElC;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,qBAAqB,GAC1B,IAAI,IAAI,uBAAuB,CAEjC;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,qBAAqB,GAC1B,IAAI,IAAI,+BAA+B,CAEzC;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,WAAW,CAAC,CAgCtB"}
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
import { DatabaseInterface } from '@happyvertical/sql';
|
|
2
|
+
/**
|
|
3
|
+
* Secret store adapter type discriminator
|
|
4
|
+
*/
|
|
5
|
+
export type SecretAdapterType = 'database' | 'aws-kms' | 'vault' | 'azure-keyvault';
|
|
6
|
+
/**
|
|
7
|
+
* Encrypted secret envelope format
|
|
8
|
+
* Stored as JSON in database or external secret stores
|
|
9
|
+
*/
|
|
10
|
+
export interface EncryptedEnvelope {
|
|
11
|
+
/** Version of envelope format for future migrations */
|
|
12
|
+
version: 1;
|
|
13
|
+
/** Algorithm used: always 'aes-256-gcm' */
|
|
14
|
+
algorithm: 'aes-256-gcm';
|
|
15
|
+
/** Base64-encoded wrapped TDEK (encrypted by AMK) - format: wrappedKey:iv:authTag */
|
|
16
|
+
wrappedKey: string;
|
|
17
|
+
/** Key ID of the AMK used to wrap the TDEK */
|
|
18
|
+
amkKeyId: string;
|
|
19
|
+
/** Base64-encoded IV for data encryption */
|
|
20
|
+
iv: string;
|
|
21
|
+
/** Base64-encoded authentication tag */
|
|
22
|
+
authTag: string;
|
|
23
|
+
/** Base64-encoded encrypted secret data */
|
|
24
|
+
ciphertext: string;
|
|
25
|
+
/** Creation timestamp */
|
|
26
|
+
createdAt: string;
|
|
27
|
+
/** Optional metadata for audit trail */
|
|
28
|
+
metadata?: Record<string, string>;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Decrypted secret with metadata
|
|
32
|
+
*/
|
|
33
|
+
export interface DecryptedSecret {
|
|
34
|
+
/** The plaintext secret value */
|
|
35
|
+
value: string;
|
|
36
|
+
/** Key ID that was used */
|
|
37
|
+
keyId: string;
|
|
38
|
+
/** When the secret was encrypted */
|
|
39
|
+
createdAt: Date;
|
|
40
|
+
/** Optional metadata */
|
|
41
|
+
metadata?: Record<string, string>;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Data Encryption Key (TDEK) for a tenant
|
|
45
|
+
*/
|
|
46
|
+
export interface TenantDataEncryptionKey {
|
|
47
|
+
/** Unique key identifier */
|
|
48
|
+
keyId: string;
|
|
49
|
+
/** Tenant this key belongs to */
|
|
50
|
+
tenantId: string;
|
|
51
|
+
/** Base64-encoded wrapped key (format: wrappedKey:iv:authTag, encrypted by AMK) */
|
|
52
|
+
wrappedKey: string;
|
|
53
|
+
/** AMK key ID used to wrap this key */
|
|
54
|
+
amkKeyId: string;
|
|
55
|
+
/** Key status */
|
|
56
|
+
status: 'active' | 'rotating' | 'retired' | 'compromised';
|
|
57
|
+
/** Key version for rotation tracking */
|
|
58
|
+
version: number;
|
|
59
|
+
/** Creation timestamp */
|
|
60
|
+
createdAt: Date;
|
|
61
|
+
/** Rotation timestamp (when next rotation should occur) */
|
|
62
|
+
rotateAfter?: Date;
|
|
63
|
+
/** Retirement timestamp (when key was retired) */
|
|
64
|
+
retiredAt?: Date;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Application Master Key reference
|
|
68
|
+
* The actual key material is in environment or KMS
|
|
69
|
+
*/
|
|
70
|
+
export interface ApplicationMasterKey {
|
|
71
|
+
/** Unique key identifier */
|
|
72
|
+
keyId: string;
|
|
73
|
+
/** Human-readable description */
|
|
74
|
+
description: string;
|
|
75
|
+
/** Key status */
|
|
76
|
+
status: 'active' | 'retiring' | 'retired';
|
|
77
|
+
/** Provider: 'env' (environment variable) or KMS provider name */
|
|
78
|
+
provider: 'env' | 'aws-kms' | 'vault' | 'azure-keyvault';
|
|
79
|
+
/** Provider-specific key reference (env var name, KMS ARN, etc.) */
|
|
80
|
+
keyReference: string;
|
|
81
|
+
/** Creation timestamp */
|
|
82
|
+
createdAt: Date;
|
|
83
|
+
/** When this key should be retired */
|
|
84
|
+
retireAfter?: Date;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Options for encryption
|
|
88
|
+
*/
|
|
89
|
+
export interface EncryptOptions {
|
|
90
|
+
/** Additional metadata to store with the secret */
|
|
91
|
+
metadata?: Record<string, string>;
|
|
92
|
+
/** Use a specific TDEK version (default: active) */
|
|
93
|
+
keyVersion?: number;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Secret store interface - implemented by all adapters
|
|
97
|
+
*/
|
|
98
|
+
export interface SecretStore {
|
|
99
|
+
/**
|
|
100
|
+
* Encrypt a secret value for a tenant
|
|
101
|
+
*/
|
|
102
|
+
encrypt(tenantId: string, secretName: string, plaintext: string, options?: EncryptOptions): Promise<EncryptedEnvelope>;
|
|
103
|
+
/**
|
|
104
|
+
* Decrypt an encrypted envelope for a tenant
|
|
105
|
+
*/
|
|
106
|
+
decrypt(tenantId: string, envelope: EncryptedEnvelope): Promise<DecryptedSecret>;
|
|
107
|
+
/**
|
|
108
|
+
* Get the active tenant data encryption key
|
|
109
|
+
*/
|
|
110
|
+
getTenantKey(tenantId: string): Promise<TenantDataEncryptionKey | null>;
|
|
111
|
+
/**
|
|
112
|
+
* Create a new tenant data encryption key
|
|
113
|
+
*/
|
|
114
|
+
createTenantKey(tenantId: string): Promise<TenantDataEncryptionKey>;
|
|
115
|
+
/**
|
|
116
|
+
* Rotate the tenant's encryption key
|
|
117
|
+
*/
|
|
118
|
+
rotateTenantKey(tenantId: string): Promise<TenantDataEncryptionKey>;
|
|
119
|
+
/**
|
|
120
|
+
* Retire a tenant key
|
|
121
|
+
*/
|
|
122
|
+
retireTenantKey(tenantId: string, keyId: string): Promise<void>;
|
|
123
|
+
/**
|
|
124
|
+
* Get the active Application Master Key info
|
|
125
|
+
*/
|
|
126
|
+
getActiveAMK(): Promise<ApplicationMasterKey>;
|
|
127
|
+
/**
|
|
128
|
+
* Re-wrap a tenant key with a new AMK (for AMK rotation)
|
|
129
|
+
*/
|
|
130
|
+
rewrapTenantKey(tenantId: string, newAmkKeyId: string): Promise<TenantDataEncryptionKey>;
|
|
131
|
+
/**
|
|
132
|
+
* List all key versions for a tenant
|
|
133
|
+
*/
|
|
134
|
+
listKeyVersions(tenantId: string): Promise<TenantDataEncryptionKey[]>;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Store event types
|
|
138
|
+
*/
|
|
139
|
+
export type SecretStoreEventType = 'key.created' | 'key.rotated' | 'key.retired' | 'secret.encrypted' | 'secret.decrypted';
|
|
140
|
+
/**
|
|
141
|
+
* Store event payload
|
|
142
|
+
*/
|
|
143
|
+
export interface SecretStoreEvent {
|
|
144
|
+
type: SecretStoreEventType;
|
|
145
|
+
tenantId: string;
|
|
146
|
+
keyId?: string;
|
|
147
|
+
secretName?: string;
|
|
148
|
+
timestamp: Date;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Event listener function
|
|
152
|
+
*/
|
|
153
|
+
export type SecretStoreEventListener = (event: SecretStoreEvent) => void | Promise<void>;
|
|
154
|
+
/**
|
|
155
|
+
* Unsubscribe function
|
|
156
|
+
*/
|
|
157
|
+
export type Unsubscribe = () => void;
|
|
158
|
+
/**
|
|
159
|
+
* AMK configuration for environment-based keys
|
|
160
|
+
*/
|
|
161
|
+
export interface AMKConfig {
|
|
162
|
+
/** Provider for AMK */
|
|
163
|
+
provider: 'env';
|
|
164
|
+
/** Environment variable name containing the key (hex-encoded 32 bytes) */
|
|
165
|
+
keyEnvVar: string;
|
|
166
|
+
/** Key ID for tracking */
|
|
167
|
+
keyId: string;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Database secret store options
|
|
171
|
+
*/
|
|
172
|
+
export interface DatabaseSecretStoreOptions {
|
|
173
|
+
type: 'database';
|
|
174
|
+
/** Database connection */
|
|
175
|
+
db: DatabaseInterface;
|
|
176
|
+
/** Table name for tenant keys (default: 'tenant_encryption_keys') */
|
|
177
|
+
keysTable?: string;
|
|
178
|
+
/** AMK configuration */
|
|
179
|
+
amk: AMKConfig;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* AWS KMS secret store options (Phase 2)
|
|
183
|
+
*/
|
|
184
|
+
export interface AWSKMSSecretStoreOptions {
|
|
185
|
+
type: 'aws-kms';
|
|
186
|
+
/** AWS region */
|
|
187
|
+
region: string;
|
|
188
|
+
/** KMS key ARN for AMK */
|
|
189
|
+
masterKeyArn: string;
|
|
190
|
+
/** Optional AWS credentials */
|
|
191
|
+
credentials?: {
|
|
192
|
+
accessKeyId: string;
|
|
193
|
+
secretAccessKey: string;
|
|
194
|
+
sessionToken?: string;
|
|
195
|
+
};
|
|
196
|
+
/** Database for TDEK storage */
|
|
197
|
+
db: DatabaseInterface;
|
|
198
|
+
/** Table name for tenant keys */
|
|
199
|
+
keysTable?: string;
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* HashiCorp Vault secret store options (Phase 2)
|
|
203
|
+
*/
|
|
204
|
+
export interface VaultSecretStoreOptions {
|
|
205
|
+
type: 'vault';
|
|
206
|
+
/** Vault server address */
|
|
207
|
+
address: string;
|
|
208
|
+
/** Vault token */
|
|
209
|
+
token: string;
|
|
210
|
+
/** Transit engine mount path (default: 'transit') */
|
|
211
|
+
transitMount?: string;
|
|
212
|
+
/** KV engine mount path for TDEKs (default: 'secret') */
|
|
213
|
+
kvMount?: string;
|
|
214
|
+
/** Namespace (Enterprise only) */
|
|
215
|
+
namespace?: string;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Azure Key Vault secret store options (Phase 2)
|
|
219
|
+
*/
|
|
220
|
+
export interface AzureKeyVaultSecretStoreOptions {
|
|
221
|
+
type: 'azure-keyvault';
|
|
222
|
+
/** Key Vault URL */
|
|
223
|
+
vaultUrl: string;
|
|
224
|
+
/** Key name for AMK */
|
|
225
|
+
masterKeyName: string;
|
|
226
|
+
/** Authentication method */
|
|
227
|
+
auth: 'managed-identity' | 'service-principal' | 'cli';
|
|
228
|
+
/** Service principal credentials (if auth is 'service-principal') */
|
|
229
|
+
credentials?: {
|
|
230
|
+
tenantId: string;
|
|
231
|
+
clientId: string;
|
|
232
|
+
clientSecret: string;
|
|
233
|
+
};
|
|
234
|
+
/** Database for TDEK storage */
|
|
235
|
+
db: DatabaseInterface;
|
|
236
|
+
/** Table name for tenant keys */
|
|
237
|
+
keysTable?: string;
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Union type for all secret store options
|
|
241
|
+
*/
|
|
242
|
+
export type GetSecretStoreOptions = DatabaseSecretStoreOptions | AWSKMSSecretStoreOptions | VaultSecretStoreOptions | AzureKeyVaultSecretStoreOptions;
|
|
243
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/shared/types.ts"],"names":[],"mappings":"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"}
|
package/metadata.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@happyvertical/secrets",
|
|
3
|
+
"path": "packages/secrets",
|
|
4
|
+
"position": {
|
|
5
|
+
"index": 24,
|
|
6
|
+
"count": 30
|
|
7
|
+
},
|
|
8
|
+
"description": "Envelope encryption for per-tenant secret management with pluggable backends",
|
|
9
|
+
"provides": [
|
|
10
|
+
"Envelope encryption for per-tenant secret management with pluggable backends"
|
|
11
|
+
],
|
|
12
|
+
"implements": [],
|
|
13
|
+
"requires": {
|
|
14
|
+
"workspace": [
|
|
15
|
+
"@happyvertical/sql",
|
|
16
|
+
"@happyvertical/utils"
|
|
17
|
+
],
|
|
18
|
+
"externalHappyVertical": [],
|
|
19
|
+
"external": []
|
|
20
|
+
},
|
|
21
|
+
"dependents": [],
|
|
22
|
+
"stability": {
|
|
23
|
+
"level": "stable",
|
|
24
|
+
"reason": "Primary package surface is described as implemented and production-oriented."
|
|
25
|
+
},
|
|
26
|
+
"keywords": [
|
|
27
|
+
"secrets"
|
|
28
|
+
]
|
|
29
|
+
}
|