Skip to content

Commit

Permalink
feat: support Permanent prop of AdminSetUserPassword service
Browse files Browse the repository at this point in the history
  • Loading branch information
solufa committed Jul 15, 2024
1 parent 4a70b90 commit 76d4a26
Show file tree
Hide file tree
Showing 8 changed files with 35 additions and 25 deletions.
29 changes: 11 additions & 18 deletions server/domain/user/model/adminMethod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,28 +33,21 @@ export const adminMethod = {
status: 'FORCE_CHANGE_PASSWORD',
};
},
deleteUser: (params: { user: UserEntity; userPoolId: string }): EntityId['deletableUser'] => {
assert(params.user.userPoolId === params.userPoolId);
deleteUser: (user: UserEntity, userPoolId: string): EntityId['deletableUser'] => {
assert(user.userPoolId === userPoolId);

return brandedId.deletableUser.entity.parse(params.user.id);
return brandedId.deletableUser.entity.parse(user.id);
},
setUserPassword: (params: {
user: UserEntity;
req: AdminSetUserPasswordTarget['reqBody'];
}): UserEntity => {
assert(params.req.UserPoolId);
assert(params.req.Password);
validatePass(params.req.Password);
setUserPassword: (user: UserEntity, req: AdminSetUserPasswordTarget['reqBody']): UserEntity => {
assert(req.UserPoolId);
assert(req.Password);
validatePass(req.Password);

return {
...params.user,
...genCredentials({
poolId: params.user.userPoolId,
username: params.user.name,
password: params.req.Password,
}),
status: 'CONFIRMED',
password: params.req.Password,
...user,
...genCredentials({ poolId: user.userPoolId, username: user.name, password: req.Password }),
status: req.Permanent ? 'CONFIRMED' : 'FORCE_CHANGE_PASSWORD',
password: req.Password,
refreshToken: ulid(),
challenge: undefined,
updatedTime: Date.now(),
Expand Down
3 changes: 2 additions & 1 deletion server/domain/user/service/createAttributes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type { UserAttributeEntity, UserEntity } from 'common/types/user';
import { brandedId } from 'service/brandedId';
import { ulid } from 'ulid';
import { z } from 'zod';
import { isEmailVerified } from './isEmailVerified';

export const COMPUTED_ATTRIBUTE_NAMES = ['sub', 'email', 'email_verified', 'updated_at'] as const;

Expand All @@ -28,7 +29,7 @@ export const toAttributeTypes = (user: UserEntity): AttributeType[] => {
return [
{ Name: 'sub', Value: user.id },
{ Name: 'email', Value: user.email },
{ Name: 'email_verified', Value: user.status === 'CONFIRMED' ? 'true' : 'false' },
{ Name: 'email_verified', Value: isEmailVerified(user) ? 'true' : 'false' },
{ Name: 'updated_at', Value: Math.floor(user.updatedTime / 1000).toString() },
...user.attributes.map((attr) => ({ Name: attr.name, Value: attr.value })),
];
Expand Down
3 changes: 2 additions & 1 deletion server/domain/user/service/genTokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { EXPIRES_SEC } from 'service/constants';
import { PORT } from 'service/envValues';
import type { AccessTokenJwt, IdTokenJwt } from 'service/types';
import { ulid } from 'ulid';
import { isEmailVerified } from './isEmailVerified';

export const genTokens = (params: {
privateKey: string;
Expand Down Expand Up @@ -39,7 +40,7 @@ export const genTokens = (params: {
};
const idToken: IdTokenJwt = {
...comomn,
email_verified: params.user.status === 'CONFIRMED',
email_verified: isEmailVerified(params.user),
'cognito:username': params.user.name,
aud: params.userPoolClientId,
token_use: 'id',
Expand Down
4 changes: 4 additions & 0 deletions server/domain/user/service/isEmailVerified.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import type { UserEntity } from 'common/types/user';

export const isEmailVerified = (user: UserEntity): boolean =>
user.status === 'CONFIRMED' || user.status === 'FORCE_CHANGE_PASSWORD';
4 changes: 2 additions & 2 deletions server/domain/user/useCase/adminUseCase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export const adminUseCase = {
assert(req.UserPoolId);

const user = await userQuery.findByName(tx, req.Username);
const deletableId = adminMethod.deleteUser({ user, userPoolId: req.UserPoolId });
const deletableId = adminMethod.deleteUser(user, req.UserPoolId);

await userCommand.delete(tx, deletableId, user.attributes);

Expand Down Expand Up @@ -115,7 +115,7 @@ export const adminUseCase = {

const user = await userQuery.findByName(tx, req.Username);

await userCommand.save(tx, adminMethod.setUserPassword({ user, req }));
await userCommand.save(tx, adminMethod.setUserPassword(user, req));

return {};
}),
Expand Down
3 changes: 2 additions & 1 deletion server/domain/user/useCase/signInUseCase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { cognitoAssert } from 'service/cognitoAssert';
import { EXPIRES_SEC } from 'service/constants';
import { transaction } from 'service/prismaClient';
import { signInMethod } from '../model/signInMethod';
import { isEmailVerified } from '../service/isEmailVerified';

export const signInUseCase = {
userSrpAuth: (req: UserSrpAuthTarget['reqBody']): Promise<UserSrpAuthTarget['resBody']> =>
Expand Down Expand Up @@ -65,7 +66,7 @@ export const signInUseCase = {
assert(pool.id === poolClient.userPoolId);
assert(user.challenge?.secretBlock === req.ChallengeResponses.PASSWORD_CLAIM_SECRET_BLOCK);

cognitoAssert(user.status === 'FORCE_CHANGE_PASSWORD', 'User is not confirmed.');
cognitoAssert(isEmailVerified(user), 'User is not confirmed.');

const tokens = signInMethod.srpAuth({
user,
Expand Down
11 changes: 10 additions & 1 deletion server/tests/api/utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
AdminCreateUserCommand,
AdminInitiateAuthCommand,
AdminSetUserPasswordCommand,
} from '@aws-sdk/client-cognito-identity-provider';
import assert from 'assert';
import { InbucketAPIClient } from 'inbucket-js-client';
Expand Down Expand Up @@ -31,11 +32,19 @@ export const createUserAndToken = async (): Promise<{ AccessToken: string }> =>
new AdminCreateUserCommand({
UserPoolId: DEFAULT_USER_POOL_ID,
Username: testUserName,
TemporaryPassword: testPassword,
UserAttributes: [{ Name: 'email', Value: `${ulid()}@example.com` }],
}),
);

await cognitoClient.send(
new AdminSetUserPasswordCommand({
UserPoolId: DEFAULT_USER_POOL_ID,
Username: testUserName,
Permanent: true,
Password: testPassword,
}),
);

const res = await cognitoClient.send(
new AdminInitiateAuthCommand({
AuthFlow: 'ADMIN_NO_SRP_AUTH',
Expand Down
3 changes: 2 additions & 1 deletion server/tests/sdk/admin.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ test(`${AdminCreateUserCommand.name} - specify TemporaryPassword`, async () => {
await cognitoClient.send(
new AdminSetUserPasswordCommand({
UserPoolId: DEFAULT_USER_POOL_ID,
Permanent: true,
Username: testUserName,
Password: testPassword,
}),
Expand Down Expand Up @@ -102,7 +103,7 @@ test(`${AdminCreateUserCommand.name} - unset TemporaryPassword`, async () => {
new AdminGetUserCommand({ UserPoolId: DEFAULT_USER_POOL_ID, Username: testUserName }),
);

expect(res.UserStatus).toBe(UserStatusType.CONFIRMED);
expect(res.UserStatus).toBe(UserStatusType.FORCE_CHANGE_PASSWORD);
});

test(AdminDeleteUserCommand.name, async () => {
Expand Down

0 comments on commit 76d4a26

Please sign in to comment.