mirror of
https://github.com/logto-io/logto.git
synced 2025-02-17 22:04:19 -05:00
refactor(core): refactor
This commit is contained in:
parent
0f0247ce2f
commit
f4a812ae8a
7 changed files with 57 additions and 35 deletions
|
@ -34,6 +34,7 @@ const logtoConfigs: LogtoConfigLibrary = {
|
||||||
resource: 'resource',
|
resource: 'resource',
|
||||||
}),
|
}),
|
||||||
getOidcConfigs: jest.fn(),
|
getOidcConfigs: jest.fn(),
|
||||||
|
upsertJwtCustomizer: jest.fn(),
|
||||||
};
|
};
|
||||||
|
|
||||||
describe('getAccessToken()', () => {
|
describe('getAccessToken()', () => {
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
import type { LogtoOidcConfigType } from '@logto/schemas';
|
|
||||||
import {
|
import {
|
||||||
cloudApiIndicator,
|
cloudApiIndicator,
|
||||||
cloudConnectionDataGuard,
|
cloudConnectionDataGuard,
|
||||||
logtoOidcConfigGuard,
|
logtoOidcConfigGuard,
|
||||||
LogtoOidcConfigKey,
|
LogtoOidcConfigKey,
|
||||||
|
jwtCustomizerConfigGuard,
|
||||||
} from '@logto/schemas';
|
} from '@logto/schemas';
|
||||||
|
import type { LogtoOidcConfigType, LogtoJwtTokenKey } from '@logto/schemas';
|
||||||
import chalk from 'chalk';
|
import chalk from 'chalk';
|
||||||
import { z, ZodError } from 'zod';
|
import { z, ZodError } from 'zod';
|
||||||
|
|
||||||
|
@ -14,7 +15,11 @@ import { consoleLog } from '#src/utils/console.js';
|
||||||
export type LogtoConfigLibrary = ReturnType<typeof createLogtoConfigLibrary>;
|
export type LogtoConfigLibrary = ReturnType<typeof createLogtoConfigLibrary>;
|
||||||
|
|
||||||
export const createLogtoConfigLibrary = ({
|
export const createLogtoConfigLibrary = ({
|
||||||
logtoConfigs: { getRowsByKeys, getCloudConnectionData: queryCloudConnectionData },
|
logtoConfigs: {
|
||||||
|
getRowsByKeys,
|
||||||
|
getCloudConnectionData: queryCloudConnectionData,
|
||||||
|
upsertJwtCustomizer: queryUpsertJwtCustomizer,
|
||||||
|
},
|
||||||
}: Pick<Queries, 'logtoConfigs'>) => {
|
}: Pick<Queries, 'logtoConfigs'>) => {
|
||||||
const getOidcConfigs = async (): Promise<LogtoOidcConfigType> => {
|
const getOidcConfigs = async (): Promise<LogtoOidcConfigType> => {
|
||||||
try {
|
try {
|
||||||
|
@ -59,5 +64,18 @@ export const createLogtoConfigLibrary = ({
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
return { getOidcConfigs, getCloudConnectionData };
|
// Can not narrow down the type of value if we utilize `buildInsertIntoWithPool` method.
|
||||||
|
const upsertJwtCustomizer = async <T extends LogtoJwtTokenKey>(
|
||||||
|
key: T,
|
||||||
|
value: z.infer<(typeof jwtCustomizerConfigGuard)[T]>
|
||||||
|
) => {
|
||||||
|
const { value: rawValue } = await queryUpsertJwtCustomizer(key, value);
|
||||||
|
|
||||||
|
return {
|
||||||
|
key,
|
||||||
|
value: jwtCustomizerConfigGuard[key].parse(rawValue),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
return { getOidcConfigs, getCloudConnectionData, upsertJwtCustomizer };
|
||||||
};
|
};
|
||||||
|
|
|
@ -57,6 +57,7 @@ const cloudConnection = createCloudConnectionLibrary({
|
||||||
resource: 'resource',
|
resource: 'resource',
|
||||||
}),
|
}),
|
||||||
getOidcConfigs: jest.fn(),
|
getOidcConfigs: jest.fn(),
|
||||||
|
upsertJwtCustomizer: jest.fn(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const getLogtoConnectors = jest.spyOn(connectorLibrary, 'getLogtoConnectors');
|
const getLogtoConnectors = jest.spyOn(connectorLibrary, 'getLogtoConnectors');
|
||||||
|
|
|
@ -92,27 +92,34 @@ export const isGuardMiddleware = <Type extends IMiddleware>(
|
||||||
): function_ is WithGuardConfig<Type> =>
|
): function_ is WithGuardConfig<Type> =>
|
||||||
function_.name === 'guardMiddleware' && has(function_, 'config');
|
function_.name === 'guardMiddleware' && has(function_, 'config');
|
||||||
|
|
||||||
export function tryParse<Output, Definition extends ZodTypeDef, Input>(
|
/**
|
||||||
|
* Previous `tryParse` function's output type was `Output | undefined`.
|
||||||
|
* It can not properly infer the output type to be `Output` even if the guard is provided,
|
||||||
|
* which brings additional but unnecessary type checks.
|
||||||
|
*/
|
||||||
|
export const parse = <Output, Definition extends ZodTypeDef, Input>(
|
||||||
type: 'query' | 'body' | 'params' | 'files',
|
type: 'query' | 'body' | 'params' | 'files',
|
||||||
guard: ZodType<Output, Definition, Input>,
|
guard: ZodType<Output, Definition, Input>,
|
||||||
data: unknown
|
data: unknown
|
||||||
): Output;
|
) => {
|
||||||
export function tryParse<Output, Definition extends ZodTypeDef, Input>(
|
|
||||||
type: 'query' | 'body' | 'params' | 'files',
|
|
||||||
guard: undefined,
|
|
||||||
data: unknown
|
|
||||||
): undefined;
|
|
||||||
export function tryParse<Output, Definition extends ZodTypeDef, Input>(
|
|
||||||
type: 'query' | 'body' | 'params' | 'files',
|
|
||||||
guard: Optional<ZodType<Output, Definition, Input>>,
|
|
||||||
data: unknown
|
|
||||||
) {
|
|
||||||
try {
|
try {
|
||||||
return guard?.parse(data);
|
return guard.parse(data);
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
throw new RequestError({ code: 'guard.invalid_input', type }, error);
|
throw new RequestError({ code: 'guard.invalid_input', type }, error);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
|
const tryParse = <Output, Definition extends ZodTypeDef, Input>(
|
||||||
|
type: 'query' | 'body' | 'params' | 'files',
|
||||||
|
guard: Optional<ZodType<Output, Definition, Input>>,
|
||||||
|
data: unknown
|
||||||
|
) => {
|
||||||
|
if (!guard) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return parse(type, guard, data);
|
||||||
|
};
|
||||||
|
|
||||||
export default function koaGuard<
|
export default function koaGuard<
|
||||||
StateT,
|
StateT,
|
||||||
|
|
|
@ -8,7 +8,6 @@ import {
|
||||||
type LogtoOidcConfigKey,
|
type LogtoOidcConfigKey,
|
||||||
type OidcConfigKey,
|
type OidcConfigKey,
|
||||||
type LogtoJwtTokenKey,
|
type LogtoJwtTokenKey,
|
||||||
type JwtCustomizerType,
|
|
||||||
} from '@logto/schemas';
|
} from '@logto/schemas';
|
||||||
import { convertToIdentifiers } from '@logto/shared';
|
import { convertToIdentifiers } from '@logto/shared';
|
||||||
import type { CommonQueryMethods } from 'slonik';
|
import type { CommonQueryMethods } from 'slonik';
|
||||||
|
@ -57,7 +56,7 @@ export const createLogtoConfigQueries = (pool: CommonQueryMethods) => {
|
||||||
key: T,
|
key: T,
|
||||||
value: z.infer<(typeof jwtCustomizerConfigGuard)[T]>
|
value: z.infer<(typeof jwtCustomizerConfigGuard)[T]>
|
||||||
) =>
|
) =>
|
||||||
pool.one<{ key: T; value: JwtCustomizerType[T] }>(
|
pool.one<{ key: T; value: Record<string, string> }>(
|
||||||
sql`
|
sql`
|
||||||
insert into ${table} (${fields.key}, ${fields.value})
|
insert into ${table} (${fields.key}, ${fields.value})
|
||||||
values (${key}, ${sql.jsonb(value)})
|
values (${key}, ${sql.jsonb(value)})
|
||||||
|
|
|
@ -54,7 +54,7 @@ const logtoConfigQueries = {
|
||||||
}),
|
}),
|
||||||
updateOidcConfigsByKey: jest.fn(),
|
updateOidcConfigsByKey: jest.fn(),
|
||||||
getRowsByKeys: jest.fn(async () => mockLogtoConfigRows),
|
getRowsByKeys: jest.fn(async () => mockLogtoConfigRows),
|
||||||
upsertJwtCustomizer: jest.fn(),
|
// UpsertJwtCustomizer: jest.fn(),
|
||||||
};
|
};
|
||||||
|
|
||||||
const logtoConfigLibraries = {
|
const logtoConfigLibraries = {
|
||||||
|
@ -62,6 +62,7 @@ const logtoConfigLibraries = {
|
||||||
[LogtoOidcConfigKey.PrivateKeys]: mockPrivateKeys,
|
[LogtoOidcConfigKey.PrivateKeys]: mockPrivateKeys,
|
||||||
[LogtoOidcConfigKey.CookieKeys]: mockCookieKeys,
|
[LogtoOidcConfigKey.CookieKeys]: mockCookieKeys,
|
||||||
})),
|
})),
|
||||||
|
upsertJwtCustomizer: jest.fn(),
|
||||||
};
|
};
|
||||||
|
|
||||||
const settingRoutes = await pickDefault(import('./logto-config.js'));
|
const settingRoutes = await pickDefault(import('./logto-config.js'));
|
||||||
|
@ -232,13 +233,13 @@ describe('configs routes', () => {
|
||||||
rows: [],
|
rows: [],
|
||||||
rowCount: 0,
|
rowCount: 0,
|
||||||
});
|
});
|
||||||
logtoConfigQueries.upsertJwtCustomizer.mockResolvedValueOnce(
|
logtoConfigLibraries.upsertJwtCustomizer.mockResolvedValueOnce(
|
||||||
mockJwtCustomizerConfigForAccessToken
|
mockJwtCustomizerConfigForAccessToken
|
||||||
);
|
);
|
||||||
const response = await routeRequester
|
const response = await routeRequester
|
||||||
.put(`/configs/jwt-customizer/access-token`)
|
.put(`/configs/jwt-customizer/access-token`)
|
||||||
.send(mockJwtCustomizerConfigForAccessToken.value);
|
.send(mockJwtCustomizerConfigForAccessToken.value);
|
||||||
expect(logtoConfigQueries.upsertJwtCustomizer).toHaveBeenCalledWith(
|
expect(logtoConfigLibraries.upsertJwtCustomizer).toHaveBeenCalledWith(
|
||||||
LogtoJwtTokenKey.AccessToken,
|
LogtoJwtTokenKey.AccessToken,
|
||||||
mockJwtCustomizerConfigForAccessToken.value
|
mockJwtCustomizerConfigForAccessToken.value
|
||||||
);
|
);
|
||||||
|
@ -252,13 +253,13 @@ describe('configs routes', () => {
|
||||||
rows: [mockJwtCustomizerConfigForAccessToken],
|
rows: [mockJwtCustomizerConfigForAccessToken],
|
||||||
rowCount: 1,
|
rowCount: 1,
|
||||||
});
|
});
|
||||||
logtoConfigQueries.upsertJwtCustomizer.mockResolvedValueOnce(
|
logtoConfigLibraries.upsertJwtCustomizer.mockResolvedValueOnce(
|
||||||
mockJwtCustomizerConfigForAccessToken
|
mockJwtCustomizerConfigForAccessToken
|
||||||
);
|
);
|
||||||
const response = await routeRequester
|
const response = await routeRequester
|
||||||
.put('/configs/jwt-customizer/access-token')
|
.put('/configs/jwt-customizer/access-token')
|
||||||
.send(mockJwtCustomizerConfigForAccessToken.value);
|
.send(mockJwtCustomizerConfigForAccessToken.value);
|
||||||
expect(logtoConfigQueries.upsertJwtCustomizer).toHaveBeenCalledWith(
|
expect(logtoConfigLibraries.upsertJwtCustomizer).toHaveBeenCalledWith(
|
||||||
LogtoJwtTokenKey.AccessToken,
|
LogtoJwtTokenKey.AccessToken,
|
||||||
mockJwtCustomizerConfigForAccessToken.value
|
mockJwtCustomizerConfigForAccessToken.value
|
||||||
);
|
);
|
||||||
|
|
|
@ -19,7 +19,7 @@ import {
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
import RequestError from '#src/errors/RequestError/index.js';
|
import RequestError from '#src/errors/RequestError/index.js';
|
||||||
import koaGuard, { tryParse } from '#src/middleware/koa-guard.js';
|
import koaGuard, { parse } from '#src/middleware/koa-guard.js';
|
||||||
import { exportJWK } from '#src/utils/jwks.js';
|
import { exportJWK } from '#src/utils/jwks.js';
|
||||||
|
|
||||||
import type { AuthedRouter, RouterInitArgs } from './types.js';
|
import type { AuthedRouter, RouterInitArgs } from './types.js';
|
||||||
|
@ -41,12 +41,12 @@ const getJwtTokenKeyAndBody = (tokenPath: LogtoJwtTokenPath, body: unknown) => {
|
||||||
if (tokenPath === LogtoJwtTokenPath.AccessToken) {
|
if (tokenPath === LogtoJwtTokenPath.AccessToken) {
|
||||||
return {
|
return {
|
||||||
key: LogtoJwtTokenKey.AccessToken,
|
key: LogtoJwtTokenKey.AccessToken,
|
||||||
body: tryParse('body', jwtCustomizerAccessTokenGuard, body),
|
body: parse('body', jwtCustomizerAccessTokenGuard, body),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
key: LogtoJwtTokenKey.ClientCredentials,
|
key: LogtoJwtTokenKey.ClientCredentials,
|
||||||
body: tryParse('body', jwtCustomizerClientCredentialsGuard, body),
|
body: parse('body', jwtCustomizerClientCredentialsGuard, body),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -81,14 +81,9 @@ const getRedactedOidcKeyResponse = async (
|
||||||
export default function logtoConfigRoutes<T extends AuthedRouter>(
|
export default function logtoConfigRoutes<T extends AuthedRouter>(
|
||||||
...[router, { queries, logtoConfigs, invalidateCache }]: RouterInitArgs<T>
|
...[router, { queries, logtoConfigs, invalidateCache }]: RouterInitArgs<T>
|
||||||
) {
|
) {
|
||||||
const {
|
const { getAdminConsoleConfig, getRowsByKeys, updateAdminConsoleConfig, updateOidcConfigsByKey } =
|
||||||
getAdminConsoleConfig,
|
queries.logtoConfigs;
|
||||||
getRowsByKeys,
|
const { getOidcConfigs, upsertJwtCustomizer } = logtoConfigs;
|
||||||
upsertJwtCustomizer,
|
|
||||||
updateAdminConsoleConfig,
|
|
||||||
updateOidcConfigsByKey,
|
|
||||||
} = queries.logtoConfigs;
|
|
||||||
const { getOidcConfigs } = logtoConfigs;
|
|
||||||
|
|
||||||
router.get(
|
router.get(
|
||||||
'/configs/admin-console',
|
'/configs/admin-console',
|
||||||
|
|
Loading…
Add table
Reference in a new issue