mirror of
https://github.com/logto-io/logto.git
synced 2025-02-17 22:04:19 -05:00
fix(core): handle not found error for password sign in (#2383)
This commit is contained in:
parent
4028669940
commit
27ce104ec5
5 changed files with 28 additions and 42 deletions
|
@ -8,12 +8,7 @@ import { getLogtoConnectorById } from '@/connectors';
|
|||
import type { SocialUserInfo } from '@/connectors/types';
|
||||
import { socialUserInfoGuard } from '@/connectors/types';
|
||||
import RequestError from '@/errors/RequestError';
|
||||
import {
|
||||
findUserByEmail,
|
||||
findUserByPhone,
|
||||
hasUserWithEmail,
|
||||
hasUserWithPhone,
|
||||
} from '@/queries/user';
|
||||
import { findUserByEmail, findUserByPhone } from '@/queries/user';
|
||||
import assertThat from '@/utils/assert-that';
|
||||
|
||||
export type SocialUserInfoSession = {
|
||||
|
@ -88,16 +83,20 @@ export const getUserInfoFromInteractionResult = async (
|
|||
export const findSocialRelatedUser = async (
|
||||
info: SocialUserInfo
|
||||
): Promise<Nullable<[{ type: 'email' | 'phone'; value: string }, User]>> => {
|
||||
if (info.phone && (await hasUserWithPhone(info.phone))) {
|
||||
if (info.phone) {
|
||||
const user = await findUserByPhone(info.phone);
|
||||
|
||||
return [{ type: 'phone', value: info.phone }, user];
|
||||
if (user) {
|
||||
return [{ type: 'phone', value: info.phone }, user];
|
||||
}
|
||||
}
|
||||
|
||||
if (info.email && (await hasUserWithEmail(info.email))) {
|
||||
if (info.email) {
|
||||
const user = await findUserByEmail(info.email);
|
||||
|
||||
return [{ type: 'email', value: info.email }, user];
|
||||
if (user) {
|
||||
return [{ type: 'email', value: info.email }, user];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
|
|
|
@ -18,14 +18,14 @@ export const findUserByUsername = async (username: string) =>
|
|||
`);
|
||||
|
||||
export const findUserByEmail = async (email: string) =>
|
||||
envSet.pool.one<User>(sql`
|
||||
envSet.pool.maybeOne<User>(sql`
|
||||
select ${sql.join(Object.values(fields), sql`,`)}
|
||||
from ${table}
|
||||
where lower(${fields.primaryEmail})=lower(${email})
|
||||
`);
|
||||
|
||||
export const findUserByPhone = async (phone: string) =>
|
||||
envSet.pool.one<User>(sql`
|
||||
envSet.pool.maybeOne<User>(sql`
|
||||
select ${sql.join(Object.values(fields), sql`,`)}
|
||||
from ${table}
|
||||
where ${fields.primaryPhone}=${phone}
|
||||
|
|
|
@ -53,12 +53,8 @@ export const smsSignInAction = <StateT, ContextT extends WithLogContext, Respons
|
|||
|
||||
checkValidateExpiration(expiresAt);
|
||||
|
||||
assertThat(
|
||||
await hasUserWithPhone(phone),
|
||||
new RequestError({ code: 'user.phone_not_exists', status: 404 })
|
||||
);
|
||||
|
||||
const user = await findUserByPhone(phone);
|
||||
assertThat(user, new RequestError({ code: 'user.phone_not_exists', status: 404 }));
|
||||
const { id } = user;
|
||||
ctx.log(type, { userId: id });
|
||||
|
||||
|
@ -99,12 +95,8 @@ export const emailSignInAction = <StateT, ContextT extends WithLogContext, Respo
|
|||
|
||||
checkValidateExpiration(expiresAt);
|
||||
|
||||
assertThat(
|
||||
await hasUserWithEmail(email),
|
||||
new RequestError({ code: 'user.email_not_exists', status: 404 })
|
||||
);
|
||||
|
||||
const user = await findUserByEmail(email);
|
||||
assertThat(user, new RequestError({ code: 'user.email_not_exists', status: 404 }));
|
||||
const { id } = user;
|
||||
ctx.log(type, { userId: id });
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/* eslint-disable max-lines */
|
||||
import type { User } from '@logto/schemas';
|
||||
import { PasscodeType, SignInIdentifier, SignUpIdentifier } from '@logto/schemas';
|
||||
import type { Nullable } from '@silverhand/essentials';
|
||||
import { addDays, addSeconds, subDays } from 'date-fns';
|
||||
import { Provider } from 'oidc-provider';
|
||||
|
||||
|
@ -14,7 +15,8 @@ import passwordlessRoutes, { registerRoute, signInRoute } from './passwordless';
|
|||
|
||||
const insertUser = jest.fn(async (..._args: unknown[]) => mockUser);
|
||||
const findUserById = jest.fn(async (): Promise<User> => mockUser);
|
||||
const findUserByEmail = jest.fn(async (): Promise<User> => mockUser);
|
||||
const findUserByEmail = jest.fn(async (): Promise<Nullable<User>> => mockUser);
|
||||
const findUserByPhone = jest.fn(async (): Promise<Nullable<User>> => mockUser);
|
||||
const updateUserById = jest.fn(async (..._args: unknown[]) => mockUser);
|
||||
const findDefaultSignInExperience = jest.fn(async () => ({
|
||||
...mockSignInExperience,
|
||||
|
@ -34,7 +36,7 @@ jest.mock('@/lib/user', () => ({
|
|||
|
||||
jest.mock('@/queries/user', () => ({
|
||||
findUserById: async () => findUserById(),
|
||||
findUserByPhone: async () => mockUser,
|
||||
findUserByPhone: async () => findUserByPhone(),
|
||||
findUserByEmail: async () => findUserByEmail(),
|
||||
updateUserById: async (...args: unknown[]) => updateUserById(...args),
|
||||
hasUser: async (username: string) => username === 'username1',
|
||||
|
@ -260,6 +262,7 @@ describe('session -> passwordlessRoutes', () => {
|
|||
});
|
||||
|
||||
it('throw 404 (with flow `forgot-password`)', async () => {
|
||||
findUserByPhone.mockResolvedValueOnce(null);
|
||||
const response = await sessionRequest
|
||||
.post('/session/passwordless/sms/verify')
|
||||
.send({ phone: '13000000001', code: '1234', flow: PasscodeType.ForgotPassword });
|
||||
|
@ -358,6 +361,7 @@ describe('session -> passwordlessRoutes', () => {
|
|||
it('throw 404 (with flow `forgot-password`)', async () => {
|
||||
const fakeTime = new Date();
|
||||
jest.useFakeTimers().setSystemTime(fakeTime);
|
||||
findUserByEmail.mockResolvedValueOnce(null);
|
||||
const response = await sessionRequest
|
||||
.post('/session/passwordless/email/verify')
|
||||
.send({ email: 'b@a.com', code: '1234', flow: PasscodeType.ForgotPassword });
|
||||
|
@ -501,6 +505,7 @@ describe('session -> passwordlessRoutes', () => {
|
|||
},
|
||||
},
|
||||
});
|
||||
findUserByPhone.mockResolvedValueOnce(null);
|
||||
const response = await sessionRequest.post(`${signInRoute}/sms`);
|
||||
expect(response.statusCode).toEqual(404);
|
||||
});
|
||||
|
@ -639,6 +644,7 @@ describe('session -> passwordlessRoutes', () => {
|
|||
},
|
||||
},
|
||||
});
|
||||
findUserByEmail.mockResolvedValueOnce(null);
|
||||
const response = await sessionRequest.post(`${signInRoute}/email`);
|
||||
expect(response.statusCode).toEqual(404);
|
||||
});
|
||||
|
|
|
@ -6,12 +6,7 @@ import { object, string } from 'zod';
|
|||
import RequestError from '@/errors/RequestError';
|
||||
import { createPasscode, sendPasscode, verifyPasscode } from '@/lib/passcode';
|
||||
import koaGuard from '@/middleware/koa-guard';
|
||||
import {
|
||||
findUserByEmail,
|
||||
findUserByPhone,
|
||||
hasUserWithEmail,
|
||||
hasUserWithPhone,
|
||||
} from '@/queries/user';
|
||||
import { findUserByEmail, findUserByPhone } from '@/queries/user';
|
||||
import { passcodeTypeGuard } from '@/routes/session/types';
|
||||
import assertThat from '@/utils/assert-that';
|
||||
|
||||
|
@ -105,13 +100,10 @@ export default function passwordlessRoutes<T extends AnonymousRouter>(
|
|||
await verifyPasscode(jti, flow, code, { phone });
|
||||
|
||||
if (flow === PasscodeType.ForgotPassword) {
|
||||
assertThat(
|
||||
await hasUserWithPhone(phone),
|
||||
new RequestError({ code: 'user.phone_not_exists', status: 404 })
|
||||
);
|
||||
const user = await findUserByPhone(phone);
|
||||
assertThat(user, new RequestError({ code: 'user.phone_not_exists', status: 404 }));
|
||||
|
||||
const { id } = await findUserByPhone(phone);
|
||||
await assignVerificationResult(ctx, provider, { flow, userId: id });
|
||||
await assignVerificationResult(ctx, provider, { flow, userId: user.id });
|
||||
ctx.status = 204;
|
||||
|
||||
return next();
|
||||
|
@ -156,14 +148,11 @@ export default function passwordlessRoutes<T extends AnonymousRouter>(
|
|||
await verifyPasscode(jti, flow, code, { email });
|
||||
|
||||
if (flow === PasscodeType.ForgotPassword) {
|
||||
assertThat(
|
||||
await hasUserWithEmail(email),
|
||||
new RequestError({ code: 'user.email_not_exists', status: 404 })
|
||||
);
|
||||
const user = await findUserByEmail(email);
|
||||
|
||||
const { id } = await findUserByEmail(email);
|
||||
assertThat(user, new RequestError({ code: 'user.email_not_exists', status: 404 }));
|
||||
|
||||
await assignVerificationResult(ctx, provider, { flow, userId: id });
|
||||
await assignVerificationResult(ctx, provider, { flow, userId: user.id });
|
||||
ctx.status = 204;
|
||||
|
||||
return next();
|
||||
|
|
Loading…
Add table
Reference in a new issue