import * as jose from "https://deno.land/x/jose@v5.9.6/index.ts"; import { getUserByEmail } from "./supabase.ts"; import { SupabaseClient } from "@supabase/supabase-js"; import crypto from "node:crypto"; import { Buffer } from "node:buffer"; import { Encoder } from "@evan/opus"; export const defaultVolume = 50; // Define your audio parameters export const SAMPLE_RATE = 24000; // For example, 24000 Hz const CHANNELS = 1; // Mono (set to 2 if you have stereo) const FRAME_DURATION = 120; // Frame length in ms const BYTES_PER_SAMPLE = 2; // 16-bit PCM: 2 bytes per sample const FRAME_SIZE = (SAMPLE_RATE * FRAME_DURATION / 1000) * CHANNELS * BYTES_PER_SAMPLE; // 960 bytes for 24000 Hz mono 16-bit const encoder = new Encoder({ channels: CHANNELS, sample_rate: SAMPLE_RATE, application: "voip", }); encoder.expert_frame_duration = FRAME_DURATION; encoder.bitrate = 12000; export const openaiApiKey = Deno.env.get("OPENAI_API_KEY"); export const geminiApiKey = Deno.env.get("GEMINI_API_KEY"); export { encoder, FRAME_SIZE }; export const isDev = Deno.env.get("DEV_MODE") === "True"; export const authenticateUser = async ( supabaseClient: SupabaseClient, authToken: string, ): Promise => { try { const jwtSecret = Deno.env.get("JWT_SECRET_KEY"); if (!jwtSecret) throw new Error("JWT_SECRET_KEY not configured"); const secretBytes = new TextEncoder().encode(jwtSecret); const payload = await jose.jwtVerify(authToken, secretBytes); const { payload: { email } } = payload; const user = await getUserByEmail(supabaseClient, email as string); return user; } catch (error: any) { throw new Error(error.message || "Failed to authenticate user"); } }; /** * Decrypts an encrypted secret with the same master encryption key. * @param encryptedData - base64 string from the database * @param iv - base64 IV from the database * @param masterKey - 32-byte string or buffer * @returns the original plaintext secret */ export function decryptSecret( encryptedData: string, iv: string, masterKey: string, ) { // Decode the base64 master key const decodedKey = Buffer.from(masterKey, "base64"); if (decodedKey.length !== 32) { throw new Error( "ENCRYPTION_KEY must be 32 bytes when decoded from base64.", ); } const decipher = crypto.createDecipheriv( "aes-256-cbc", decodedKey, // Use the decoded key instead of raw masterKey Buffer.from(iv, "base64"), ); let decrypted = decipher.update(encryptedData, "base64", "utf8"); decrypted += decipher.final("utf8"); return decrypted; }