diff --git a/packages/core/src/errors/RequestError/collection/sign-in-errors.ts b/packages/core/src/errors/RequestError/collection/sign-in-errors.ts new file mode 100644 index 000000000..d02b2c77d --- /dev/null +++ b/packages/core/src/errors/RequestError/collection/sign-in-errors.ts @@ -0,0 +1,11 @@ +export enum SignInErrorCode { + InvalidCredentials = 'sign_in.invalid_credentials', + InvalidSignInMethod = 'sign_in.invalid_sign_in_method', + InsufficientInfo = 'sign_in.insufficient_info', +} + +export const signInErrorMessage: Record = { + [SignInErrorCode.InvalidCredentials]: 'Invalid credentials. Please check your input.', + [SignInErrorCode.InvalidSignInMethod]: 'Current sign-in method is not available.', + [SignInErrorCode.InsufficientInfo]: 'Insufficent sign-in info.', +}; diff --git a/packages/core/src/errors/RequestError/message.ts b/packages/core/src/errors/RequestError/message.ts index 266e2c66c..6bff81736 100644 --- a/packages/core/src/errors/RequestError/message.ts +++ b/packages/core/src/errors/RequestError/message.ts @@ -3,10 +3,12 @@ import { guardErrorMessage } from './collection/guard-errors'; import { oidcErrorMessage } from './collection/oidc-errors'; import { registerErrorMessage } from './collection/register-errors'; import { swaggerErrorMessage } from './collection/swagger-errors'; +import { signInErrorMessage } from './collection/sign-in-errors'; export const requestErrorMessage: Record = { ...guardErrorMessage, ...oidcErrorMessage, ...registerErrorMessage, ...swaggerErrorMessage, + ...signInErrorMessage, }; diff --git a/packages/core/src/errors/RequestError/types.ts b/packages/core/src/errors/RequestError/types.ts index 0f11a023e..e4a686e97 100644 --- a/packages/core/src/errors/RequestError/types.ts +++ b/packages/core/src/errors/RequestError/types.ts @@ -2,14 +2,16 @@ import { GuardErrorCode } from './collection/guard-errors'; import { OidcErrorCode } from './collection/oidc-errors'; import { RegisterErrorCode } from './collection/register-errors'; import { SwaggerErrorCode } from './collection/swagger-errors'; +import { SignInErrorCode } from './collection/sign-in-errors'; -export { GuardErrorCode, OidcErrorCode, SwaggerErrorCode, RegisterErrorCode }; +export { GuardErrorCode, OidcErrorCode, SwaggerErrorCode, RegisterErrorCode, SignInErrorCode }; export type RequestErrorCode = | GuardErrorCode | OidcErrorCode | RegisterErrorCode - | SwaggerErrorCode; + | SwaggerErrorCode + | SignInErrorCode; export type RequestErrorMetadata = { code: RequestErrorCode; diff --git a/packages/core/src/proxies/ui.ts b/packages/core/src/proxies/ui.ts index 0fd0c4056..4b1d17b6a 100644 --- a/packages/core/src/proxies/ui.ts +++ b/packages/core/src/proxies/ui.ts @@ -3,7 +3,7 @@ import proxy from 'koa-proxies'; // CAUTION: this is for testing only export default function uiProxy() { return proxy(/^\/(?!api|oidc).*$/, { - target: 'http://localhost:3000', + target: 'http://localhost:5000', changeOrigin: true, logs: true, }); diff --git a/packages/core/src/routes/sign-in.ts b/packages/core/src/routes/sign-in.ts index 2c8f87e02..bf63df523 100644 --- a/packages/core/src/routes/sign-in.ts +++ b/packages/core/src/routes/sign-in.ts @@ -6,7 +6,7 @@ import { findUserById } from '@/queries/user'; import { Provider } from 'oidc-provider'; import { conditional } from '@logto/essentials'; import koaGuard from '@/middleware/koa-guard'; -import { OidcErrorCode } from '@/errors/RequestError'; +import RequestError, { OidcErrorCode, SignInErrorCode } from '@/errors/RequestError'; export default function signInRoutes(provider: Provider) { const router = new Router(); @@ -22,25 +22,38 @@ export default function signInRoutes(provider: Provider) { if (name === 'login') { const { id, password } = ctx.guard.body; - assert(id && password, 'Insufficent sign-in info.'); - const { passwordEncrypted, passwordEncryptionMethod, passwordEncryptionSalt } = - await findUserById(id); + assert(id && password, new RequestError(SignInErrorCode.InsufficientInfo)); - assert(passwordEncrypted && passwordEncryptionMethod && passwordEncryptionSalt); - assert( - encryptPassword(id, password, passwordEncryptionSalt, passwordEncryptionMethod) === - passwordEncrypted - ); + try { + const { passwordEncrypted, passwordEncryptionMethod, passwordEncryptionSalt } = + await findUserById(id); - const redirectTo = await provider.interactionResult( - ctx.req, - ctx.res, - { - login: { accountId: id }, - }, - { mergeWithLastSubmission: false } - ); - ctx.body = { redirectTo }; + assert( + passwordEncrypted && passwordEncryptionMethod && passwordEncryptionSalt, + new RequestError(SignInErrorCode.InvalidSignInMethod) + ); + assert( + encryptPassword(id, password, passwordEncryptionSalt, passwordEncryptionMethod) === + passwordEncrypted, + new RequestError(SignInErrorCode.InvalidCredentials) + ); + + const redirectTo = await provider.interactionResult( + ctx.req, + ctx.res, + { + login: { accountId: id }, + }, + { mergeWithLastSubmission: false } + ); + ctx.body = { redirectTo }; + } catch (error: unknown) { + if (!(error instanceof RequestError)) { + throw new RequestError(SignInErrorCode.InvalidCredentials); + } + + throw error; + } } else if (name === 'consent') { ctx.body = { redirectTo: ctx.request.origin + '/sign-in/consent' }; } else {