Fix otp admin login (#8639)

* Fix otp admin login

Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com>

* Fix

Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com>

---------

Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com>
This commit is contained in:
Denis Bykhov
2025-04-19 01:17:31 +07:00
committed by GitHub
parent e7ff27fd53
commit bbbdf67b28
3 changed files with 116 additions and 96 deletions
@@ -1715,6 +1715,7 @@ describe('account utils', () => {
describe('loginOrSignUpWithProvider', () => {
const mockCtx = {
info: jest.fn(),
error: jest.fn()
} as unknown as MeasureContext
+40 -32
View File
@@ -150,7 +150,7 @@ export async function login (
const isConfirmed = emailSocialId.verifiedOn != null
const extraToken: Record<string, string> = isAdminEmail(email) ? { admin: 'true' } : {}
const extraToken: Record<string, string> = isAdminEmail(normalizedEmail) ? { admin: 'true' } : {}
ctx.info('Login succeeded', { email, normalizedEmail, isConfirmed, emailSocialId, ...extraToken })
return {
@@ -292,48 +292,56 @@ export async function validateOtp (
// Note: can support OTP based on any other social logins later
const normalizedEmail = cleanEmail(email)
const emailSocialId = await getEmailSocialId(db, normalizedEmail)
try {
const emailSocialId = await getEmailSocialId(db, normalizedEmail)
if (emailSocialId == null) {
throw new PlatformError(new Status(Severity.ERROR, platform.status.AccountNotFound, { account: email }))
}
if (emailSocialId == null) {
throw new PlatformError(new Status(Severity.ERROR, platform.status.AccountNotFound, { account: email }))
}
const isValid = await isOtpValid(db, emailSocialId._id, code)
const isValid = await isOtpValid(db, emailSocialId._id, code)
if (!isValid) {
throw new PlatformError(new Status(Severity.ERROR, platform.status.InvalidOtp, {}))
}
if (!isValid) {
throw new PlatformError(new Status(Severity.ERROR, platform.status.InvalidOtp, {}))
}
await db.otp.deleteMany({ socialId: emailSocialId._id })
await db.otp.deleteMany({ socialId: emailSocialId._id })
if (emailSocialId.verifiedOn == null) {
await db.socialId.updateOne({ _id: emailSocialId._id }, { verifiedOn: Date.now() })
}
if (emailSocialId.verifiedOn == null) {
await db.socialId.updateOne({ _id: emailSocialId._id }, { verifiedOn: Date.now() })
}
// This method handles both login and signup
const account = await db.account.findOne({ uuid: emailSocialId.personUuid as AccountUuid })
// This method handles both login and signup
const account = await db.account.findOne({ uuid: emailSocialId.personUuid as AccountUuid })
if (account == null) {
// This is a signup
await createAccount(db, emailSocialId.personUuid, true)
if (account == null) {
// This is a signup
await createAccount(db, emailSocialId.personUuid, true)
ctx.info('OTP signup success', emailSocialId)
} else {
await confirmHulyIds(ctx, db, account.uuid)
ctx.info('OTP signup success', emailSocialId)
} else {
await confirmHulyIds(ctx, db, account.uuid)
ctx.info('OTP login success', emailSocialId)
}
ctx.info('OTP login success', emailSocialId)
}
const person = await db.person.findOne({ uuid: emailSocialId.personUuid })
if (person == null) {
throw new PlatformError(new Status(Severity.ERROR, platform.status.InternalServerError, {}))
}
const person = await db.person.findOne({ uuid: emailSocialId.personUuid })
if (person == null) {
throw new PlatformError(new Status(Severity.ERROR, platform.status.InternalServerError, {}))
}
return {
account: emailSocialId.personUuid as AccountUuid,
name: getPersonName(person),
socialId: emailSocialId._id,
token: generateToken(emailSocialId.personUuid)
const extraToken: Record<string, string> = isAdminEmail(normalizedEmail) ? { admin: 'true' } : {}
return {
account: emailSocialId.personUuid as AccountUuid,
name: getPersonName(person),
socialId: emailSocialId._id,
token: generateToken(emailSocialId.personUuid, undefined, extraToken)
}
} catch (err: any) {
Analytics.handleError(err)
ctx.error('OTP login error', { email, err })
throw err
}
}
+75 -64
View File
@@ -61,6 +61,7 @@ import {
type SocialId,
type Workspace
} from './types'
import { isAdminEmail } from './admin'
export const GUEST_ACCOUNT = 'b6996120-416f-49cd-841e-e4a5d2e49c9b'
@@ -1075,80 +1076,90 @@ export async function loginOrSignUpWithProvider (
socialId: SocialKey,
signUpDisabled = false
): Promise<LoginInfo | null> {
const normalizedEmail = cleanEmail(email)
try {
const normalizedEmail = cleanEmail(email)
// Find if any of the target/email social ids exist
const targetSocialId = await db.socialId.findOne(socialId)
const emailSocialId =
normalizedEmail !== '' ? await db.socialId.findOne({ type: SocialIdType.EMAIL, value: normalizedEmail }) : undefined
let personUuid = targetSocialId?.personUuid ?? emailSocialId?.personUuid
// Find if any of the target/email social ids exist
const targetSocialId = await db.socialId.findOne(socialId)
const emailSocialId =
normalizedEmail !== ''
? await db.socialId.findOne({ type: SocialIdType.EMAIL, value: normalizedEmail })
: undefined
let personUuid = targetSocialId?.personUuid ?? emailSocialId?.personUuid
if (personUuid == null) {
if (signUpDisabled) {
return null
if (personUuid == null) {
if (signUpDisabled) {
return null
}
personUuid = await db.person.insertOne({ firstName: first, lastName: last })
}
personUuid = await db.person.insertOne({ firstName: first, lastName: last })
}
if (personUuid == null) {
throw new PlatformError(new Status(Severity.ERROR, platform.status.InternalServerError, {}))
}
const person = await db.person.findOne({ uuid: personUuid })
if (person == null) {
throw new PlatformError(new Status(Severity.ERROR, platform.status.InternalServerError, {}))
}
const account = await db.account.findOne({ uuid: personUuid as AccountUuid })
if (account == null) {
if (signUpDisabled) {
return null
if (personUuid == null) {
throw new PlatformError(new Status(Severity.ERROR, platform.status.InternalServerError, {}))
}
await createAccount(db, personUuid, true)
await db.person.updateOne({ uuid: personUuid }, { firstName: first, lastName: last })
}
const person = await db.person.findOne({ uuid: personUuid })
// We should check and reset password if there's an account with password but no social ids have been
// confirmed yet
const confirmedSocialId = await db.socialId.findOne({ personUuid, verifiedOn: { $gt: 0 } })
if (confirmedSocialId == null) {
await db.resetPassword(personUuid as AccountUuid)
}
let socialIdId: PersonId | undefined
// Create and/or confirm missing social ids
if (targetSocialId == null) {
socialIdId = await db.socialId.insertOne({ ...socialId, personUuid, verifiedOn: Date.now() })
} else if (targetSocialId.verifiedOn == null) {
await db.socialId.updateOne({ key: targetSocialId.key }, { verifiedOn: Date.now() })
socialIdId = targetSocialId._id
}
if (emailSocialId == null) {
if (normalizedEmail !== '') {
await db.socialId.insertOne({
type: SocialIdType.EMAIL,
value: normalizedEmail,
personUuid,
verifiedOn: Date.now()
})
if (person == null) {
throw new PlatformError(new Status(Severity.ERROR, platform.status.InternalServerError, {}))
}
} else if (emailSocialId.verifiedOn == null) {
await db.socialId.updateOne({ key: emailSocialId.key }, { verifiedOn: Date.now() })
}
await confirmHulyIds(ctx, db, personUuid as AccountUuid)
const account = await db.account.findOne({ uuid: personUuid as AccountUuid })
return {
account: personUuid as AccountUuid,
socialId: socialIdId,
name: getPersonName(person),
token: generateToken(personUuid)
if (account == null) {
if (signUpDisabled) {
return null
}
await createAccount(db, personUuid, true)
await db.person.updateOne({ uuid: personUuid }, { firstName: first, lastName: last })
}
// We should check and reset password if there's an account with password but no social ids have been
// confirmed yet
const confirmedSocialId = await db.socialId.findOne({ personUuid, verifiedOn: { $gt: 0 } })
if (confirmedSocialId == null) {
await db.resetPassword(personUuid as AccountUuid)
}
let socialIdId: PersonId | undefined
// Create and/or confirm missing social ids
if (targetSocialId == null) {
socialIdId = await db.socialId.insertOne({ ...socialId, personUuid, verifiedOn: Date.now() })
} else if (targetSocialId.verifiedOn == null) {
await db.socialId.updateOne({ key: targetSocialId.key }, { verifiedOn: Date.now() })
socialIdId = targetSocialId._id
}
if (emailSocialId == null) {
if (normalizedEmail !== '') {
await db.socialId.insertOne({
type: SocialIdType.EMAIL,
value: normalizedEmail,
personUuid,
verifiedOn: Date.now()
})
}
} else if (emailSocialId.verifiedOn == null) {
await db.socialId.updateOne({ key: emailSocialId.key }, { verifiedOn: Date.now() })
}
await confirmHulyIds(ctx, db, personUuid as AccountUuid)
const extraToken: Record<string, string> = isAdminEmail(normalizedEmail) ? { admin: 'true' } : {}
ctx.info('Provider login succeeded', { email, normalizedEmail, emailSocialId, ...extraToken })
return {
account: personUuid as AccountUuid,
socialId: socialIdId,
name: getPersonName(person),
token: generateToken(personUuid, undefined, extraToken)
}
} catch (err: any) {
Analytics.handleError(err)
ctx.error('Provider login failed', { email, err })
throw err
}
}