Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0982be2f58 | |||
| ff70278be4 | |||
| 5171669d4d | |||
| 5f0d5c0e72 | |||
| 5541c0553c | |||
| 172730cf0f | |||
| 9ccce7cbfd |
@@ -52,6 +52,10 @@ services:
|
|||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
environment:
|
environment:
|
||||||
NODE_ENV: production
|
NODE_ENV: production
|
||||||
|
# Docker sets HOSTNAME=<container-id>, and the Next.js standalone server binds to
|
||||||
|
# exactly that one interface - localhost (healthcheck) and the container's other
|
||||||
|
# network addresses then answer with ECONNREFUSED.
|
||||||
|
HOSTNAME: "0.0.0.0"
|
||||||
DATABASE_URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}?schema=public
|
DATABASE_URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}?schema=public
|
||||||
DIRECT_URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}?schema=public
|
DIRECT_URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}?schema=public
|
||||||
REDIS_URL: redis://redis:6379
|
REDIS_URL: redis://redis:6379
|
||||||
@@ -129,7 +133,10 @@ services:
|
|||||||
context: ./scripts/social-worker
|
context: ./scripts/social-worker
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
environment:
|
environment:
|
||||||
QRMASTER_API_BASE: http://web:3000
|
# Container name, not the `web` service alias: the staging stack joins this same
|
||||||
|
# external network and registers `web` as an alias too, so the alias can resolve
|
||||||
|
# to the staging app - which has a different INTERNAL_API_SECRET and answers 401.
|
||||||
|
QRMASTER_API_BASE: http://qrmaster-web:3000
|
||||||
INTERNAL_API_SECRET: ${INTERNAL_API_SECRET}
|
INTERNAL_API_SECRET: ${INTERNAL_API_SECRET}
|
||||||
SOCIAL_MILESTONE_POSTING_ENABLED: ${SOCIAL_MILESTONE_POSTING_ENABLED:-false}
|
SOCIAL_MILESTONE_POSTING_ENABLED: ${SOCIAL_MILESTONE_POSTING_ENABLED:-false}
|
||||||
SOCIAL_WORKER_INTERVAL_SECONDS: ${SOCIAL_WORKER_INTERVAL_SECONDS:-10}
|
SOCIAL_WORKER_INTERVAL_SECONDS: ${SOCIAL_WORKER_INTERVAL_SECONDS:-10}
|
||||||
@@ -149,7 +156,9 @@ services:
|
|||||||
SOCIAL_ASSET_ADMIN_KEY: ${SOCIAL_ASSET_ADMIN_KEY:-${TIKTOK_ADMIN_KEY:-}}
|
SOCIAL_ASSET_ADMIN_KEY: ${SOCIAL_ASSET_ADMIN_KEY:-${TIKTOK_ADMIN_KEY:-}}
|
||||||
depends_on:
|
depends_on:
|
||||||
web:
|
web:
|
||||||
condition: service_started
|
# Not service_started: the worker's first cycle would otherwise run while web is
|
||||||
|
# still applying migrations and booting, logging a connection error per channel.
|
||||||
|
condition: service_healthy
|
||||||
networks:
|
networks:
|
||||||
- qrmaster-network
|
- qrmaster-network
|
||||||
|
|
||||||
|
|||||||
@@ -5,9 +5,13 @@ import { isSocialChannel, SOCIAL_CHANNELS, SocialChannel } from '@/lib/social-mi
|
|||||||
|
|
||||||
export const dynamic = 'force-dynamic';
|
export const dynamic = 'force-dynamic';
|
||||||
|
|
||||||
|
// The worker trims its own copy of the secret before sending it, so a stray
|
||||||
|
// trailing space or CR in the compose env file would otherwise show up here as a
|
||||||
|
// permanent 401 while both sides still look identical in a hash comparison.
|
||||||
function isAuthorized(request: NextRequest) {
|
function isAuthorized(request: NextRequest) {
|
||||||
const secret = process.env.INTERNAL_API_SECRET;
|
const secret = process.env.INTERNAL_API_SECRET?.trim();
|
||||||
return Boolean(secret) && request.headers.get('authorization') === `Bearer ${secret}`;
|
const presented = request.headers.get('authorization')?.trim().replace(/^Bearer\s+/i, '');
|
||||||
|
return Boolean(secret) && presented === secret;
|
||||||
}
|
}
|
||||||
|
|
||||||
function approvalDelayHours() {
|
function approvalDelayHours() {
|
||||||
|
|||||||
Reference in New Issue
Block a user