diff --git a/src/Managing.Web3Proxy/src/plugins/custom/privy.ts b/src/Managing.Web3Proxy/src/plugins/custom/privy.ts index 1c970c6f..d0aa2a40 100644 --- a/src/Managing.Web3Proxy/src/plugins/custom/privy.ts +++ b/src/Managing.Web3Proxy/src/plugins/custom/privy.ts @@ -50,26 +50,77 @@ declare module 'fastify' { } } +/** + * Reads a secret from Docker secrets mount point (production only) + */ +const readDockerSecret = (secretName: string): string | undefined => { + if (process.env.NODE_ENV !== 'production') return undefined + + const secretPath = `/run/secrets/${secretName}` + if (fs.existsSync(secretPath)) { + try { + return fs.readFileSync(secretPath, 'utf8').trim() + } catch (error) { + console.error(`Failed to read Docker secret ${secretPath}:`, error) + return undefined + } + } + return undefined +} + /** * Returns an initialized PrivyClient instance with configuration from environment variables * @returns The configured PrivyClient instance */ export const getPrivyClient = (fastify?: FastifyInstance): PrivyClient => { - // Prefer Fastify decorator (populated by privy-secrets plugin) + const isProd = process.env.NODE_ENV === 'production' + + // Try multiple sources in order of preference: + // 1. Fastify decorator (populated by privy-secrets plugin) + // 2. Fastify config (from env plugin) + // 3. Docker secrets (production only) + // 4. Environment variables + const decorated = (fastify as any)?.privySecrets as { appId: string; appSecret: string; authKey: string } | undefined - const appId = decorated?.appId || fastify?.config?.PRIVY_APP_ID || process.env.PRIVY_APP_ID - const appSecret = decorated?.appSecret || fastify?.config?.PRIVY_APP_SECRET || process.env.PRIVY_APP_SECRET - const authKey = decorated?.authKey || fastify?.config?.PRIVY_AUTHORIZATION_KEY || process.env.PRIVY_AUTHORIZATION_KEY + + let appId = decorated?.appId || fastify?.config?.PRIVY_APP_ID + let appSecret = decorated?.appSecret || fastify?.config?.PRIVY_APP_SECRET + let authKey = decorated?.authKey || fastify?.config?.PRIVY_AUTHORIZATION_KEY + + // In production, fall back to Docker secrets if not found in decorator/config + if (isProd) { + if (!appId) appId = readDockerSecret('PRIVY_APP_ID') + if (!appSecret) appSecret = readDockerSecret('PRIVY_APP_SECRET') + if (!authKey) authKey = readDockerSecret('PRIVY_AUTHORIZATION_KEY') + } + + // Final fallback to environment variables + appId = appId || process.env.PRIVY_APP_ID + appSecret = appSecret || process.env.PRIVY_APP_SECRET + authKey = authKey || process.env.PRIVY_AUTHORIZATION_KEY if (!appId || !appSecret || !authKey) { console.warn('Missing Privy environment variables:'); console.warn('PRIVY_APP_ID:', appId ? 'present' : 'missing'); console.warn('PRIVY_APP_SECRET:', appSecret ? 'present' : 'missing'); console.warn('PRIVY_AUTHORIZATION_KEY:', authKey ? 'present' : 'missing'); + console.warn('NODE_ENV:', process.env.NODE_ENV); + console.warn('Fastify privySecrets decorated:', !!decorated); + console.warn('Fastify config available:', !!fastify?.config); + + // In production, also log Docker secret file existence + if (isProd) { + console.warn('Docker secrets check:'); + console.warn(' /run/secrets/PRIVY_APP_ID exists:', fs.existsSync('/run/secrets/PRIVY_APP_ID')); + console.warn(' /run/secrets/PRIVY_APP_SECRET exists:', fs.existsSync('/run/secrets/PRIVY_APP_SECRET')); + console.warn(' /run/secrets/PRIVY_AUTHORIZATION_KEY exists:', fs.existsSync('/run/secrets/PRIVY_AUTHORIZATION_KEY')); + } + throw new Error('Missing required Privy environment variables'); } console.log('appId', appId); + console.log('Privy client initialized successfully'); return new PrivyClient( appId,