diff --git a/.env.example b/.env.example index 125810d..0e1dbbc 100644 --- a/.env.example +++ b/.env.example @@ -3,7 +3,7 @@ NODE_ENV=production PORT=3000 # Next.js -NEXT_PUBLIC_SITE_URL=https://www.eversolo.com +NEXT_PUBLIC_SITE_URL=https://www.luxsin.net # Payload PAYLOAD_SECRET=replace-me-with-a-long-random-string @@ -20,3 +20,35 @@ SMTP_PASS= SMTP_FROM="Eversolo Website " AFTER_SERVICE_NOTIFY_EMAIL=service@eversolo.com SALES_NOTIFY_EMAIL=sales@eversolo.com + +# Paste-URL allow list (upload fields: media / files / videos) +# Comma-separated hostnames allowed when using "paste URL" in upload fields. +# Bare hostnames default to https; full "protocol://host" entries are also accepted. +# When unset, defaults to: www.eversolo.com,eversolo.com,am.luxsinaudio.com +# NOTE: NEXT_PUBLIC_ prefix required — value is inlined into client bundle at build time. +NEXT_PUBLIC_PASTE_URL_ALLOW_LIST=www.eversolo.com,eversolo.com,am.luxsinaudio.com + +# AWS S3 media uploads (素材库直传 S3 / CloudFront) +# Required: the five keys below must be set or uploads will fail. +FIRMWARE_AWS_ACCESS_KEY_ID= +FIRMWARE_AWS_SECRET_ACCESS_KEY= +FIRMWARE_AWS_BUCKET= +FIRMWARE_AWS_REGION=ap-southeast-1 +FIRMWARE_AWS_CDN_DOMAIN= +# Optional: CDN scheme used to build public URLs (http | https, default http). +FIRMWARE_AWS_CDN_SCHEME=https +# Optional: CloudFront distribution id; when set, CDN cache is invalidated after uploads. +FIRMWARE_AWS_CLOUDFRONT_DISTRIBUTION_ID= +# Optional: S3 key prefixes. "folder" stores category/target uploads, "customFolder" stores custom-dir uploads. +FIRMWARE_AWS_FOLDER=mediaassets +FIRMWARE_AWS_CUSTOM_FOLDER=webassets +# Optional: set true when the bucket uses public-read ACL (default false). +FIRMWARE_AWS_PUBLIC_ACL=false +# Optional: max upload size in MB (default 2048). +FIRMWARE_MAX_SIZE_MB=2048 +# Optional: multipart tuning. Files larger than the threshold are uploaded in parts. +FIRMWARE_AWS_MULTIPART_THRESHOLD_MB=32 +FIRMWARE_AWS_MULTIPART_PART_SIZE_MB=16 +FIRMWARE_AWS_MULTIPART_CONCURRENCY=4 +# Optional: presigned URL lifetime in seconds (default 3600, max 604800). +FIRMWARE_UPLOAD_TOKEN_TTL_SECONDS=3600 diff --git a/Dockerfile b/Dockerfile index 3c39f9d..ef6ea88 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,10 +14,12 @@ COPY . . RUN mkdir -p public ARG NEXT_PUBLIC_SITE_URL +ARG NEXT_PUBLIC_PASTE_URL_ALLOW_LIST ARG PAYLOAD_SECRET ARG DATABASE_URI ENV NEXT_PUBLIC_SITE_URL=$NEXT_PUBLIC_SITE_URL +ENV NEXT_PUBLIC_PASTE_URL_ALLOW_LIST=$NEXT_PUBLIC_PASTE_URL_ALLOW_LIST ENV PAYLOAD_SECRET=$PAYLOAD_SECRET ENV DATABASE_URI=$DATABASE_URI ENV NODE_ENV=production diff --git a/docker-compose.yml b/docker-compose.yml index 18a7ec3..c233ef9 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,6 +6,7 @@ services: # Enable BuildKit layer/cache mounts: DOCKER_BUILDKIT=1 docker compose build app args: NEXT_PUBLIC_SITE_URL: ${NEXT_PUBLIC_SITE_URL} + NEXT_PUBLIC_PASTE_URL_ALLOW_LIST: ${NEXT_PUBLIC_PASTE_URL_ALLOW_LIST} PAYLOAD_SECRET: ${PAYLOAD_SECRET} DATABASE_URI: ${DATABASE_URI} container_name: eversolo-web diff --git a/src/app/(payload)/admin/_components/eversolo-paste-url-fetch-provider.tsx b/src/app/(payload)/admin/_components/eversolo-paste-url-fetch-provider.tsx index dadc74e..83220ca 100644 --- a/src/app/(payload)/admin/_components/eversolo-paste-url-fetch-provider.tsx +++ b/src/app/(payload)/admin/_components/eversolo-paste-url-fetch-provider.tsx @@ -2,7 +2,13 @@ import { useEffect } from 'react' -const allowedHosts = new Set(['www.eversolo.com', 'eversolo.com']) +const DEFAULT_PASTE_HOSTS = 'www.eversolo.com,eversolo.com,am.luxsinaudio.com' +const allowedHosts = new Set( + (process.env.NEXT_PUBLIC_PASTE_URL_ALLOW_LIST || DEFAULT_PASTE_HOSTS) + .split(',') + .map((h) => h.trim().replace(/^https?:\/\//i, '').replace(/\/.*$/, '')) + .filter(Boolean), +) const proxyPath = '/api/eversolo-paste-url' const pasteFetchCollectDelay = 300 const pasteFetchIdleReleaseDelay = 250 diff --git a/src/payload/upload-paste-url-allow-list.ts b/src/payload/upload-paste-url-allow-list.ts index b3af2ec..2d8c0f0 100644 --- a/src/payload/upload-paste-url-allow-list.ts +++ b/src/payload/upload-paste-url-allow-list.ts @@ -1,12 +1,29 @@ import type { AllowList } from 'payload' -export const eversoloPasteURLAllowList: AllowList = [ - { - hostname: 'www.eversolo.com', - protocol: 'https', - }, - { - hostname: 'eversolo.com', - protocol: 'https', - }, -] +/** + * Paste-URL allow list for upload fields (media / files / videos). + * + * Configure via the NEXT_PUBLIC_PASTE_URL_ALLOW_LIST environment variable: + * - Comma-separated hostnames, e.g. "www.eversolo.com,am.luxsinaudio.com" + * - Bare hostnames default to https; you may also pass full "protocol://host" entries. + * - When the variable is unset or empty, the built-in defaults below are used. + * + * NOTE: NEXT_PUBLIC_ prefix is required so the client-side fetch interceptor + * can also read this value at build time. + */ +const DEFAULT_HOSTS = ['www.eversolo.com', 'eversolo.com', 'am.luxsinaudio.com'] + +function buildAllowList(): AllowList { + const raw = (process.env.NEXT_PUBLIC_PASTE_URL_ALLOW_LIST || '').trim() + const entries = raw ? raw.split(',').map((item) => item.trim()).filter(Boolean) : DEFAULT_HOSTS + + return entries.map((entry) => { + if (/^https?:\/\//i.test(entry)) { + const url = new URL(entry) + return { hostname: url.hostname, protocol: url.protocol.replace(':', '') as 'http' | 'https' } + } + return { hostname: entry, protocol: 'https' as const } + }) +} + +export const eversoloPasteURLAllowList: AllowList = buildAllowList()