diff --git a/app/src/api/controllers/userController.ts b/app/src/api/controllers/userController.ts index 9a2b1004..df04e894 100644 --- a/app/src/api/controllers/userController.ts +++ b/app/src/api/controllers/userController.ts @@ -5,6 +5,7 @@ import express from 'express'; import * as userService from '../services/user'; import * as passwordResetService from '../services/passwordReset'; import { TokenVerificationError } from '../services/passwordReset'; +import { ValidationError } from '../validation'; function createUser(req, res) { const user = req.body; @@ -87,6 +88,8 @@ async function resetPassword(req: express.Request, res: express.Response) { } catch (err) { if (err instanceof TokenVerificationError) { return res.send({ error: 'Could not verify token' }); + } else if (err instanceof ValidationError) { + return res.send({ error: err.message}); } throw err; diff --git a/app/src/api/services/passwordReset.ts b/app/src/api/services/passwordReset.ts index 07ede0a0..c3799d0d 100644 --- a/app/src/api/services/passwordReset.ts +++ b/app/src/api/services/passwordReset.ts @@ -5,6 +5,7 @@ import nodemailer from 'nodemailer'; import db from '../../db'; import * as userService from './user'; import { transporter } from './email'; +import { validatePassword } from '../validation'; /** @@ -24,6 +25,7 @@ export async function sendPasswordResetToken(email: string, siteOrigin: string): } export async function resetPassword(passwordResetToken: string, newPassword: string): Promise { + validatePassword(newPassword); const userId = await verifyPasswordResetToken(passwordResetToken); if (userId != undefined) { await updatePasswordForUser(userId, newPassword); diff --git a/app/src/api/services/user.ts b/app/src/api/services/user.ts index 0e471aa4..0556eaf2 100644 --- a/app/src/api/services/user.ts +++ b/app/src/api/services/user.ts @@ -3,14 +3,18 @@ * */ import db from '../../db'; +import { validateUsername, ValidationError, validatePassword } from '../validation'; function createUser(user) { - if (!user.password || user.password.length < 8) { - return Promise.reject({ error: 'Password must be at least 8 characters' }) - } - if (user.password.length > 70) { - return Promise.reject({ error: 'Password must be at most 70 characters' }) + try { + validateUsername(user.username); + validatePassword(user.password); + } catch(err) { + if (err instanceof ValidationError) { + return Promise.reject({ error: err.message }); + } else throw err; } + return db.one( `INSERT INTO users ( diff --git a/app/src/api/validation.ts b/app/src/api/validation.ts new file mode 100644 index 00000000..4e9036bb --- /dev/null +++ b/app/src/api/validation.ts @@ -0,0 +1,25 @@ +class ValidationError extends Error { + constructor(message) { + super(message); + this.name = 'ValidationError'; + } +} + +function validateUsername(username: string): void { + if (username == undefined) throw new ValidationError('Username is required'); + if (!username.match(/^\w+$/)) throw new ValidationError('Username can only contain alphanumeric characters and underscore'); + if (username.length < 4) throw new ValidationError('Username must be at least 4 characters long'); + if (username.length > 30) throw new ValidationError('Username must be at most 30 characters long'); +} + +function validatePassword(password: string): void { + if (password == undefined) throw new ValidationError('Password is required'); + if (password.length < 8) throw new ValidationError('Password must be at least 8 characters long'); + if (password.length > 70) throw new ValidationError('Password must be at most 70 characters long'); +} + +export { + ValidationError, + validateUsername, + validatePassword +}; \ No newline at end of file