From 2a82f7f9fdcb78058c1181ff19eee4a7c995b947 Mon Sep 17 00:00:00 2001 From: 732642856 <732642856@qq.com> Date: Mon, 20 Jul 2026 01:37:06 +0800 Subject: [PATCH] fix: derive internal dynamic rectification token --- frontend/src/lib/birth-time-dynamic-token.ts | 14 ++++++++++++++ frontend/src/lib/birth-time-journey-engine.ts | 6 +++++- frontend/tests/birth-time-journey-engine.test.ts | 7 +++++++ scripts/jyotish_api_server.py | 6 ++++++ 4 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 frontend/src/lib/birth-time-dynamic-token.ts diff --git a/frontend/src/lib/birth-time-dynamic-token.ts b/frontend/src/lib/birth-time-dynamic-token.ts new file mode 100644 index 00000000..782d2850 --- /dev/null +++ b/frontend/src/lib/birth-time-dynamic-token.ts @@ -0,0 +1,14 @@ +import { createHash } from "node:crypto"; + +export function resolveDynamicRectificationToken( + configuredToken: string | undefined, + serviceRoleKey: string | undefined, +): string | null { + const configured = configuredToken?.trim(); + if (configured) return configured; + const serviceRole = serviceRoleKey?.trim(); + if (!serviceRole) return null; + return createHash("sha256") + .update(`jyotisha-dynamic-rectification-v1:${serviceRole}`) + .digest("hex"); +} diff --git a/frontend/src/lib/birth-time-journey-engine.ts b/frontend/src/lib/birth-time-journey-engine.ts index 7ced28b5..e43ac2e9 100644 --- a/frontend/src/lib/birth-time-journey-engine.ts +++ b/frontend/src/lib/birth-time-journey-engine.ts @@ -5,6 +5,7 @@ import { createJourneyEngineWire, } from "./birth-time-journey-engine-model.ts"; import type { BirthTimeJourneyEngine } from "./birth-time-journey-service.ts"; +import { resolveDynamicRectificationToken } from "./birth-time-dynamic-token.ts"; export { BirthTimeJourneyEngineConfigurationError, @@ -16,7 +17,10 @@ export function createJyotishBirthTimeJourneyEngine( ): BirthTimeJourneyEngine { return createJourneyEngineMethods(createJourneyEngineWire({ apiBase, - dynamicToken: process.env.JYOTISH_DYNAMIC_RECTIFICATION_TOKEN ?? null, + dynamicToken: resolveDynamicRectificationToken( + process.env.JYOTISH_DYNAMIC_RECTIFICATION_TOKEN, + process.env.SUPABASE_SERVICE_ROLE_KEY, + ), fetchImpl: fetch, })); } diff --git a/frontend/tests/birth-time-journey-engine.test.ts b/frontend/tests/birth-time-journey-engine.test.ts index 23c0a124..a5675ab2 100644 --- a/frontend/tests/birth-time-journey-engine.test.ts +++ b/frontend/tests/birth-time-journey-engine.test.ts @@ -9,6 +9,7 @@ import { eventScorePayload, } from "../src/lib/birth-time-journey-engine-model.ts"; import type { JourneyEngineFetch } from "../src/lib/birth-time-journey-engine-model.ts"; +import { resolveDynamicRectificationToken } from "../src/lib/birth-time-dynamic-token.ts"; test("journey engine serializes only stored event-scoring inputs", () => { const payload = eventScorePayload({ @@ -191,6 +192,12 @@ test("missing dynamic token fails both endpoints before fetch", async () => { assert.equal(harness.calls.length, 0); }); +test("dynamic token derives only from a server-side service role fallback", () => { + assert.equal(resolveDynamicRectificationToken("configured-token", "service-role"), "configured-token"); + assert.match(resolveDynamicRectificationToken(undefined, "service-role") ?? "", /^[a-f0-9]{64}$/); + assert.equal(resolveDynamicRectificationToken(undefined, undefined), null); +}); + test("legacy wire calls never receive dynamic authorization", async () => { const calls: { readonly path: string; readonly init: RequestInit }[] = []; const engine = createJourneyEngineMethods(createJourneyEngineWire({ diff --git a/scripts/jyotish_api_server.py b/scripts/jyotish_api_server.py index 12d082a9..c656d8ec 100644 --- a/scripts/jyotish_api_server.py +++ b/scripts/jyotish_api_server.py @@ -1510,6 +1510,12 @@ class JyotishAPIHandler(BaseHTTPRequestHandler): def _require_dynamic_rectification_token(self): configured = os.environ.get('JYOTISH_DYNAMIC_RECTIFICATION_TOKEN', '').strip() + if not configured: + service_role = os.environ.get('SUPABASE_SERVICE_ROLE_KEY', '').strip() + if service_role: + configured = hashlib.sha256( + f'jyotisha-dynamic-rectification-v1:{service_role}'.encode('utf-8') + ).hexdigest() supplied = self._job_access_token() matches = secrets.compare_digest(supplied, configured) if not configured or not matches: