From ef4a8d7ea12c336da818ecfe38d7fc5aabe35438 Mon Sep 17 00:00:00 2001 From: Cassie Tarakajian Date: Mon, 6 Apr 2020 19:01:37 -0400 Subject: [PATCH] Use MongoDB Regexes to query case insensitive username/password --- server/config/passport.js | 2 +- server/controllers/user.controller.js | 14 +++++++------- server/models/user.js | 5 +++-- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/server/config/passport.js b/server/config/passport.js index 4c739138..3ef7a0e2 100644 --- a/server/config/passport.js +++ b/server/config/passport.js @@ -24,7 +24,7 @@ passport.deserializeUser((id, done) => { * Sign in using Email/Username and Password. */ passport.use(new LocalStrategy({ usernameField: 'email' }, (email, password, done) => { - User.findByMailOrName(email.toLowerCase()) + User.findByMailOrName(email) .then((user) => { // eslint-disable-line consistent-return if (!user) { return done(null, false, { msg: `Email ${email} not found.` }); diff --git a/server/controllers/user.controller.js b/server/controllers/user.controller.js index c50cefb4..d552e648 100644 --- a/server/controllers/user.controller.js +++ b/server/controllers/user.controller.js @@ -1,5 +1,6 @@ import crypto from 'crypto'; import async from 'async'; +import escapeStringRegexp from 'escape-string-regexp'; import User from '../models/user'; import mail from '../utils/mail'; @@ -41,12 +42,11 @@ export function findUserByUsername(username, cb) { export function createUser(req, res, next) { const { username, email } = req.body; const { password } = req.body; - const usernameLowerCase = username.toLowerCase(); const emailLowerCase = email.toLowerCase(); const EMAIL_VERIFY_TOKEN_EXPIRY_TIME = Date.now() + (3600000 * 24); // 24 hours random((tokenError, token) => { const user = new User({ - username: usernameLowerCase, + username: username, email: emailLowerCase, password, verified: User.EmailConfirmation.Sent, @@ -57,8 +57,8 @@ export function createUser(req, res, next) { User.findOne( { $or: [ - { email: { $in: [ email, emailLowerCase ]} }, - { username: { $in: [ username, usernameLowerCase ]} } + { email: new RegExp(`^${escapeStringRegexp(email)}$`, 'i') }, + { username: new RegExp(`^${escapeStringRegexp(username)}$`, 'i') } ] }, (err, existingUser) => { @@ -106,7 +106,7 @@ export function duplicateUserCheck(req, res) { const checkType = req.query.check_type; const value = req.query[checkType]; const query = {}; - query[checkType] = value; + query[checkType] = new RegExp(`^${escapeStringRegexp(value)}$`, 'i'); User.findOne(query, (err, user) => { if (user) { return res.json({ @@ -151,7 +151,7 @@ export function resetPasswordInitiate(req, res) { async.waterfall([ random, (token, done) => { - User.findOne({ email: req.body.email }, (err, user) => { + User.findOne({ email: req.body.email.toLowerCase() }, (err, user) => { if (!user) { res.json({ success: true, message: 'If the email is registered with the editor, an email has been sent.' }); return; @@ -281,7 +281,7 @@ export function updatePassword(req, res) { } export function userExists(username, callback) { - User.findOne({ username }, (err, user) => ( + User.findOne({ username: new RegExp(`^${escapeStringRegexp(username)}$`, 'i') }, (err, user) => ( user ? callback(true) : callback(false) )); } diff --git a/server/models/user.js b/server/models/user.js index 98c0e1fd..d5e5d8f6 100644 --- a/server/models/user.js +++ b/server/models/user.js @@ -1,4 +1,5 @@ import mongoose from 'mongoose'; +import escapeStringRegexp from 'escape-string-regexp'; const bcrypt = require('bcrypt-nodejs'); @@ -144,9 +145,9 @@ userSchema.methods.findMatchingKey = function findMatchingKey(candidateKey, cb) userSchema.statics.findByMailOrName = function findByMailOrName(email) { const query = { $or: [{ - email, + email: new RegExp(`^${escapeStringRegexp(email)}$`, 'i'), }, { - username: email, + username: new RegExp(`^${escapeStringRegexp(email)}$`, 'i'), }], }; return this.findOne(query).exec();