From 9aa4caa826a42df394188a78bd9dafe93ad339ec Mon Sep 17 00:00:00 2001 From: Gao Sun Date: Mon, 11 Oct 2021 17:55:17 +0800 Subject: [PATCH] refactor(core): fulfill correct `applicationType` when needed (#126) * refactor(core): fulfill correct `applicationType` when needed * refactor(core): use enum for application type * refactor(core): do not filter undefined automatically --- .../core/src/database/update-where.test.ts | 18 +++++++++++++++++- packages/core/src/oidc/utils.ts | 12 ++++++++++-- packages/core/src/routes/application.ts | 16 +++++++++++----- .../schemas/src/foundations/jsonb-types.ts | 1 + 4 files changed, 39 insertions(+), 8 deletions(-) diff --git a/packages/core/src/database/update-where.test.ts b/packages/core/src/database/update-where.test.ts index cd1b60261..70b7163ba 100644 --- a/packages/core/src/database/update-where.test.ts +++ b/packages/core/src/database/update-where.test.ts @@ -12,7 +12,10 @@ describe('buildUpdateWhere()', () => { ); const updateWhere = buildUpdateWhere(pool, Users); await expect( - updateWhere({ set: { username: '123' }, where: { id: 'foo', username: '456' } }) + updateWhere({ + set: { username: '123' }, + where: { id: 'foo', username: '456' }, + }) ).resolves.toBe(undefined); }); @@ -32,6 +35,19 @@ describe('buildUpdateWhere()', () => { ).resolves.toStrictEqual(user); }); + it('throws an error when `undefined` found in values', async () => { + const pool = createTestPool( + 'update "users"\nset "username"=$1\nwhere "id"=$2 and "username"=$3' + ); + const updateWhere = buildUpdateWhere(pool, Users); + await expect( + updateWhere({ + set: { username: '123', id: undefined }, + where: { id: 'foo', username: '456' }, + }) + ).rejects.toMatchError(new TypeError("Cannot read property 'toString' of undefined")); + }); + it('throws `entity.not_exists_with_id` error with `undefined` when `returning` is true', async () => { const pool = createTestPool('update "users"\nset "username"=$1\nwhere "id"=$2\nreturning *'); const updateWhere = buildUpdateWhere(pool, Users, true); diff --git a/packages/core/src/oidc/utils.ts b/packages/core/src/oidc/utils.ts index 3c1ff71aa..68fd56902 100644 --- a/packages/core/src/oidc/utils.ts +++ b/packages/core/src/oidc/utils.ts @@ -1,6 +1,14 @@ -import { OidcClientMetadata } from '@logto/schemas'; +import { ApplicationType, OidcClientMetadata } from '@logto/schemas'; -export const generateOidcClientMetadata = (): OidcClientMetadata => ({ +const getApplicationTypeString = (type: ApplicationType) => + type === ApplicationType.Native ? 'native' : 'web'; + +export const buildOidcClientMetadata = ( + type: ApplicationType, + metadata?: OidcClientMetadata +): OidcClientMetadata => ({ redirectUris: [], postLogoutRedirectUris: [], + ...metadata, + applicationType: getApplicationTypeString(type), }); diff --git a/packages/core/src/routes/application.ts b/packages/core/src/routes/application.ts index c13c58193..b4177b106 100644 --- a/packages/core/src/routes/application.ts +++ b/packages/core/src/routes/application.ts @@ -2,7 +2,7 @@ import { Applications } from '@logto/schemas'; import { object, string } from 'zod'; import koaGuard from '@/middleware/koa-guard'; -import { generateOidcClientMetadata } from '@/oidc/utils'; +import { buildOidcClientMetadata } from '@/oidc/utils'; import { deleteApplicationById, findApplicationById, @@ -31,13 +31,13 @@ export default function applicationRoutes(router: T) { .merge(Applications.guard.pick({ name: true, type: true })), }), async (ctx, next) => { - const { name, type, ...rest } = ctx.guard.body; + const { name, type, oidcClientMetadata, ...rest } = ctx.guard.body; ctx.body = await insertApplication({ id: applicationId(), type, name, - oidcClientMetadata: generateOidcClientMetadata(), + oidcClientMetadata: buildOidcClientMetadata(type, oidcClientMetadata), ...rest, }); return next(); @@ -63,7 +63,6 @@ export default function applicationRoutes(router: T) { '/application/:id', koaGuard({ params: object({ id: string().min(1) }), - // Consider `.deepPartial()` if OIDC client metadata bloats body: Applications.guard.omit({ id: true, createdAt: true }).partial(), }), async (ctx, next) => { @@ -71,8 +70,15 @@ export default function applicationRoutes(router: T) { params: { id }, body, } = ctx.guard; + const application = await findApplicationById(id); - ctx.body = await updateApplicationById(id, body); + ctx.body = await updateApplicationById(id, { + ...body, + oidcClientMetadata: buildOidcClientMetadata(body.type ?? application.type, { + ...application.oidcClientMetadata, + ...body.oidcClientMetadata, + }), + }); return next(); } ); diff --git a/packages/schemas/src/foundations/jsonb-types.ts b/packages/schemas/src/foundations/jsonb-types.ts index 3367c74a9..8a618d57a 100644 --- a/packages/schemas/src/foundations/jsonb-types.ts +++ b/packages/schemas/src/foundations/jsonb-types.ts @@ -15,6 +15,7 @@ export const oidcModelInstancePayloadGuard = z export type OidcModelInstancePayload = z.infer; export const oidcClientMetadataGuard = z.object({ + applicationType: z.enum(['web', 'native']), redirectUris: z.string().array(), postLogoutRedirectUris: z.string().array(), });