From b8d5a6d103d166bb969ca404114eed2033423de6 Mon Sep 17 00:00:00 2001 From: Kevin Gatera Date: Mon, 9 Mar 2026 12:58:16 -0400 Subject: [PATCH] fix case-insensitive local auth user lookup --- server/models/User.js | 12 ++++++---- test/server/models/User.test.js | 42 +++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 4 deletions(-) diff --git a/server/models/User.js b/server/models/User.js index 633fc1cef..f71f80f3b 100644 --- a/server/models/User.js +++ b/server/models/User.js @@ -348,11 +348,13 @@ class User extends Model { static async getUserByUsername(username) { if (!username) return null - const cachedUser = userCache.getByUsername(username) + const normalizedUsername = username.toLowerCase() + + const cachedUser = userCache.getByUsername(normalizedUsername) if (cachedUser) return cachedUser const user = await this.findOne({ - where: sequelize.where(sequelize.fn('lower', sequelize.col('username')), username.toLowerCase()), + where: sequelize.where(sequelize.fn('LOWER', sequelize.col('username')), normalizedUsername), include: this.sequelize.models.mediaProgress }) @@ -369,11 +371,13 @@ class User extends Model { static async getUserByEmail(email) { if (!email) return null - const cachedUser = userCache.getByEmail(email) + const normalizedEmail = email.toLowerCase() + + const cachedUser = userCache.getByEmail(normalizedEmail) if (cachedUser) return cachedUser const user = await this.findOne({ - where: sequelize.where(sequelize.fn('lower', sequelize.col('email')), email.toLowerCase()), + where: sequelize.where(sequelize.fn('LOWER', sequelize.col('email')), normalizedEmail), include: this.sequelize.models.mediaProgress }) diff --git a/test/server/models/User.test.js b/test/server/models/User.test.js index 5b935fee6..734c31609 100644 --- a/test/server/models/User.test.js +++ b/test/server/models/User.test.js @@ -3,6 +3,48 @@ const sinon = require('sinon') const User = require('../../../server/models/User') describe('User model', () => { + describe('case-insensitive lookup helpers', () => { + afterEach(() => { + sinon.restore() + }) + + it('should query usernames case-insensitively', async () => { + User.sequelize = { + models: { + mediaProgress: {} + } + } + + const findOneStub = sinon.stub(User, 'findOne').resolves(null) + + await User.getUserByUsername('Madison') + + expect(findOneStub.calledOnce).to.equal(true) + const options = findOneStub.firstCall.args[0] + expect(options.where.attribute.fn).to.equal('LOWER') + expect(options.where.attribute.args[0].col).to.equal('username') + expect(options.where.logic).to.equal('madison') + }) + + it('should query emails case-insensitively', async () => { + User.sequelize = { + models: { + mediaProgress: {} + } + } + + const findOneStub = sinon.stub(User, 'findOne').resolves(null) + + await User.getUserByEmail('Example.User@Example.com') + + expect(findOneStub.calledOnce).to.equal(true) + const options = findOneStub.firstCall.args[0] + expect(options.where.attribute.fn).to.equal('LOWER') + expect(options.where.attribute.args[0].col).to.equal('email') + expect(options.where.logic).to.equal('example.user@example.com') + }) + }) + describe('getUserByIdOrOldId', () => { let originalSequelize