diff --git a/packages/server/src/enterprise/controllers/account.controller.ts b/packages/server/src/enterprise/controllers/account.controller.ts index 4878b0ea3..794971d9c 100644 --- a/packages/server/src/enterprise/controllers/account.controller.ts +++ b/packages/server/src/enterprise/controllers/account.controller.ts @@ -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 +} diff --git a/packages/server/src/enterprise/services/account.service.ts b/packages/server/src/enterprise/services/account.service.ts index 14aef1d86..c1a88b339 100644 --- a/packages/server/src/enterprise/services/account.service.ts +++ b/packages/server/src/enterprise/services/account.service.ts @@ -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 +/** Optional referral field for Stripe referral tracking in CLOUD; not a User entity column. */ +type RegistrationUser = Partial & { referral?: string } + +export type AccountDTO = { + user: RegistrationUser organization: Partial organizationUser: Partial workspace: Partial @@ -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 diff --git a/packages/server/src/enterprise/services/user.service.ts b/packages/server/src/enterprise/services/user.service.ts index 069e70da0..bb88988f6 100644 --- a/packages/server/src/enterprise/services/user.service.ts +++ b/packages/server/src/enterprise/services/user.service.ts @@ -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 diff --git a/packages/ui/src/views/organization/index.jsx b/packages/ui/src/views/organization/index.jsx index 72886d114..5b07dc612 100644 --- a/packages/ui/src/views/organization/index.jsx +++ b/packages/ui/src/views/organization/index.jsx @@ -145,7 +145,6 @@ const OrganizationSetupPage = () => { user: { name: username, email: email, - type: 'pro', credential: password } }