feat(API/login): permissive email handling
Allow case insensitive email when there's no other candidate. closes #6570
This commit is contained in:
parent
714d9c4aa7
commit
5e44b71940
|
@ -28,6 +28,8 @@ describe('Test oauth', function () {
|
|||
})
|
||||
|
||||
await setAccessTokensToServers([ server ])
|
||||
await server.users.create({ username: 'user1', email: 'user@example.com' })
|
||||
await server.users.create({ username: 'user2', email: 'User@example.com', password: 'AdvancedPassword' })
|
||||
|
||||
sqlCommand = new SQLCommand(server)
|
||||
})
|
||||
|
@ -79,7 +81,7 @@ describe('Test oauth', function () {
|
|||
})
|
||||
|
||||
it('Should not login with an invalid password', async function () {
|
||||
const user = { username: server.store.user.username, password: 'mew_three' }
|
||||
const user = { username: 'User@example.com', password: 'password' }
|
||||
const body = await server.login.login({ user, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
|
||||
|
||||
expectInvalidCredentials(body)
|
||||
|
@ -87,6 +89,9 @@ describe('Test oauth', function () {
|
|||
|
||||
it('Should be able to login', async function () {
|
||||
await server.login.login({ expectedStatus: HttpStatusCode.OK_200 })
|
||||
|
||||
const user = { username: 'User@example.com', password: 'AdvancedPassword' }
|
||||
await server.login.login({ user, expectedStatus: HttpStatusCode.OK_200 })
|
||||
})
|
||||
|
||||
it('Should be able to login with an insensitive username', async function () {
|
||||
|
@ -99,6 +104,14 @@ describe('Test oauth', function () {
|
|||
const user3 = { username: 'ROOt', password: server.store.user.password }
|
||||
await server.login.login({ user: user3, expectedStatus: HttpStatusCode.OK_200 })
|
||||
})
|
||||
|
||||
it('Should be able to login with an insensitive email when no similar emails exist', async function () {
|
||||
const user = { username: 'ADMIN' + server.internalServerNumber + '@example.com', password: server.store.user.password }
|
||||
await server.login.login({ user, expectedStatus: HttpStatusCode.OK_200 })
|
||||
|
||||
const user2 = { username: 'admin' + server.internalServerNumber + '@example.com', password: server.store.user.password }
|
||||
await server.login.login({ user: user2, expectedStatus: HttpStatusCode.OK_200 })
|
||||
})
|
||||
})
|
||||
|
||||
describe('Logout', function () {
|
||||
|
|
|
@ -14,7 +14,7 @@ import { OAuthClientModel } from '../../models/oauth/oauth-client.js'
|
|||
import { OAuthTokenModel } from '../../models/oauth/oauth-token.js'
|
||||
import { UserModel } from '../../models/user/user.js'
|
||||
import { findAvailableLocalActorName } from '../local-actor.js'
|
||||
import { buildUser, createUserAccountAndChannelAndPlaylist } from '../user.js'
|
||||
import { buildUser, createUserAccountAndChannelAndPlaylist, getUserByEmailPermissive } from '../user.js'
|
||||
import { ExternalUser } from './external-auth.js'
|
||||
import { TokensCache } from './tokens-cache.js'
|
||||
|
||||
|
@ -87,7 +87,7 @@ async function getUser (usernameOrEmail?: string, password?: string, bypassLogin
|
|||
if (bypassLogin && bypassLogin.bypass === true) {
|
||||
logger.info('Bypassing oauth login by plugin %s.', bypassLogin.pluginName)
|
||||
|
||||
let user = await UserModel.loadByEmail(bypassLogin.user.email)
|
||||
let user = getUserByEmailPermissive(await UserModel.loadByEmailCaseInsensitive(bypassLogin.user.email), bypassLogin.user.email)
|
||||
|
||||
if (!user) {
|
||||
user = await createUserFromExternal(bypassLogin.pluginName, bypassLogin.user)
|
||||
|
@ -119,7 +119,14 @@ async function getUser (usernameOrEmail?: string, password?: string, bypassLogin
|
|||
|
||||
logger.debug('Getting User (username/email: ' + usernameOrEmail + ', password: ******).')
|
||||
|
||||
const user = await UserModel.loadByUsernameOrEmail(usernameOrEmail)
|
||||
const users = await UserModel.loadByUsernameOrEmailCaseInsensitive(usernameOrEmail)
|
||||
let user: MUserDefault
|
||||
|
||||
if (usernameOrEmail.includes('@')) {
|
||||
user = getUserByEmailPermissive(users, usernameOrEmail)
|
||||
} else {
|
||||
user = users[0]
|
||||
}
|
||||
|
||||
// If we don't find the user, or if the user belongs to a plugin
|
||||
if (!user || user.pluginAuth !== null || !password) return null
|
||||
|
|
|
@ -701,6 +701,20 @@ export class UserModel extends SequelizeModel<UserModel> {
|
|||
return UserModel.findOne(query)
|
||||
}
|
||||
|
||||
static loadByUsernameOrEmailCaseInsensitive (usernameOrEmail: string): Promise<MUserDefault[]> {
|
||||
const query = {
|
||||
where: {
|
||||
[Op.or]: [
|
||||
where(fn('lower', col('username')), fn('lower', usernameOrEmail) as any),
|
||||
|
||||
where(fn('lower', col('email')), fn('lower', usernameOrEmail) as any)
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
return UserModel.findAll(query)
|
||||
}
|
||||
|
||||
static loadByVideoId (videoId: number): Promise<MUserDefault> {
|
||||
const query = {
|
||||
include: [
|
||||
|
|
Loading…
Reference in New Issue