From de8af5b69cbed932a69a43eed9be9030f5ecc43d Mon Sep 17 00:00:00 2001 From: david-loe <56305409+david-loe@users.noreply.github.com> Date: Sat, 7 Sep 2024 09:13:00 +0200 Subject: [PATCH] Make Magic Login case insensitive Fixes #88 --- backend/authStrategies/magiclogin.ts | 5 +++-- backend/controller/authController.ts | 4 ++-- common/scripts.ts | 4 ++++ 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/backend/authStrategies/magiclogin.ts b/backend/authStrategies/magiclogin.ts index 197c7e36..625f6bc6 100644 --- a/backend/authStrategies/magiclogin.ts +++ b/backend/authStrategies/magiclogin.ts @@ -1,4 +1,5 @@ import { default as MagicLoginStrategy } from 'passport-magic-login' +import { escapeRegExp } from '../../common/scripts.js' import { NotAllowedError } from '../controller/error.js' import i18n from '../i18n.js' import { sendMail } from '../mail/mail.js' @@ -8,7 +9,7 @@ const magicLogin = new MagicLoginStrategy.default({ secret: process.env.MAGIC_LOGIN_SECRET, callbackUrl: process.env.VITE_BACKEND_URL + '/auth/magiclogin/callback', sendMagicLink: async (destination, href) => { - var user = await User.findOne({ 'fk.magiclogin': destination }).lean() + var user = await User.findOne({ 'fk.magiclogin': { $regex: new RegExp('^' + escapeRegExp(destination) + '$', 'i') } }).lean() if (user) { sendMail( [user], @@ -22,7 +23,7 @@ const magicLogin = new MagicLoginStrategy.default({ } }, verify: async function (payload, callback) { - var user = await User.findOne({ 'fk.magiclogin': payload.destination }).lean() + var user = await User.findOne({ 'fk.magiclogin': { $regex: new RegExp('^' + escapeRegExp(payload.destination) + '$', 'i') } }).lean() if (user) { callback(null, user, { redirect: payload.redirect }) } else { diff --git a/backend/controller/authController.ts b/backend/controller/authController.ts index ebf19906..14a846cb 100644 --- a/backend/controller/authController.ts +++ b/backend/controller/authController.ts @@ -1,7 +1,7 @@ import { Request as ExRequest, Response as ExResponse, NextFunction } from 'express' import passport from 'passport' import { Body, Controller, Delete, Get, Middlewares, Post, Query, Request, Response, Route, Security, SuccessResponse, Tags } from 'tsoa' -import { Base64 } from '../../common/scripts.js' +import { Base64, escapeRegExp } from '../../common/scripts.js' import magiclogin from '../authStrategies/magiclogin.js' import User from '../models/user.js' import { NotAllowedError, NotImplementedError } from './error.js' @@ -29,7 +29,7 @@ const microsoftCallbackHandler = useMicrosoft ? passport.authenticate('microsoft const magicloginHandler = useMagicLogin ? async (req: ExRequest, res: ExResponse, next: NextFunction) => { - var user = await User.findOne({ 'fk.magiclogin': req.body.destination }) + var user = await User.findOne({ 'fk.magiclogin': { $regex: new RegExp('^' + escapeRegExp(req.body.destination) + '$', 'i') } }) if (user && (await user.isActive())) { magiclogin.send(req, res) } else { diff --git a/common/scripts.ts b/common/scripts.ts index f1ce74f4..caf3adf1 100644 --- a/common/scripts.ts +++ b/common/scripts.ts @@ -485,3 +485,7 @@ export function download(file: File) { document.body.removeChild(link) window.URL.revokeObjectURL(url) } + +export function escapeRegExp(str: string) { + return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') // $& means the whole matched string +}