fix: Add additional checks for disabled projects

This commit is contained in:
Dries Augustyns
2025-12-15 07:41:21 +01:00
parent e50c33ae4b
commit 780741e37f
2 changed files with 74 additions and 2 deletions
+32 -2
View File
@@ -7,7 +7,7 @@ import type {NextFunction, Request, Response} from 'express';
import {DASHBOARD_URI, STRIPE_ENABLED, STRIPE_PRICE_EMAIL_USAGE, STRIPE_PRICE_ONBOARDING} from '../app/constants.js';
import {stripe} from '../app/stripe.js';
import {prisma} from '../database/prisma.js';
import {NotAuthenticated, NotFound} from '../exceptions/index.js';
import {ErrorCode, HttpException, NotAuthenticated, NotFound} from '../exceptions/index.js';
import type {AuthResponse} from '../middleware/auth.js';
import {isAuthenticated} from '../middleware/auth.js';
import {BillingLimitService} from '../services/BillingLimitService.js';
@@ -63,6 +63,16 @@ export class Users {
throw new NotAuthenticated();
}
// Check if user is a member of any disabled project
const {hasDisabledProject, disabledProjectNames} = await SecurityService.userHasDisabledProject(auth.userId);
if (hasDisabledProject) {
throw new HttpException(
403,
`You cannot create new projects while you are a member of disabled projects: ${disabledProjectNames.join(', ')}. Please contact support to resolve security violations.`,
ErrorCode.PROJECT_DISABLED,
);
}
const {name} = ProjectSchemas.create.parse(req.body);
// Generate unique API keys
@@ -692,6 +702,16 @@ export class Users {
throw new NotFound('Project not found or you do not have permission to reset it');
}
// Check if project is disabled - block reset operation
const isDisabled = await SecurityService.isProjectDisabled(id);
if (isDisabled) {
throw new HttpException(
403,
'Cannot reset a disabled project. Please contact support to resolve security violations before making changes.',
ErrorCode.PROJECT_DISABLED,
);
}
// Delete all project data in a transaction
await prisma.$transaction(async tx => {
// Delete all emails
@@ -770,13 +790,14 @@ export class Users {
);
}
// Get project to check for active subscription
// Get project to check for active subscription and disabled status
const project = await prisma.project.findUnique({
where: {id},
select: {
name: true,
subscription: true,
customer: true,
disabled: true,
},
});
@@ -784,6 +805,15 @@ export class Users {
throw new NotFound('Project not found');
}
// Check if project is disabled - block delete operation
if (project.disabled) {
throw new HttpException(
403,
'Cannot delete a disabled project. Please contact support to resolve security violations.',
ErrorCode.PROJECT_DISABLED,
);
}
// If project has an active subscription, cancel it first
if (STRIPE_ENABLED && stripe && project.subscription) {
try {
+42
View File
@@ -147,6 +147,48 @@ export class SecurityService {
}
}
/**
* Check if a user is a member of any disabled project
* Users with disabled projects cannot create new projects
*/
public static async userHasDisabledProject(userId: string): Promise<{
hasDisabledProject: boolean;
disabledProjectNames: string[];
}> {
const disabledMemberships = await prisma.membership.findMany({
where: {
userId,
project: {
disabled: true,
},
},
include: {
project: {
select: {
name: true,
},
},
},
});
return {
hasDisabledProject: disabledMemberships.length > 0,
disabledProjectNames: disabledMemberships.map(m => m.project.name),
};
}
/**
* Check if a specific project is disabled
*/
public static async isProjectDisabled(projectId: string): Promise<boolean> {
const project = await prisma.project.findUnique({
where: {id: projectId},
select: {disabled: true},
});
return project?.disabled ?? false;
}
/**
* Get a project's security metrics (for admin/dashboard display)
*/