0
Fork 0
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:
Gao Sun 2022-07-05 18:01:49 +08:00 committed by GitHub
parent 31886c7e3a
commit 273720ea8c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 55 additions and 20 deletions

View file

@ -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> {

View file

@ -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.`);

View file

@ -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();

View file

@ -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);
},
};
}

View file

@ -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,
});

View file

@ -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 {

View 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);

View file

@ -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`;

View file

@ -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: [] },
});