From 1c9d69a8e00eb13ee4e14f231180dd569ab93110 Mon Sep 17 00:00:00 2001 From: "Lin, Hung-Shin" Date: Wed, 1 Nov 2023 15:02:30 +0800 Subject: [PATCH] feat: add validators for username, email, password * not passed yet --- server/src/api/controllers/authController.js | 74 +------------------- server/src/api/routes/auth.js | 28 ++++++-- server/src/api/validators/authValidator.js | 43 ++++++++++++ server/src/middleware/validator.js | 13 ++++ 4 files changed, 82 insertions(+), 76 deletions(-) create mode 100644 server/src/api/validators/authValidator.js create mode 100644 server/src/middleware/validator.js diff --git a/server/src/api/controllers/authController.js b/server/src/api/controllers/authController.js index 7a87a53..5dd0232 100644 --- a/server/src/api/controllers/authController.js +++ b/server/src/api/controllers/authController.js @@ -1,4 +1,4 @@ -import { isValidEmail, isValidUsername } from '@linux-odyssey/utils' +import { matchedData } from 'express-validator' import { User } from '@linux-odyssey/models' import { genJWT, hashPassword } from '../../utils/auth.js' @@ -12,67 +12,8 @@ export async function issueToken(req, res) { res.json({ token }) } -async function invalidUsername(username) { - return !isValidUsername(username) || User.exists({ username }) -} - -async function invalidEmail(email) { - return !isValidEmail(email) || User.exists({ email }) -} - -export async function checkUsername(req, res) { - const { username, email } = req.query - const cred = username || email - if (!cred) { - res.status(400).json({ - message: 'username or email is required', - }) - return - } - - if (isValidEmail(cred)) { - res.json({ - type: 'email', - available: !(await User.exists({ email: cred })), - }) - return - } - if (isValidUsername(cred)) { - res.json({ - type: 'username', - available: !(await User.exists({ username: cred })), - }) - return - } - res.status(400).json({ - message: 'invalid username or email', - }) -} - export async function register(req, res, next) { - const { username, password, email } = req.body - if (!(username && password && email)) { - res.status(400).json({ - message: 'username, password, and email are required', - }) - return - } - - if (await invalidUsername(username)) { - res.status(409).json({ - type: 'username', - message: 'Invalid username', - }) - return - } - - if (await invalidEmail(email)) { - res.status(409).json({ - type: 'email', - message: 'Invalid email', - }) - return - } + const { username, password, email } = matchedData(req) const user = new User({ username, @@ -81,7 +22,6 @@ export async function register(req, res, next) { try { user.hashedPassword = await hashPassword(password) await user.save() - req.user = user req.login(user, (err) => { if (err) { next(err) @@ -131,7 +71,7 @@ export async function socialLogin(req, res) { } export async function registerFromSession(req, res) { - const { username } = req.body + const { username } = matchedData(req) const { newUser } = req.session if (!newUser) { @@ -141,14 +81,6 @@ export async function registerFromSession(req, res) { return } - if (await invalidUsername(username)) { - res.status(409).json({ - type: 'username', - message: 'Invalid username', - }) - return - } - newUser.username = username const user = new User(newUser) diff --git a/server/src/api/routes/auth.js b/server/src/api/routes/auth.js index 8b9954d..85d9196 100644 --- a/server/src/api/routes/auth.js +++ b/server/src/api/routes/auth.js @@ -5,12 +5,17 @@ import enabledMethods from '../../auth/passport.js' import { register, - checkUsername, checkSession, logout, socialLogin, registerFromSession, } from '../controllers/authController.js' +import { + checkNewEmail, + checkNewUsername, + checkPassword, +} from '../validators/authValidator.js' +import { noError } from '../../middleware/validator.js' const router = Router() @@ -22,12 +27,20 @@ router.post( } ) -router.post('/register', register) +router.post( + '/register', + checkNewUsername(), + checkNewEmail(), + checkPassword(), + noError, + register +) router.post('/logout', logout) -router.get('/check-username', checkUsername) - +router.get('/check-username', checkNewUsername(), noError, (req, res) => + res.json({ available: true }) +) router.get('/check-session', checkSession) router.get('/available-methods', (req, res) => { @@ -44,6 +57,11 @@ if (enabledMethods.github) { router.get('/github/callback', passport.authenticate('github'), socialLogin) } -router.post('/register-from-session', registerFromSession) +router.post( + '/register-from-session', + checkNewUsername(), + noError, + registerFromSession +) export default router diff --git a/server/src/api/validators/authValidator.js b/server/src/api/validators/authValidator.js new file mode 100644 index 0000000..9ed7172 --- /dev/null +++ b/server/src/api/validators/authValidator.js @@ -0,0 +1,43 @@ +import { query } from 'express-validator' + +import { isValidUsername } from '@linux-odyssey/utils' +import { User } from '@linux-odyssey/models' + +export const checkUsername = () => + query('username') + .notEmpty() + .isString() + .custom((username) => { + if (!isValidUsername(username)) { + throw new Error('Invalid username') + } + return true + }) + .trim() + +export const checkNewUsername = () => + checkUsername().custom(async (username) => { + if (await User.exists({ username })) { + throw new Error('Username taken') + } + return true + }) + +export const checkEmail = () => query('email').notEmpty().isEmail().trim() + +export const checkNewEmail = () => + checkEmail().custom(async (email) => { + if (await User.exists({ email })) { + throw new Error('Email taken') + } + return true + }) + +export const checkPassword = () => + query('password').notEmpty().isStrongPassword({ + minLength: 8, + minNumbers: 1, + minLowercase: 1, + minUppercase: 1, + minSymbols: 0, + }) diff --git a/server/src/middleware/validator.js b/server/src/middleware/validator.js new file mode 100644 index 0000000..8cda838 --- /dev/null +++ b/server/src/middleware/validator.js @@ -0,0 +1,13 @@ +import { validationResult } from 'express-validator' + +export function noError(req, res, next) { + const result = validationResult(req) + if (result.isEmpty()) { + next() + return + } + console.log(result.array()) + res.status(400).json({ + errors: result.array(), + }) +}