Skip to content

Commit

Permalink
Add input validation for user service when updating user
Browse files Browse the repository at this point in the history
  • Loading branch information
McNaBry committed Nov 13, 2024
1 parent c56766e commit 760fd3e
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 11 deletions.
32 changes: 21 additions & 11 deletions services/user/src/controller/user-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
registrationSchema,
updatePasswordSchema,
updateUsernameAndEmailSchema,
updateUserSchema,
UserValidationErrors,
} from '../types/custom';

Expand Down Expand Up @@ -181,7 +182,7 @@ export async function updatePassword(req: Request, res: Response) {
err => err.message == UserValidationErrors.REQUIRED,
);
if (required_errors.length > 0) {
handleBadRequest(res, 'old password and/or new password are missing');
handleBadRequest(res, 'No field to update: username and email and password are all missing!');
}
handleBadRequest(res, 'invalid password');
}
Expand All @@ -194,12 +195,21 @@ export async function updatePassword(req: Request, res: Response) {

export async function updateUser(req: Request, res: Response) {
try {
const { username, email, password } = req.body;
if (!(username || email || password)) {
handleBadRequest(res, 'No field to update: username and email and password are all missing!');
const parseResult = updateUserSchema.safeParse(req.body);
if (!parseResult.success) {
const required_errors = parseResult.error.errors.filter(
err => err.message == UserValidationErrors.REQUIRED,
);
if (required_errors.length > 0) {
handleBadRequest(res, 'No field to update: username and email and password are all missing!');
return;
}
handleBadRequest(res, 'invalid username and/or email and/or password');
return;
}

const { username, email, password } = req.body;

const userId = req.params.id;
if (!isValidObjectId(userId)) {
handleNotFound(res, `User ${userId} not found`);
Expand All @@ -210,6 +220,7 @@ export async function updateUser(req: Request, res: Response) {
handleNotFound(res, `User ${userId} not found`);
return;
}

if (username || email) {
const userByUsername = await _findUserByUsername(username);
if (userByUsername && userByUsername.id !== userId) {
Expand All @@ -223,14 +234,13 @@ export async function updateUser(req: Request, res: Response) {
}
}

if (!password) {
handleBadRequest(res, 'No field to update: password is missing!');
return;
}
const salt = bcrypt.genSaltSync(10);
const hashedPassword = bcrypt.hashSync(password, salt);

const updatedUser = (await _updateUserById(userId, username, email, hashedPassword)) as User;
const updatedUser = (await _updateUserById(
userId,
username ?? user.username,

Check failure on line 240 in services/user/src/controller/user-controller.ts

View workflow job for this annotation

GitHub Actions / build-service (services/user)

Delete `·`
email ?? user.email,

Check failure on line 241 in services/user/src/controller/user-controller.ts

View workflow job for this annotation

GitHub Actions / build-service (services/user)

Delete `·`
password ? bcrypt.hashSync(password, salt) : user.password

Check failure on line 242 in services/user/src/controller/user-controller.ts

View workflow job for this annotation

GitHub Actions / build-service (services/user)

Insert `,`
)) as User;
handleSuccess(res, 200, `Updated data for user ${userId}`, formatUserResponse(updatedUser));
} catch (err) {
console.error(err);
Expand Down
16 changes: 16 additions & 0 deletions services/user/src/types/custom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,22 @@ export const registrationSchema = z.object({
password: passwordSchema,
});

export const updateUserSchema = z.object({

Check failure on line 46 in services/user/src/types/custom.ts

View workflow job for this annotation

GitHub Actions / build-service (services/user)

Insert `⏎····`
username: usernameSchema.optional(),

Check failure on line 47 in services/user/src/types/custom.ts

View workflow job for this annotation

GitHub Actions / build-service (services/user)

Insert `····`
email: emailSchema.optional(),

Check failure on line 48 in services/user/src/types/custom.ts

View workflow job for this annotation

GitHub Actions / build-service (services/user)

Insert `····`
password: passwordSchema.optional(),

Check failure on line 49 in services/user/src/types/custom.ts

View workflow job for this annotation

GitHub Actions / build-service (services/user)

Insert `····`
}).superRefine((data, ctx) => {

Check failure on line 50 in services/user/src/types/custom.ts

View workflow job for this annotation

GitHub Actions / build-service (services/user)

Replace `})` with `····})⏎····`
if (!data.username && !data.email && !data.password) {

Check failure on line 51 in services/user/src/types/custom.ts

View workflow job for this annotation

GitHub Actions / build-service (services/user)

Replace `····` with `········`
// If none of the variables are present, assign error to each one

Check failure on line 52 in services/user/src/types/custom.ts

View workflow job for this annotation

GitHub Actions / build-service (services/user)

Insert `····`
// Granular control over which is missing is not needed
ctx.addIssue({
path: ['username', 'password', 'email'],
message: UserValidationErrors.REQUIRED,
code: z.ZodIssueCode.custom,
});
}
});

export const updateUsernameAndEmailSchema = z.object({
username: usernameSchema,
email: emailSchema,
Expand Down

0 comments on commit 760fd3e

Please sign in to comment.