Forráskód Böngészése

Unify cron secret auth

gpt-engineer-app[bot] 1 napja
szülő
commit
c8df76b43b
1 módosított fájl, 51 hozzáadás és 12 törlés
  1. 51 12
      supabase/functions/_shared/security.ts

+ 51 - 12
supabase/functions/_shared/security.ts

@@ -118,25 +118,64 @@ export async function verifySuperUser(req: Request): Promise<boolean> {
 
 /**
  * Validates a cron job secret for internal service-to-service calls
- * Cron jobs should use a shared secret for authentication
- * SECURITY: Fails closed - requires CRON_SECRET to be configured
+ * ASYNC version: checks env var first, then falls back to app_secrets table
+ * SECURITY: Fails closed - requires secret to be configured somewhere
  */
-export function validateCronSecret(req: Request): boolean {
+export async function validateCronSecret(req: Request): Promise<boolean> {
   const cronSecret = req.headers.get('x-cron-secret');
-  const expectedSecret = Deno.env.get('CRON_SECRET');
   
-  // SECURITY: Fail closed - require explicit configuration
-  if (!expectedSecret) {
-    console.error('CRON_SECRET environment variable not configured - denying access');
+  if (!cronSecret) {
     return false;
   }
-  
-  // Constant-time comparison to prevent timing attacks
-  if (cronSecret?.length !== expectedSecret.length) {
+
+  // 1. Try environment variable first (fastest)
+  const envSecret = Deno.env.get('CRON_SECRET');
+  if (envSecret) {
+    if (cronSecret.length !== envSecret.length) {
+      console.log('validateCronSecret: secret length mismatch (env)');
+      return false;
+    }
+    if (cronSecret === envSecret) {
+      return true;
+    }
+    console.log('validateCronSecret: secret value mismatch (env)');
+    return false;
+  }
+
+  // 2. Fallback: read from app_secrets table via service_role
+  console.log('validateCronSecret: CRON_SECRET not in env, trying app_secrets fallback');
+  try {
+    const supabase = createClient(
+      Deno.env.get('SUPABASE_URL')!,
+      Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!
+    );
+
+    const { data, error } = await supabase
+      .from('app_secrets')
+      .select('value')
+      .eq('key', 'cron_secret')
+      .single();
+
+    if (error || !data?.value) {
+      console.error('validateCronSecret: cron_secret not found in app_secrets either - denying access');
+      return false;
+    }
+
+    const dbSecret = data.value;
+    if (cronSecret.length !== dbSecret.length) {
+      console.log('validateCronSecret: secret length mismatch (db)');
+      return false;
+    }
+    if (cronSecret === dbSecret) {
+      console.log('validateCronSecret: validated via app_secrets fallback');
+      return true;
+    }
+    console.log('validateCronSecret: secret value mismatch (db)');
+    return false;
+  } catch (err) {
+    console.error('validateCronSecret: error reading app_secrets:', err);
     return false;
   }
-  
-  return cronSecret === expectedSecret;
 }
 
 /**