From 1c2766be893feaed35413025bb092e2cc565e15a Mon Sep 17 00:00:00 2001 From: Gao Sun Date: Wed, 22 Feb 2023 12:38:30 +0800 Subject: [PATCH] refactor: fix cloud env (#3179) --- Dockerfile | 18 +++++++------- Dockerfile.cloud | 31 +++++++++++++++--------- package.json | 1 + packages/cloud/package.json | 2 +- packages/cloud/src/env-set/index.ts | 5 +++- packages/core/package.json | 2 +- packages/core/src/middleware/koa-cors.ts | 22 ++++++++++++----- packages/core/src/oidc/adapter.ts | 8 +++--- 8 files changed, 57 insertions(+), 32 deletions(-) diff --git a/Dockerfile b/Dockerfile index 5ce463653..9a6e2d1fe 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,34 +1,34 @@ -# Build stage +###### [STAGE] Build ###### FROM node:18-alpine as builder WORKDIR /etc/logto ENV CI=true -# No need for build +# No need for Docker build ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true -# Install toolchain +### Install toolchain ### RUN npm add --location=global pnpm@^7.14.0 # https://github.com/nodejs/docker-node/blob/main/docs/BestPractices.md#node-gyp-alpine RUN apk add --no-cache python3 make g++ COPY . . -# Install dependencies and build +### Install dependencies and build ### RUN node .scripts/update-parcelrc.js RUN pnpm i RUN pnpm -r build -# Add official connectors +### Add official connectors ### RUN pnpm cli connector add --official -p . -# Prune dependencies for production +### Prune dependencies for production ### RUN rm -rf node_modules packages/**/node_modules RUN NODE_ENV=production pnpm i -# Clean up -RUN rm -rf .scripts .parcel-cache pnpm-*.yaml +### Clean up ### +RUN rm -rf .scripts .parcel-cache pnpm-*.yaml packages/cloud -# Seal stage +###### [STAGE] Seal ###### FROM node:18-alpine as app WORKDIR /etc/logto COPY --from=builder /etc/logto . diff --git a/Dockerfile.cloud b/Dockerfile.cloud index 34d813d6c..39d282d66 100644 --- a/Dockerfile.cloud +++ b/Dockerfile.cloud @@ -1,31 +1,40 @@ -# Build stage +###### [STAGE] Build ###### FROM node:18-alpine as builder WORKDIR /etc/logto ENV CI=true -# No need for build +# No need for Docker build ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true -# Install toolchain +### Install toolchain ### RUN npm add --location=global pnpm@^7.14.0 # https://github.com/nodejs/docker-node/blob/main/docs/BestPractices.md#node-gyp-alpine RUN apk add --no-cache python3 make g++ COPY . . -# Install dependencies and build +### Install dependencies ### RUN node .scripts/update-parcelrc.js RUN pnpm i -RUN pnpm prepack -RUN cd packages/cloud && pnpm build -# Prune dependencies for production +### Build ### +# Admin Console build env +ENV CONSOLE_PUBLIC_URL=/ +# Temporarily use it for Admin Console build, will try to use runtime technique later +ENV ADMIN_TENANT_ENDPOINT=https://admin.app.logto.dev/ +RUN pnpm prepack +RUN pnpm -r --filter @logto/console --filter @logto/cloud build + +### Prune dependencies for production ### RUN rm -rf node_modules packages/**/node_modules RUN NODE_ENV=production pnpm i -# Seal stage +### Clean up ### +RUN rm -rf .scripts .parcel-cache pnpm-*.yaml + +###### [STAGE] Seal ###### FROM node:18-alpine as app -WORKDIR /etc/logto -COPY --from=builder /etc/logto/packages/cloud . +WORKDIR /etc/logto-cloud +COPY --from=builder /etc/logto . EXPOSE 3003 -ENTRYPOINT ["npm", "start"] +ENTRYPOINT ["npm", "run", "start:cloud"] diff --git a/package.json b/package.json index d35dfa86e..f29737989 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "start:dev": "pnpm -r --parallel --filter=!@logto/integration-tests --filter=!@logto/cloud dev", "start:dev:cloud": "CONSOLE_PUBLIC_URL=/ pnpm -r --parallel --filter=!@logto/integration-tests dev", "start": "cd packages/core && NODE_ENV=production node .", + "start:cloud": "cd packages/cloud && NODE_ENV=production node .", "cli": "logto", "alteration": "logto db alt", "//": "# `changeset version` won't run version lifecycle scripts, see https://github.com/changesets/changesets/issues/860", diff --git a/packages/cloud/package.json b/packages/cloud/package.json index 6728636f3..cf325e10e 100644 --- a/packages/cloud/package.json +++ b/packages/cloud/package.json @@ -16,7 +16,7 @@ "lint": "eslint --ext .ts src", "lint:report": "pnpm lint --format json --output-file report.json", "dev": "rm -rf build/ && nodemon", - "start": "NODE_ENV=production node build/index.js" + "start": "NODE_ENV=production node ." }, "dependencies": { "@logto/core-kit": "workspace:*", diff --git a/packages/cloud/src/env-set/index.ts b/packages/cloud/src/env-set/index.ts index aab43c73d..13bdcee1e 100644 --- a/packages/cloud/src/env-set/index.ts +++ b/packages/cloud/src/env-set/index.ts @@ -1,7 +1,10 @@ const getEnv = (key: string) => process.env[key]; class GlobalValues { - public readonly logtoEndpoint = new URL(getEnv('LOGTO_ENDPOINT') ?? 'http://localhost:3002'); + public readonly logtoEndpoint = new URL( + getEnv('ADMIN_TENANT_ENDPOINT') ?? 'http://localhost:3002' + ); + public readonly dbUrl = getEnv('DB_URL'); public readonly isProduction = getEnv('NODE_ENV') === 'production'; } diff --git a/packages/core/package.json b/packages/core/package.json index b85deca41..d8360ffc8 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -18,7 +18,7 @@ "lint": "eslint --ext .ts src", "lint:report": "pnpm lint --format json --output-file report.json", "dev": "rm -rf build/ && pnpm run copyfiles && nodemon", - "start": "NODE_ENV=production node build/index.js", + "start": "NODE_ENV=production node .", "test:only": "NODE_OPTIONS=\"--experimental-vm-modules --max_old_space_size=4096\" jest --logHeapUsage", "test": "pnpm build:test && pnpm test:only", "test:ci": "pnpm test:only --coverage --silent", diff --git a/packages/core/src/middleware/koa-cors.ts b/packages/core/src/middleware/koa-cors.ts index a05fff924..41fa02883 100644 --- a/packages/core/src/middleware/koa-cors.ts +++ b/packages/core/src/middleware/koa-cors.ts @@ -2,6 +2,7 @@ import cors from '@koa/cors'; import type { MiddlewareType } from 'koa'; import type UrlSet from '#src/env-set/UrlSet.js'; +import { EnvSet } from '#src/env-set/index.js'; export default function koaCors( ...urlSets: UrlSet[] @@ -10,12 +11,21 @@ export default function koaCors( origin: (ctx) => { const { origin } = ctx.request.headers; - return origin && - urlSets - .flatMap((set) => set.deduplicated()) - .some((value) => new URL(value).origin === origin) - ? origin - : ''; + if ( + origin && + urlSets.some((set) => + set.deduplicated().some( + (url) => + url.origin === origin && + // Disable localhost CORS in production since it's unsafe + !(EnvSet.values.isProduction && url.hostname === 'localhost') + ) + ) + ) { + return origin; + } + + return ''; }, exposeHeaders: '*', }); diff --git a/packages/core/src/oidc/adapter.ts b/packages/core/src/oidc/adapter.ts index ee079f702..e5da0f2e3 100644 --- a/packages/core/src/oidc/adapter.ts +++ b/packages/core/src/oidc/adapter.ts @@ -15,9 +15,11 @@ import { getConstantClientMetadata } from './utils.js'; const buildAdminConsoleClientMetadata = (envSet: EnvSet): AllClientMetadata => { const { adminUrlSet, cloudUrlSet } = EnvSet.values; - const urls = [...adminUrlSet.deduplicated(), ...cloudUrlSet.deduplicated()].map((url) => - appendPath(url, '/console').toString() - ); + const urls = [ + ...adminUrlSet.deduplicated().map((url) => appendPath(url, '/console').toString()), + // Logto Cloud uses `https://some.cloud.endpoint/[tenantId]` to serve Admin Console for specific Tenant ID + ...cloudUrlSet.deduplicated().map((url) => appendPath(url, '/' + envSet.tenantId).toString()), + ]; return { ...getConstantClientMetadata(envSet, ApplicationType.SPA),