From 2d009aaeeadbbaf9aa5602ddc3dfb976465bc2e9 Mon Sep 17 00:00:00 2001 From: Alexey Zinoviev Date: Tue, 17 Jun 2025 20:45:58 +0400 Subject: [PATCH] uberf-8425: improve account methods params checks (#9278) Signed-off-by: Alexey Zinoviev --- packages/account-client/src/client.ts | 2 +- .../account/src/__tests__/operations.test.ts | 4 +- server/account/src/operations.ts | 173 ++++++++++++++++-- server/account/src/serviceOperations.ts | 93 +++++++++- server/account/src/utils.ts | 5 +- 5 files changed, 247 insertions(+), 30 deletions(-) diff --git a/packages/account-client/src/client.ts b/packages/account-client/src/client.ts index d6fbcf1a13..31bd494b11 100644 --- a/packages/account-client/src/client.ts +++ b/packages/account-client/src/client.ts @@ -369,7 +369,7 @@ class AccountClientImpl implements AccountClient { async resendInvite (email: string, role: AccountRole): Promise { const request = { method: 'resendInvite' as const, - params: [email, role] + params: { email, role } } await this.rpc(request) diff --git a/server/account/src/__tests__/operations.test.ts b/server/account/src/__tests__/operations.test.ts index 6860e628a2..96d2a1a252 100644 --- a/server/account/src/__tests__/operations.test.ts +++ b/server/account/src/__tests__/operations.test.ts @@ -424,7 +424,7 @@ describe('invite operations', () => { ;(mockDb.invite.findOne as jest.Mock).mockResolvedValue(existingInvite) global.fetch = jest.fn().mockResolvedValue({ ok: true }) - await resendInvite(mockCtx, mockDb, mockBranding, mockToken, mockEmail, AccountRole.User) + await resendInvite(mockCtx, mockDb, mockBranding, mockToken, { email: mockEmail, role: AccountRole.User }) expect(mockDb.invite.updateOne).toHaveBeenCalledWith( { id: existingInvite.id }, @@ -446,7 +446,7 @@ describe('invite operations', () => { ;(mockDb.invite.insertOne as jest.Mock).mockResolvedValue(newInviteId) global.fetch = jest.fn().mockResolvedValue({ ok: true }) - await resendInvite(mockCtx, mockDb, mockBranding, mockToken, mockEmail, AccountRole.User) + await resendInvite(mockCtx, mockDb, mockBranding, mockToken, { email: mockEmail, role: AccountRole.User }) expect(mockDb.invite.insertOne).toHaveBeenCalled() expect(global.fetch).toHaveBeenCalled() diff --git a/server/account/src/operations.ts b/server/account/src/operations.ts index 118071c442..436cc305b4 100644 --- a/server/account/src/operations.ts +++ b/server/account/src/operations.ts @@ -98,7 +98,8 @@ import { wrap, updateAllowReadOnlyGuests, READONLY_GUEST_ACCOUNT, - getWorkspaceByDataId + getWorkspaceByDataId, + assignableRoles } from './utils' // Note: it is IMPORTANT to always destructure params passed here to avoid sending extra params @@ -145,6 +146,11 @@ export async function login ( } ): Promise { const { email, password } = params + + if (email == null || password == null || email === '' || password === '') { + throw new PlatformError(new Status(Severity.ERROR, platform.status.BadRequest, {})) + } + const normalizedEmail = cleanEmail(email) try { @@ -199,6 +205,10 @@ export async function loginOtp ( ): Promise { const { email } = params + if (email == null || email === '') { + throw new PlatformError(new Status(Severity.ERROR, platform.status.BadRequest, {})) + } + // Note: can support OTP based on any other social logins later const normalizedEmail = cleanEmail(email) const emailSocialId = await getEmailSocialId(db, normalizedEmail) @@ -231,12 +241,17 @@ export async function signUp ( email: string password: string firstName: string - lastName: string + lastName?: string }, meta?: Meta ): Promise { const { email, password, firstName, lastName } = params - const { account, socialId } = await signUpByEmail(ctx, db, branding, email, password, firstName, lastName) + + if (email == null || password == null || firstName == null || email === '' || password === '' || firstName === '') { + throw new PlatformError(new Status(Severity.ERROR, platform.status.BadRequest, {})) + } + + const { account, socialId } = await signUpByEmail(ctx, db, branding, email, password, firstName, lastName ?? '') const person = await db.person.findOne({ uuid: account }) if (person == null) { throw new PlatformError(new Status(Severity.ERROR, platform.status.InternalServerError, {})) @@ -270,10 +285,15 @@ export async function signUpOtp ( params: { email: string firstName: string - lastName: string + lastName?: string } ): Promise { const { email, firstName, lastName } = params + + if (email == null || firstName == null || email === '' || firstName === '') { + throw new PlatformError(new Status(Severity.ERROR, platform.status.BadRequest, {})) + } + // Note: can support OTP based on any other social logins later const normalizedEmail = cleanEmail(email) let emailSocialId = await getEmailSocialId(db, normalizedEmail) @@ -287,12 +307,12 @@ export async function signUpOtp ( throw new PlatformError(new Status(Severity.ERROR, platform.status.AccountAlreadyExists, {})) } - await db.person.updateOne({ uuid: emailSocialId.personUuid }, { firstName, lastName }) + await db.person.updateOne({ uuid: emailSocialId.personUuid }, { firstName, lastName: lastName ?? '' }) personUuid = emailSocialId.personUuid } else { // There's no person linked to this email, so we need to create a new one - personUuid = await db.person.insertOne({ firstName, lastName }) + personUuid = await db.person.insertOne({ firstName, lastName: lastName ?? '' }) const newSocialId = { type: SocialIdType.EMAIL, value: normalizedEmail, personUuid } const emailSocialIdId = await db.socialId.insertOne(newSocialId) emailSocialId = { ...newSocialId, _id: emailSocialIdId, key: buildSocialIdString(newSocialId) } @@ -314,6 +334,10 @@ export async function validateOtp ( ): Promise { const { email, code, password } = params + if (email == null || code == null || email === '' || code === '') { + throw new PlatformError(new Status(Severity.ERROR, platform.status.BadRequest, {})) + } + // Note: can support OTP based on any other social logins later const normalizedEmail = cleanEmail(email) try { @@ -383,6 +407,11 @@ export async function createWorkspace ( } ): Promise { const { workspaceName, region } = params + + if (workspaceName == null || workspaceName.length === 0) { + throw new PlatformError(new Status(Severity.ERROR, platform.status.BadRequest, {})) + } + const { account } = decodeTokenVerbose(ctx, token) checkRateLimit(account, workspaceName) @@ -448,6 +477,11 @@ export async function createInvite ( } ): Promise { const { exp, emailMask, email, limit, role, autoJoin } = params + + if (role == null || !assignableRoles.includes(role)) { + throw new PlatformError(new Status(Severity.ERROR, platform.status.BadRequest, {})) + } + const { account, workspace: workspaceUuid, extra } = decodeTokenVerbose(ctx, token) const currentAccount = await db.account.findOne({ uuid: account }) @@ -501,6 +535,11 @@ export async function sendInvite ( } ): Promise { const { email, role, expHours } = params + + if (email == null || email === '' || role == null || !assignableRoles.includes(role)) { + throw new PlatformError(new Status(Severity.ERROR, platform.status.BadRequest, {})) + } + const { account, workspace: workspaceUuid, extra } = decodeTokenVerbose(ctx, token) const currentAccount = await db.account.findOne({ uuid: account }) @@ -540,6 +579,11 @@ export async function createInviteLink ( } ): Promise { const { email, role, autoJoin, firstName, lastName, navigateUrl, expHours } = params + + if (email == null || email === '' || role == null || !assignableRoles.includes(role)) { + throw new PlatformError(new Status(Severity.ERROR, platform.status.BadRequest, {})) + } + const { account, workspace: workspaceUuid, extra } = decodeTokenVerbose(ctx, token) const currentAccount = await db.account.findOne({ uuid: account }) @@ -626,10 +670,19 @@ export async function resendInvite ( db: AccountDB, branding: Branding | null, token: string, - email: string, - role: AccountRole + params: { + email: string + role: AccountRole + } ): Promise { + const { email, role } = params + + if (email == null || email === '' || role == null || !assignableRoles.includes(role)) { + throw new PlatformError(new Status(Severity.ERROR, platform.status.BadRequest, {})) + } + const { account, workspace: workspaceUuid, extra } = decodeTokenVerbose(ctx, token) + const currentAccount = await db.account.findOne({ uuid: account }) if (currentAccount == null) { throw new PlatformError(new Status(Severity.ERROR, platform.status.AccountNotFound, { account })) @@ -687,6 +740,11 @@ export async function join ( meta?: Meta ): Promise { const { email, password, inviteId } = params + + if (email == null || email === '' || password == null || password === '' || inviteId == null || inviteId === '') { + throw new PlatformError(new Status(Severity.ERROR, platform.status.BadRequest, {})) + } + const normalizedEmail = cleanEmail(email) const invite = await getWorkspaceInvite(db, inviteId) if (invite == null) { @@ -726,6 +784,10 @@ export async function checkJoin ( ): Promise { const { inviteId } = params + if (inviteId == null || inviteId === '') { + throw new PlatformError(new Status(Severity.ERROR, platform.status.BadRequest, {})) + } + const invite = await getWorkspaceInvite(db, inviteId) if (invite == null) { throw new PlatformError(new Status(Severity.ERROR, platform.status.Forbidden, {})) @@ -766,6 +828,11 @@ export async function checkAutoJoin ( params: { inviteId: string, firstName?: string, lastName?: string } ): Promise { const { inviteId, firstName, lastName } = params + + if (inviteId == null || inviteId === '') { + throw new PlatformError(new Status(Severity.ERROR, platform.status.BadRequest, {})) + } + const invite = await getWorkspaceInvite(db, inviteId) if (invite == null) { throw new PlatformError(new Status(Severity.ERROR, platform.status.Forbidden, {})) @@ -878,12 +945,26 @@ export async function signUpJoin ( email: string password: string first: string - last: string + last?: string inviteId: string }, meta?: Meta ): Promise { const { email, password, first, last, inviteId } = params + + if ( + email == null || + email === '' || + password == null || + password === '' || + first == null || + first === '' || + inviteId == null || + inviteId === '' + ) { + throw new PlatformError(new Status(Severity.ERROR, platform.status.BadRequest, {})) + } + const normalizedEmail = cleanEmail(email) ctx.info('Signing up and joining a workspace using invite', { email, normalizedEmail, first, last, inviteId }) @@ -899,7 +980,7 @@ export async function signUpJoin ( throw new PlatformError(new Status(Severity.ERROR, platform.status.WorkspaceNotFound, { workspaceUuid })) } - const { account } = await signUpByEmail(ctx, db, branding, email, password, first, last, true) + const { account } = await signUpByEmail(ctx, db, branding, email, password, first, last ?? '', true) void setTimezoneIfNotDefined(ctx, db, account, null, meta) return await doJoinByInvite(ctx, db, branding, generateToken(account, workspaceUuid), account, workspace, invite) @@ -951,6 +1032,11 @@ export async function changePassword ( } ): Promise { const { oldPassword, newPassword } = params + + if (oldPassword == null || oldPassword === '' || newPassword == null || newPassword === '') { + throw new PlatformError(new Status(Severity.ERROR, platform.status.BadRequest, {})) + } + const { account: accountUuid } = decodeTokenVerbose(ctx, token) ctx.info('Changing password', { accountUuid }) @@ -978,6 +1064,11 @@ export async function requestPasswordReset ( params: { email: string } ): Promise { const { email } = params + + if (email == null || email === '') { + throw new PlatformError(new Status(Severity.ERROR, platform.status.BadRequest, {})) + } + const normalizedEmail = cleanEmail(email) ctx.info('Requesting password reset', { email, normalizedEmail }) @@ -1046,6 +1137,10 @@ export async function restorePassword ( ): Promise { const { password } = params + if (password == null || password === '') { + throw new PlatformError(new Status(Severity.ERROR, platform.status.BadRequest, {})) + } + const { account, extra } = decodeTokenVerbose(ctx, token) ctx.info('Restoring password', { account, extra }) @@ -1081,6 +1176,11 @@ export async function leaveWorkspace ( params: { account: AccountUuid } ): Promise { const { account: targetAccount } = params + + if (targetAccount == null || targetAccount === '') { + throw new PlatformError(new Status(Severity.ERROR, platform.status.BadRequest, {})) + } + const { account, workspace } = decodeTokenVerbose(ctx, token) ctx.info('Removing account from workspace', { account, workspace }) @@ -1128,17 +1228,20 @@ export async function changeUsername ( token: string, params: { first: string - last: string + last?: string } ): Promise { const { first, last } = params + + if (first == null || first === '') { + throw new PlatformError(new Status(Severity.ERROR, platform.status.BadRequest, {})) + } + const { account } = decodeTokenVerbose(ctx, token) - ctx.info('Changing name of person', { account, first, last }) + await db.person.updateOne({ uuid: account }, { firstName: first, lastName: last ?? '' }) - await db.person.updateOne({ uuid: account }, { firstName: first, lastName: last }) - - ctx.info('Name changed', { account, first, last }) + ctx.info('Person name changed', { account, first, last }) } export async function updateWorkspaceName ( @@ -1149,6 +1252,11 @@ export async function updateWorkspaceName ( params: { name: string } ): Promise { const { name } = params + + if (name == null || name === '') { + throw new PlatformError(new Status(Severity.ERROR, platform.status.BadRequest, {})) + } + const { account, workspace } = decodeTokenVerbose(ctx, token) const role = await db.getWorkspaceRole(account, workspace) @@ -1224,13 +1332,19 @@ export async function getWorkspacesInfo ( token: string, params: { ids: WorkspaceUuid[] } ): Promise { - const { account } = decodeTokenVerbose(ctx, token) const { ids } = params + if (ids == null) { + throw new PlatformError(new Status(Severity.ERROR, platform.status.BadRequest, {})) + } + + const { account } = decodeTokenVerbose(ctx, token) + if (account !== systemAccountUuid) { ctx.error('getWorkspaceInfos with wrong user', { account, token }) throw new PlatformError(new Status(Severity.ERROR, platform.status.Forbidden, {})) } + const workspaces: WorkspaceInfoWithStatus[] = [] for (const id of ids) { const ws = await getWorkspaceInfoWithStatusById(db, id) @@ -1547,6 +1661,11 @@ export async function findPersonBySocialKey ( params: { socialString: string, requireAccount?: boolean } ): Promise { const { socialString } = params + + if (socialString == null || socialString === '') { + throw new PlatformError(new Status(Severity.ERROR, platform.status.BadRequest, {})) + } + decodeTokenVerbose(ctx, token) const socialId = await db.socialId.findOne({ key: socialString }) @@ -1572,6 +1691,11 @@ export async function findPersonBySocialId ( params: { socialId: PersonId, requireAccount?: boolean } ): Promise { const { socialId, requireAccount } = params + + if (socialId == null || socialId === '') { + throw new PlatformError(new Status(Severity.ERROR, platform.status.BadRequest, {})) + } + decodeTokenVerbose(ctx, token) const socialIdObj = await db.socialId.findOne({ _id: socialId }) @@ -1650,8 +1774,12 @@ export async function getAccountInfo ( token: string, params: { accountId: AccountUuid } ): Promise { - decodeTokenVerbose(ctx, token) const { accountId } = params + if (accountId == null || accountId === '') { + throw new PlatformError(new Status(Severity.ERROR, platform.status.BadRequest, {})) + } + + decodeTokenVerbose(ctx, token) const account = await getAccount(db, accountId) if (account === undefined || account === null) { throw new PlatformError(new Status(Severity.ERROR, platform.status.AccountNotFound, {})) @@ -1729,8 +1857,13 @@ async function createMailbox ( domain: string } ): Promise<{ mailbox: string, socialId: PersonId }> { - const { account } = decodeTokenVerbose(ctx, token) const { name, domain } = params + + if (name == null || name === '' || domain == null || domain === '') { + throw new PlatformError(new Status(Severity.ERROR, platform.status.BadRequest, {})) + } + + const { account } = decodeTokenVerbose(ctx, token) const normalizedName = cleanEmail(name) const normalizedDomain = cleanEmail(domain) const mailbox = normalizedName + '@' + normalizedDomain @@ -1778,6 +1911,10 @@ async function deleteMailbox ( token: string, params: { mailbox: string } ): Promise { + if (params.mailbox == null || params.mailbox === '') { + throw new PlatformError(new Status(Severity.ERROR, platform.status.BadRequest, {})) + } + const { account } = decodeTokenVerbose(ctx, token) const mailbox = cleanEmail(params.mailbox) diff --git a/server/account/src/serviceOperations.ts b/server/account/src/serviceOperations.ts index 9f918a03e0..6476dab3ae 100644 --- a/server/account/src/serviceOperations.ts +++ b/server/account/src/serviceOperations.ts @@ -67,7 +67,8 @@ import { doReleaseSocialId, doMergeAccounts, doMergePersons, - READONLY_GUEST_ACCOUNT + READONLY_GUEST_ACCOUNT, + assignableRoles } from './utils' // Note: it is IMPORTANT to always destructure params passed here to avoid sending extra params @@ -210,6 +211,11 @@ export async function updateWorkspaceRoleBySocialKey ( } ): Promise { const { socialKey, targetRole } = params + + if (socialKey == null || socialKey === '' || targetRole == null || !assignableRoles.includes(targetRole)) { + throw new PlatformError(new Status(Severity.ERROR, platform.status.BadRequest, {})) + } + const { extra } = decodeTokenVerbose(ctx, token) verifyAllowedServices(['workspace', 'tool'], extra) @@ -282,13 +288,18 @@ export async function updateWorkspaceInfo ( } ): Promise { const { workspaceUuid, event, version, message } = params - let progress = params.progress const { extra } = decodeTokenVerbose(ctx, token) if (!['workspace', 'tool'].includes(extra?.service)) { throw new PlatformError(new Status(Severity.ERROR, platform.status.Forbidden, {})) } + if (workspaceUuid == null || workspaceUuid === '' || event == null) { + throw new PlatformError(new Status(Severity.ERROR, platform.status.BadRequest, {})) + } + + let progress = params.progress + const wsExists = await db.workspace.exists({ uuid: workspaceUuid }) if (!wsExists) { throw new PlatformError(new Status(Severity.ERROR, platform.status.WorkspaceNotFound, { workspaceUuid })) @@ -476,6 +487,17 @@ export async function assignWorkspace ( throw new PlatformError(new Status(Severity.ERROR, platform.status.Forbidden, {})) } + if ( + email == null || + email === '' || + workspaceUuid == null || + workspaceUuid === '' || + role == null || + !assignableRoles.includes(role) + ) { + throw new PlatformError(new Status(Severity.ERROR, platform.status.BadRequest, {})) + } + const normalizedEmail = cleanEmail(email) const emailSocialId = await getEmailSocialId(db, normalizedEmail) @@ -515,6 +537,10 @@ export async function getPersonInfo ( const { extra } = decodeTokenVerbose(ctx, token) verifyAllowedServices(['workspace', 'tool'], extra) + if (account == null || account === '') { + throw new PlatformError(new Status(Severity.ERROR, platform.status.BadRequest, {})) + } + const person = await db.person.findOne({ uuid: account }) if (person == null) { @@ -543,7 +569,7 @@ export async function releaseSocialId ( const { personUuid, type, value } = params - if (personUuid == null || !Object.values(SocialIdType).includes(type) || value == null) { + if (personUuid == null || !Object.values(SocialIdType).includes(type) || value == null || value === '') { throw new PlatformError(new Status(Severity.ERROR, platform.status.BadRequest, {})) } @@ -562,6 +588,10 @@ export async function addSocialIdToPerson ( verifyAllowedServices(['github', 'telegram-bot', 'gmail', 'tool', 'workspace', 'hulygram'], extra) + if (person == null || person === '' || !Object.values(SocialIdType).includes(type) || value == null || value === '') { + throw new PlatformError(new Status(Severity.ERROR, platform.status.BadRequest, {})) + } + return await addSocialId(db, person, type, value, confirmed, displayValue) } @@ -577,6 +607,10 @@ export async function updateSocialId ( verifyAllowedServices(['telegram-bot', 'gmail'], extra) + if (personId == null || personId === '') { + throw new PlatformError(new Status(Severity.ERROR, platform.status.BadRequest, {})) + } + const socialId = await db.socialId.findOne({ _id: personId }) if (socialId != null) { throw new PlatformError(new Status(Severity.ERROR, platform.status.SocialIdNotFound, { _id: personId })) @@ -593,6 +627,7 @@ export async function createIntegration ( params: Integration ): Promise { const { extra, account } = decodeTokenVerbose(ctx, token) + // it checks params and throws BadRequest if params are invalid const existing = await findExistingIntegration(account, db, params, extra) if (existing != null) { throw new PlatformError(new Status(Severity.ERROR, platform.status.IntegrationAlreadyExists, {})) @@ -616,6 +651,7 @@ export async function updateIntegration ( params: Integration ): Promise { const { extra, account } = decodeTokenVerbose(ctx, token) + // it checks params and throws BadRequest if params are invalid const existing = await findExistingIntegration(account, db, params, extra) if (existing == null) { throw new PlatformError(new Status(Severity.ERROR, platform.status.IntegrationNotFound, {})) @@ -633,6 +669,7 @@ export async function deleteIntegration ( params: IntegrationKey ): Promise { const { extra, account } = decodeTokenVerbose(ctx, token) + // it checks params and throws BadRequest if params are invalid const existing = await findExistingIntegration(account, db, params, extra) if (existing == null) { throw new PlatformError(new Status(Severity.ERROR, platform.status.IntegrationNotFound, {})) @@ -695,7 +732,7 @@ export async function getIntegration ( const isAllowedService = verifyAllowedServices(integrationServices, extra, false) const { socialId, kind, workspaceUuid } = params - if (kind == null || socialId == null || workspaceUuid === undefined) { + if (kind == null || kind === '' || socialId == null || socialId === '' || workspaceUuid === undefined) { throw new PlatformError(new Status(Severity.ERROR, platform.status.BadRequest, {})) } @@ -719,7 +756,14 @@ export async function addIntegrationSecret ( ): Promise { const { extra, account } = decodeTokenVerbose(ctx, token) const { socialId, kind, workspaceUuid, key, secret } = params - if (kind == null || socialId == null || workspaceUuid === undefined || key == null) { + if ( + kind == null || + kind === '' || + socialId == null || + socialId === '' || + workspaceUuid === undefined || + key == null + ) { throw new PlatformError(new Status(Severity.ERROR, platform.status.BadRequest, {})) } @@ -746,7 +790,14 @@ export async function updateIntegrationSecret ( ): Promise { const { extra, account } = decodeTokenVerbose(ctx, token) const { socialId, kind, workspaceUuid, key, secret } = params - if (kind == null || socialId == null || workspaceUuid === undefined || key == null) { + if ( + kind == null || + kind === '' || + socialId == null || + socialId === '' || + workspaceUuid === undefined || + key == null + ) { throw new PlatformError(new Status(Severity.ERROR, platform.status.BadRequest, {})) } @@ -773,7 +824,14 @@ export async function deleteIntegrationSecret ( ): Promise { const { extra, account } = decodeTokenVerbose(ctx, token) const { socialId, kind, workspaceUuid, key } = params - if (kind == null || socialId == null || workspaceUuid === undefined || key == null) { + if ( + kind == null || + kind === '' || + socialId == null || + socialId === '' || + workspaceUuid === undefined || + key == null + ) { throw new PlatformError(new Status(Severity.ERROR, platform.status.BadRequest, {})) } @@ -802,7 +860,14 @@ export async function getIntegrationSecret ( verifyAllowedServices(integrationServices, extra) const { socialId, kind, workspaceUuid, key } = params - if (kind == null || socialId == null || workspaceUuid === undefined || key == null) { + if ( + kind == null || + kind === '' || + socialId == null || + socialId === '' || + workspaceUuid === undefined || + key == null + ) { throw new PlatformError(new Status(Severity.ERROR, platform.status.BadRequest, {})) } const existing = await db.integrationSecret.findOne({ socialId, kind, workspaceUuid, key }) @@ -836,6 +901,10 @@ export async function findFullSocialIdBySocialKey ( const { socialKey } = params + if (socialKey == null || socialKey === '') { + throw new PlatformError(new Status(Severity.ERROR, platform.status.BadRequest, {})) + } + return await db.socialId.findOne({ key: socialKey }) } @@ -853,6 +922,10 @@ export async function mergeSpecifiedPersons ( verifyAllowedServices(['tool', 'workspace'], extra) const { primaryPerson, secondaryPerson } = params + if (primaryPerson == null || primaryPerson === '' || secondaryPerson == null || secondaryPerson === '') { + throw new PlatformError(new Status(Severity.ERROR, platform.status.BadRequest, {})) + } + await doMergePersons(db, primaryPerson, secondaryPerson) } @@ -870,6 +943,10 @@ export async function mergeSpecifiedAccounts ( verifyAllowedServices(['tool', 'workspace'], extra) const { primaryAccount, secondaryAccount } = params + if (primaryAccount == null || primaryAccount === '' || secondaryAccount == null || secondaryAccount === '') { + throw new PlatformError(new Status(Severity.ERROR, platform.status.BadRequest, {})) + } + await doMergeAccounts(db, primaryAccount, secondaryAccount) } diff --git a/server/account/src/utils.ts b/server/account/src/utils.ts index 29097a100f..a210bcaba1 100644 --- a/server/account/src/utils.ts +++ b/server/account/src/utils.ts @@ -119,6 +119,8 @@ export async function getAccountDB ( } } +export const assignableRoles = [AccountRole.Guest, AccountRole.User, AccountRole.Maintainer, AccountRole.Owner] + export function getRolePower (role: AccountRole): number { return roleOrder[role] } @@ -1612,7 +1614,8 @@ export async function findExistingIntegration ( extra: any ): Promise { const { socialId, kind, workspaceUuid } = params - if (kind == null || socialId == null || workspaceUuid === undefined) { + // Note: workspaceUuid === null is a decent use case for account-wise integration not related to a particular workspace + if (kind == null || kind === '' || socialId == null || socialId === '' || workspaceUuid === undefined) { throw new PlatformError(new Status(Severity.ERROR, platform.status.BadRequest, {})) }