mirror of
https://github.com/logto-io/logto.git
synced 2025-03-17 22:31:28 -05:00
refactor(core): use ENDPOINT
to replace original env urls (#1416)
* refactor(core): use `ENDPOINT` to replace original env urls * refactor(core): log endpoint if needed * refactor: update AC App ID in tests * fix(core): oidc issuer * refactor: remove unnecessary `.toString()`
This commit is contained in:
parent
31886c7e3a
commit
273720ea8c
9 changed files with 55 additions and 20 deletions
|
@ -23,7 +23,11 @@ import initOidc from '@/oidc/init';
|
|||
import initRouter from '@/routes/init';
|
||||
|
||||
const logListening = () => {
|
||||
console.log(chalk.bold(chalk.green(`App is running at ${envSet.values.localhostUrl}`)));
|
||||
const { localhostUrl, endpoint } = envSet.values;
|
||||
|
||||
for (const url of new Set([localhostUrl, endpoint])) {
|
||||
console.log(chalk.bold(chalk.green(`App is running at ${url}`)));
|
||||
}
|
||||
};
|
||||
|
||||
export default async function initApp(app: Koa): Promise<void> {
|
||||
|
|
|
@ -58,7 +58,7 @@ export const insertInto = <T extends SchemaLike>(object: T, table: string) => {
|
|||
`;
|
||||
};
|
||||
|
||||
export const createDatabaseCli = (dsn: string, demoAppUrl: string) => {
|
||||
export const createDatabaseCli = (dsn: string) => {
|
||||
const pool = createPool(dsn, { interceptors: createInterceptors() });
|
||||
|
||||
const createTables = async () => {
|
||||
|
@ -84,7 +84,7 @@ export const createDatabaseCli = (dsn: string, demoAppUrl: string) => {
|
|||
pool.query(insertInto(managementResource, 'resources')),
|
||||
pool.query(insertInto(createDefaultSetting(), 'settings')),
|
||||
pool.query(insertInto(defaultSignInExperience, 'sign_in_experiences')),
|
||||
pool.query(insertInto(createDemoAppApplication([demoAppUrl]), 'applications')),
|
||||
pool.query(insertInto(createDemoAppApplication(), 'applications')),
|
||||
pool.query(insertInto(defaultRole, 'roles')),
|
||||
]);
|
||||
console.log(`${chalk.blue('[seed-tables]')} Seed tables succeeded.`);
|
||||
|
|
|
@ -78,7 +78,7 @@ const inquireForLogtoDsn = async (key: string): Promise<[Optional<string>, boole
|
|||
return initDatabase(dsn);
|
||||
};
|
||||
|
||||
const createPoolByEnv = async (isTest: boolean, demoAppUrl: string) => {
|
||||
const createPoolByEnv = async (isTest: boolean) => {
|
||||
// Database connection is disabled in unit test environment
|
||||
if (isTest) {
|
||||
return;
|
||||
|
@ -102,7 +102,7 @@ const createPoolByEnv = async (isTest: boolean, demoAppUrl: string) => {
|
|||
throw error;
|
||||
}
|
||||
|
||||
const cli = createDatabaseCli(dsn, demoAppUrl);
|
||||
const cli = createDatabaseCli(dsn);
|
||||
|
||||
if (needsSeed) {
|
||||
await cli.createTables();
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import { getEnv, Optional } from '@silverhand/essentials';
|
||||
import { DatabasePool } from 'slonik';
|
||||
|
||||
import { appendPath } from '@/utils/url';
|
||||
|
||||
import createPoolByEnv from './create-pool-by-env';
|
||||
import loadOidcValues from './oidc';
|
||||
|
||||
|
@ -18,6 +20,7 @@ const loadEnvValues = async () => {
|
|||
const isHttpsEnabled = Boolean(process.env.HTTPS_CERT_PATH && process.env.HTTPS_KEY_PATH);
|
||||
const port = Number(getEnv('PORT', '3001'));
|
||||
const localhostUrl = `${isHttpsEnabled ? 'https' : 'http'}://localhost:${port}`;
|
||||
const endpoint = getEnv('ENDPOINT', localhostUrl);
|
||||
|
||||
return Object.freeze({
|
||||
isTest,
|
||||
|
@ -27,10 +30,11 @@ const loadEnvValues = async () => {
|
|||
httpsKey: process.env.HTTPS_KEY_PATH,
|
||||
port,
|
||||
localhostUrl,
|
||||
endpoint,
|
||||
developmentUserId: getEnv('DEVELOPMENT_USER_ID'),
|
||||
trustProxyHeader: getEnv('TRUST_PROXY_HEADER') === 'true',
|
||||
oidc: await loadOidcValues(localhostUrl),
|
||||
adminConsoleUrl: getEnv('ADMIN_CONSOLE_URL', `${localhostUrl}/console`),
|
||||
oidc: await loadOidcValues(appendPath(endpoint, '/oidc').toString()),
|
||||
adminConsoleUrl: appendPath(endpoint, '/console'),
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -63,7 +67,7 @@ function createEnvSet() {
|
|||
|
||||
load: async () => {
|
||||
values = await loadEnvValues();
|
||||
pool = await createPoolByEnv(values.isTest, `${values.localhostUrl}/${MountedApps.DemoApp}`);
|
||||
pool = await createPoolByEnv(values.isTest);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -108,7 +108,7 @@ const readCookieKeys = async (): Promise<string[]> => {
|
|||
);
|
||||
};
|
||||
|
||||
const loadOidcValues = async (defaultUrl: string) => {
|
||||
const loadOidcValues = async (issuer: string) => {
|
||||
const cookieKeys = await readCookieKeys();
|
||||
const privateKey = crypto.createPrivateKey(await readPrivateKey());
|
||||
const publicKey = crypto.createPublicKey(privateKey);
|
||||
|
@ -117,7 +117,7 @@ const loadOidcValues = async (defaultUrl: string) => {
|
|||
cookieKeys,
|
||||
privateKey,
|
||||
publicKey,
|
||||
issuer: getEnv('OIDC_ISSUER', `${defaultUrl}/oidc`),
|
||||
issuer,
|
||||
defaultIdTokenTtl: 60 * 60,
|
||||
defaultRefreshTokenTtl: 14 * 24 * 60 * 60,
|
||||
});
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { ApplicationType, CreateApplication, GrantType } from '@logto/schemas';
|
||||
import { adminConsoleApplicationId } from '@logto/schemas/lib/seeds';
|
||||
import { ApplicationType, CreateApplication, GrantType, OidcClientMetadata } from '@logto/schemas';
|
||||
import { adminConsoleApplicationId, demoAppApplicationId } from '@logto/schemas/lib/seeds';
|
||||
import dayjs from 'dayjs';
|
||||
import { AdapterFactory, AllClientMetadata } from 'oidc-provider';
|
||||
import snakecaseKeys from 'snakecase-keys';
|
||||
|
||||
import envSet from '@/env-set';
|
||||
import envSet, { MountedApps } from '@/env-set';
|
||||
import { findApplicationById } from '@/queries/application';
|
||||
import {
|
||||
consumeInstanceById,
|
||||
|
@ -14,12 +14,15 @@ import {
|
|||
revokeInstanceByGrantId,
|
||||
upsertInstance,
|
||||
} from '@/queries/oidc-model-instance';
|
||||
import { appendPath } from '@/utils/url';
|
||||
|
||||
import { getApplicationTypeString } from './utils';
|
||||
|
||||
const buildAdminConsoleClientMetadata = (): AllClientMetadata => {
|
||||
const { localhostUrl, adminConsoleUrl } = envSet.values;
|
||||
const urls = [...new Set([`${localhostUrl}/console`, adminConsoleUrl])];
|
||||
const urls = [
|
||||
...new Set([appendPath(localhostUrl, '/console').toString(), adminConsoleUrl.toString()]),
|
||||
];
|
||||
|
||||
return {
|
||||
client_id: adminConsoleApplicationId,
|
||||
|
@ -27,11 +30,28 @@ const buildAdminConsoleClientMetadata = (): AllClientMetadata => {
|
|||
application_type: getApplicationTypeString(ApplicationType.SPA),
|
||||
grant_types: Object.values(GrantType),
|
||||
token_endpoint_auth_method: 'none',
|
||||
redirect_uris: urls.map((url) => `${url}/callback`),
|
||||
redirect_uris: urls.map((url) => appendPath(url, '/callback').toString()),
|
||||
post_logout_redirect_uris: urls,
|
||||
};
|
||||
};
|
||||
|
||||
const buildDemoAppUris = (
|
||||
oidcClientMetadata: OidcClientMetadata
|
||||
): Pick<OidcClientMetadata, 'redirectUris' | 'postLogoutRedirectUris'> => {
|
||||
const { localhostUrl, endpoint } = envSet.values;
|
||||
const urls = [
|
||||
appendPath(localhostUrl, MountedApps.DemoApp).toString(),
|
||||
appendPath(endpoint, MountedApps.DemoApp).toString(),
|
||||
];
|
||||
|
||||
const data = {
|
||||
redirectUris: [...new Set([...urls, ...oidcClientMetadata.redirectUris])],
|
||||
postLogoutRedirectUris: [...new Set([...urls, ...oidcClientMetadata.postLogoutRedirectUris])],
|
||||
};
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
export default function postgresAdapter(modelName: string): ReturnType<AdapterFactory> {
|
||||
if (modelName === 'Client') {
|
||||
const reject = async () => Promise.reject(new Error('Not implemented'));
|
||||
|
@ -48,7 +68,10 @@ export default function postgresAdapter(modelName: string): ReturnType<AdapterFa
|
|||
grant_types: Object.values(GrantType),
|
||||
token_endpoint_auth_method: 'none',
|
||||
...snakecaseKeys(oidcClientMetadata),
|
||||
...customClientMetadata, // OIDC Provider won't camelcase custom parameter keys
|
||||
...(client_id === demoAppApplicationId &&
|
||||
snakecaseKeys(buildDemoAppUris(oidcClientMetadata))),
|
||||
// `node-oidc-provider` won't camelCase custom parameter keys, so we need to keep the keys camelCased
|
||||
...customClientMetadata,
|
||||
});
|
||||
|
||||
return {
|
||||
|
|
4
packages/core/src/utils/url.ts
Normal file
4
packages/core/src/utils/url.ts
Normal file
|
@ -0,0 +1,4 @@
|
|||
import path from 'path';
|
||||
|
||||
export const appendPath = (url: URL | string, ...pathnames: string[]): URL =>
|
||||
new URL(path.join(new URL(url).pathname, ...pathnames), url);
|
|
@ -2,7 +2,7 @@ import { getEnv } from '@silverhand/essentials';
|
|||
|
||||
export const logtoUrl = getEnv('LOGTO_URL');
|
||||
|
||||
export const adminConsoleApplicationId = 'admin_console';
|
||||
export const adminConsoleApplicationId = 'admin-console';
|
||||
|
||||
export const discoveryUrl = `${logtoUrl}/oidc/.well-known/openid-configuration`;
|
||||
|
||||
|
|
|
@ -5,14 +5,14 @@ import { ApplicationType, CreateApplication } from '../db-entries';
|
|||
*
|
||||
* This built-in application does not belong to any tenant in the OSS version.
|
||||
*/
|
||||
export const adminConsoleApplicationId = 'admin_console';
|
||||
export const adminConsoleApplicationId = 'admin-console';
|
||||
|
||||
export const demoAppApplicationId = 'demo-app';
|
||||
|
||||
export const createDemoAppApplication = (urls: string[]): Readonly<CreateApplication> => ({
|
||||
export const createDemoAppApplication = (): Readonly<CreateApplication> => ({
|
||||
id: demoAppApplicationId,
|
||||
name: 'Demo App',
|
||||
description: 'Logto demo app.',
|
||||
type: ApplicationType.SPA,
|
||||
oidcClientMetadata: { redirectUris: urls, postLogoutRedirectUris: urls },
|
||||
oidcClientMetadata: { redirectUris: [], postLogoutRedirectUris: [] },
|
||||
});
|
||||
|
|
Loading…
Add table
Reference in a new issue