From 22dad6d0fcae6e0a0e4f5aece6734a2adc59632e Mon Sep 17 00:00:00 2001 From: Kelly Date: Wed, 10 Dec 2025 15:21:13 -0700 Subject: [PATCH] feat: Add wildcard trusted origins for cannaiq.co and cannabrands.app MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add *.cannaiq.co and *.cannabrands.app patterns to both: - auth/middleware.ts (admin routes) - public-api.ts (consumer /api/v1/* routes) This allows any subdomain of these domains to access the API without requiring an API key. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- backend/src/auth/middleware.ts | 1 + backend/src/routes/public-api.ts | 31 +++++++++++++++++++++++++++++-- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/backend/src/auth/middleware.ts b/backend/src/auth/middleware.ts index 15e82d53..1a7aec9c 100755 --- a/backend/src/auth/middleware.ts +++ b/backend/src/auth/middleware.ts @@ -32,6 +32,7 @@ const TRUSTED_ORIGINS = [ // Pattern-based trusted origins (wildcards) const TRUSTED_ORIGIN_PATTERNS = [ /^https:\/\/.*\.cannabrands\.app$/, // *.cannabrands.app + /^https:\/\/.*\.cannaiq\.co$/, // *.cannaiq.co ]; // Trusted IPs for internal pod-to-pod communication diff --git a/backend/src/routes/public-api.ts b/backend/src/routes/public-api.ts index 7179fa8b..61265ca1 100644 --- a/backend/src/routes/public-api.ts +++ b/backend/src/routes/public-api.ts @@ -130,6 +130,12 @@ const CONSUMER_TRUSTED_ORIGINS = [ 'http://localhost:3002', ]; +// Wildcard trusted origin patterns (*.domain.com) +const CONSUMER_TRUSTED_PATTERNS = [ + /^https:\/\/([a-z0-9-]+\.)?cannaiq\.co$/, + /^https:\/\/([a-z0-9-]+\.)?cannabrands\.app$/, +]; + // Trusted IPs for local development (bypass API key auth) const TRUSTED_IPS = ['127.0.0.1', '::1', '::ffff:127.0.0.1']; @@ -150,8 +156,17 @@ function isConsumerTrustedRequest(req: Request): boolean { return true; } const origin = req.headers.origin; - if (origin && CONSUMER_TRUSTED_ORIGINS.includes(origin)) { - return true; + if (origin) { + // Check exact matches + if (CONSUMER_TRUSTED_ORIGINS.includes(origin)) { + return true; + } + // Check wildcard patterns + for (const pattern of CONSUMER_TRUSTED_PATTERNS) { + if (pattern.test(origin)) { + return true; + } + } } const referer = req.headers.referer; if (referer) { @@ -160,6 +175,18 @@ function isConsumerTrustedRequest(req: Request): boolean { return true; } } + // Check wildcard patterns against referer origin + try { + const refererUrl = new URL(referer); + const refererOrigin = refererUrl.origin; + for (const pattern of CONSUMER_TRUSTED_PATTERNS) { + if (pattern.test(refererOrigin)) { + return true; + } + } + } catch { + // Invalid referer URL, ignore + } } return false; }