mirror of
https://github.com/FlowiseAI/Flowise.git
synced 2026-10-12 02:02:17 +00:00
Fix improper mass assignment in account registration (#5689)
* Sanitize account information during registration * Fix Improper Mass Assignment in Account Registration * Update account.service.ts * Fix improper mass assignment in account registration * Fix improper mass assignment in account registration * Update packages/server/src/enterprise/controllers/account.controller.ts Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * Update packages/server/src/enterprise/controllers/account.controller.ts Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * fix(account.controller.ts): remove additional } * chore(organization/index.jsx): remove hardcoded user type pro from organization setup --------- Co-authored-by: yau-wd <[email protected]> Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
This commit is contained in:
co-authored by
gemini-code-assist[bot]
yau-wd
parent
4b1b8ba376
commit
1e4b0d8788
@@ -1,13 +1,16 @@
|
||||
import { NextFunction, Request, Response } from 'express'
|
||||
import { StatusCodes } from 'http-status-codes'
|
||||
import { getRunningExpressApp } from '../../utils/getRunningExpressApp'
|
||||
import { AccountService } from '../services/account.service'
|
||||
import { Organization } from '../database/entities/organization.entity'
|
||||
import { User } from '../database/entities/user.entity'
|
||||
import { AccountDTO, AccountService } from '../services/account.service'
|
||||
|
||||
export class AccountController {
|
||||
public async register(req: Request, res: Response, next: NextFunction) {
|
||||
try {
|
||||
const accountService = new AccountService()
|
||||
const data = await accountService.register(req.body)
|
||||
const sanitizedBody = sanitizeRegistrationDTO(req.body)
|
||||
const data = await accountService.register(sanitizedBody)
|
||||
return res.status(StatusCodes.CREATED).json(data)
|
||||
} catch (error) {
|
||||
next(error)
|
||||
@@ -134,3 +137,42 @@ export class AccountController {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function sanitizeRegistrationDTO(data: AccountDTO): AccountDTO {
|
||||
const sanitized: AccountDTO = {
|
||||
user: {},
|
||||
organization: {},
|
||||
organizationUser: {},
|
||||
workspace: {},
|
||||
workspaceUser: {},
|
||||
role: {}
|
||||
}
|
||||
|
||||
// Strict allowlist: only fields a client may supply during registration.
|
||||
// Never accept server-managed fields: id, createdBy, updatedBy, createdDate, updatedDate, status, tokenExpiry.
|
||||
const allowedUserFields: (keyof User)[] = ['name', 'email', 'credential', 'tempToken']
|
||||
if (data.user && typeof data.user === 'object' && !Array.isArray(data.user)) {
|
||||
for (const field of allowedUserFields) {
|
||||
const value = data.user[field]
|
||||
if (value != null) {
|
||||
sanitized.user[field] = value as any
|
||||
}
|
||||
}
|
||||
if (data.user.referral != null) {
|
||||
sanitized.user.referral = data.user.referral
|
||||
}
|
||||
}
|
||||
|
||||
// Allow organization.name for Enterprise owner registration (the only path that doesn't hardcode it).
|
||||
const allowedOrgFields: (keyof Organization)[] = ['name']
|
||||
if (data.organization && typeof data.organization === 'object' && !Array.isArray(data.organization)) {
|
||||
for (const field of allowedOrgFields) {
|
||||
const value = data.organization[field]
|
||||
if (value != null) {
|
||||
sanitized.organization[field] = value as any
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return sanitized
|
||||
}
|
||||
|
||||
@@ -29,8 +29,11 @@ import { UserErrorMessage, UserService } from './user.service'
|
||||
import { WorkspaceUserErrorMessage, WorkspaceUserService } from './workspace-user.service'
|
||||
import { WorkspaceErrorMessage, WorkspaceService } from './workspace.service'
|
||||
|
||||
type AccountDTO = {
|
||||
user: Partial<User>
|
||||
/** Optional referral field for Stripe referral tracking in CLOUD; not a User entity column. */
|
||||
type RegistrationUser = Partial<User> & { referral?: string }
|
||||
|
||||
export type AccountDTO = {
|
||||
user: RegistrationUser
|
||||
organization: Partial<Organization>
|
||||
organizationUser: Partial<OrganizationUser>
|
||||
workspace: Partial<Workspace>
|
||||
@@ -138,7 +141,6 @@ export class AccountService {
|
||||
const { customerId, subscriptionId } = await this.identityManager.createStripeUserAndSubscribe({
|
||||
email: data.user.email,
|
||||
userPlan: UserPlan.FREE,
|
||||
// @ts-ignore
|
||||
referral: data.user.referral || ''
|
||||
})
|
||||
data.organization.customerId = customerId
|
||||
|
||||
@@ -88,10 +88,11 @@ export class UserService {
|
||||
if (data.status) this.validateUserStatus(data.status)
|
||||
|
||||
data.id = generateId()
|
||||
if (data.createdBy) {
|
||||
const createdBy = await this.readUserById(data.createdBy, queryRunner)
|
||||
if (!createdBy) throw new InternalFlowiseError(StatusCodes.NOT_FOUND, UserErrorMessage.USER_NOT_FOUND)
|
||||
data.createdBy = createdBy.id
|
||||
const createdById = data.createdBy
|
||||
if (createdById) {
|
||||
const createdByUser = await this.readUserById(createdById, queryRunner)
|
||||
if (!createdByUser) throw new InternalFlowiseError(StatusCodes.NOT_FOUND, UserErrorMessage.USER_NOT_FOUND)
|
||||
data.createdBy = createdByUser.id
|
||||
data.updatedBy = data.createdBy
|
||||
} else {
|
||||
data.createdBy = data.id
|
||||
|
||||
@@ -145,7 +145,6 @@ const OrganizationSetupPage = () => {
|
||||
user: {
|
||||
name: username,
|
||||
email: email,
|
||||
type: 'pro',
|
||||
credential: password
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user