0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2024-12-16 20:26:19 -05:00

feat(core): post /session/forgot-password/phone/verify-passcode-and-reset-password (#334)

* feat(core): add post /session/forgot-password/phone/verify-passcode and UT

* feat(core): reset password once passcode verification succeed
This commit is contained in:
Darcy Ye 2022-03-08 16:09:06 +08:00 committed by GitHub
parent 1399c9258e
commit 9e677ca97a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 77 additions and 0 deletions

View file

@ -780,6 +780,46 @@ describe('sessionRoutes', () => {
});
});
describe('POST /session/forgot-password/phone/verify-passcode-and-reset-password', () => {
beforeAll(() => {
interactionDetails.mockResolvedValueOnce({
jti: 'jti',
});
});
it('throw if no user can be found with phone', async () => {
const response = await sessionRequest
.post('/session/forgot-password/phone/verify-passcode-and-reset-password')
.send({ phone: '13000000001', code: '1234', password: '123456' });
expect(response).toHaveProperty('statusCode', 422);
});
it('fail to verify passcode', async () => {
const response = await sessionRequest
.post('/session/forgot-password/phone/verify-passcode-and-reset-password')
.send({ phone: '13000000000', code: '1231', password: '123456' });
expect(response).toHaveProperty('statusCode', 400);
});
it('verify passcode, reset password and assign result', async () => {
const response = await sessionRequest
.post('/session/forgot-password/phone/verify-passcode-and-reset-password')
.send({ phone: '13000000000', code: '1234', password: '123456' });
expect(response).toHaveProperty('statusCode', 200);
expect(updateUserById).toHaveBeenCalledWith('id', {
passwordEncryptionSalt: 'user1',
passwordEncrypted: 'id_123456_user1',
passwordEncryptionMethod: 'SaltAndPepper',
});
expect(interactionResult).toHaveBeenCalledWith(
expect.anything(),
expect.anything(),
expect.objectContaining({ login: { accountId: 'id' } }),
expect.anything()
);
});
});
describe('POST /session/bind-social', () => {
it('throw if session is not authorized', async () => {
interactionDetails.mockResolvedValueOnce({});

View file

@ -503,6 +503,43 @@ export default function sessionRoutes<T extends AnonymousRouter>(router: T, prov
}
);
router.post(
'/session/forgot-password/phone/verify-passcode-and-reset-password',
koaGuard({
body: object({
phone: string().regex(phoneRegEx),
code: string(),
password: string().regex(passwordRegEx),
}),
}),
async (ctx, next) => {
const { jti } = await provider.interactionDetails(ctx.req, ctx.res);
const { phone, code, password } = ctx.guard.body;
ctx.userLog.phone = phone;
ctx.userLog.type = UserLogType.ForgotPasswordPhone;
assertThat(
await hasUserWithPhone(phone),
new RequestError({ code: 'user.phone_not_exists', status: 422 })
);
await verifyPasscode(jti, PasscodeType.ForgotPassword, code, { phone });
const { id } = await findUserByPhone(phone);
ctx.userLog.userId = id;
const { passwordEncryptionSalt, passwordEncrypted, passwordEncryptionMethod } =
encryptUserPassword(id, password);
await updateUserById(id, {
passwordEncryptionSalt,
passwordEncrypted,
passwordEncryptionMethod,
});
await assignInteractionResults(ctx, provider, { login: { accountId: id } });
return next();
}
);
router.post(
'/session/bind-social',
koaGuard({