mirror of
https://github.com/hcengineering/platform.git
synced 2026-09-09 19:27:44 +02:00
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:
@@ -1715,6 +1715,7 @@ describe('account utils', () => {
|
||||
|
||||
describe('loginOrSignUpWithProvider', () => {
|
||||
const mockCtx = {
|
||||
info: jest.fn(),
|
||||
error: jest.fn()
|
||||
} as unknown as MeasureContext
|
||||
|
||||
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user