fix: update project disabled messages for clarity and consistency
This commit is contained in:
@@ -52,7 +52,15 @@ export class Domains {
|
||||
const isDisabled = await SecurityService.isProjectDisabled(projectId);
|
||||
if (isDisabled) {
|
||||
throw new NotAllowed(
|
||||
'Cannot add domains to a disabled project. Please contact support to resolve security violations before making changes.',
|
||||
'This project has been disabled. Please contact support for assistance.',
|
||||
);
|
||||
}
|
||||
|
||||
// Block subdomains whose root domain belongs to a disabled project
|
||||
const rootCheck = await DomainService.checkSubdomainOfDisabledRoot(domain);
|
||||
if (rootCheck.blocked) {
|
||||
throw new NotAllowed(
|
||||
'This domain cannot be added at this time. Please contact support for assistance.',
|
||||
);
|
||||
}
|
||||
|
||||
@@ -138,7 +146,7 @@ export class Domains {
|
||||
const isDisabled = await SecurityService.isProjectDisabled(domain.projectId);
|
||||
if (isDisabled) {
|
||||
throw new NotAllowed(
|
||||
'Cannot remove domains from a disabled project. Please contact support to resolve security violations before making changes.',
|
||||
'This project has been disabled. Please contact support for assistance.',
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ export class Users {
|
||||
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.`,
|
||||
`You cannot create new projects at this time. Please contact support for assistance.`,
|
||||
ErrorCode.PROJECT_DISABLED,
|
||||
);
|
||||
}
|
||||
@@ -615,7 +615,7 @@ export class Users {
|
||||
if (isDisabled) {
|
||||
throw new HttpException(
|
||||
403,
|
||||
'Cannot reset a disabled project. Please contact support to resolve security violations before making changes.',
|
||||
'This project has been disabled. Please contact support for assistance.',
|
||||
ErrorCode.PROJECT_DISABLED,
|
||||
);
|
||||
}
|
||||
@@ -703,7 +703,7 @@ export class Users {
|
||||
if (project.disabled) {
|
||||
throw new HttpException(
|
||||
403,
|
||||
'Cannot delete a disabled project. Please contact support to resolve security violations.',
|
||||
'This project has been disabled. Please contact support for assistance.',
|
||||
ErrorCode.PROJECT_DISABLED,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -170,13 +170,11 @@ export async function createEmailWorker() {
|
||||
where: {id: emailId},
|
||||
data: {
|
||||
status: EmailStatus.FAILED,
|
||||
error: `Phishing content detected with ${phishingCheck.confidence}% confidence - project disabled`,
|
||||
error: 'This email could not be sent. The project has been disabled. Please contact support.',
|
||||
},
|
||||
});
|
||||
|
||||
throw new Error(
|
||||
`Phishing content detected with ${phishingCheck.confidence}% confidence - project ${email.projectId} disabled`,
|
||||
);
|
||||
throw new Error(`Project ${email.projectId} has been disabled due to a policy violation`);
|
||||
}
|
||||
|
||||
// Send via AWS SES
|
||||
|
||||
@@ -135,7 +135,7 @@ export const requirePublicKey = async (req: Request, res: Response, next: NextFu
|
||||
if (isWriteOperation) {
|
||||
throw new HttpException(
|
||||
403,
|
||||
'Project is disabled due to security violations. All write operations are blocked.',
|
||||
'This project has been disabled. Please contact support for assistance.',
|
||||
ErrorCode.PROJECT_DISABLED,
|
||||
);
|
||||
}
|
||||
@@ -204,7 +204,7 @@ export const requireSecretKey = async (req: Request, res: Response, next: NextFu
|
||||
if (isWriteOperation) {
|
||||
throw new HttpException(
|
||||
403,
|
||||
'Project is disabled due to security violations. All write operations are blocked.',
|
||||
'This project has been disabled. Please contact support for assistance.',
|
||||
ErrorCode.PROJECT_DISABLED,
|
||||
);
|
||||
}
|
||||
@@ -271,7 +271,7 @@ export const requireAuth = async (req: Request, res: Response, next: NextFunctio
|
||||
if (isWriteOperation) {
|
||||
throw new HttpException(
|
||||
403,
|
||||
'Project is disabled due to security violations. All write operations are blocked.',
|
||||
'This project has been disabled. Please contact support for assistance.',
|
||||
ErrorCode.PROJECT_DISABLED,
|
||||
);
|
||||
}
|
||||
@@ -315,7 +315,7 @@ export const requireAuth = async (req: Request, res: Response, next: NextFunctio
|
||||
if (isWriteOperation) {
|
||||
throw new HttpException(
|
||||
403,
|
||||
'Project is disabled due to security violations. All write operations are blocked.',
|
||||
'This project has been disabled. Please contact support for assistance.',
|
||||
ErrorCode.PROJECT_DISABLED,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -388,6 +388,49 @@ export class DomainService {
|
||||
return domain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the registrable root domain (last two labels) from a domain name.
|
||||
* e.g. "mail.example.com" → "example.com", "example.com" → "example.com"
|
||||
*/
|
||||
private static rootDomain(domain: string): string {
|
||||
const parts = domain.split('.');
|
||||
return parts.length > 2 ? parts.slice(-2).join('.') : domain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the root domain of `domain` is owned by a disabled project.
|
||||
* Prevents subdomains from being added when the parent domain is flagged.
|
||||
*/
|
||||
public static async checkSubdomainOfDisabledRoot(
|
||||
domain: string,
|
||||
): Promise<{blocked: boolean; projectName?: string; projectId?: string}> {
|
||||
const root = this.rootDomain(domain);
|
||||
|
||||
// Only relevant when the submitted domain is actually a subdomain
|
||||
if (root === domain) {
|
||||
return {blocked: false};
|
||||
}
|
||||
|
||||
const rootDomainRecord = await prisma.domain.findFirst({
|
||||
where: {domain: root},
|
||||
include: {
|
||||
project: {
|
||||
select: {id: true, name: true, disabled: true},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (rootDomainRecord?.project.disabled) {
|
||||
return {
|
||||
blocked: true,
|
||||
projectName: rootDomainRecord.project.name,
|
||||
projectId: rootDomainRecord.project.id,
|
||||
};
|
||||
}
|
||||
|
||||
return {blocked: false};
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a domain is already linked to another project
|
||||
* Used when adding a new domain to verify if the user has access to the existing project
|
||||
|
||||
@@ -752,7 +752,7 @@ export class SecurityService {
|
||||
landingUrl: LANDING_URI,
|
||||
});
|
||||
await Promise.all(
|
||||
emails.map(email => sendPlatformEmail(email, 'Project Disabled - Security Risk', template)),
|
||||
emails.map(email => sendPlatformEmail(email, 'Project Disabled', template)),
|
||||
);
|
||||
}
|
||||
} catch (emailError) {
|
||||
@@ -974,7 +974,7 @@ ${strippedBody.substring(0, 2000)}`,
|
||||
data: {disabled: true},
|
||||
});
|
||||
|
||||
const violation = `Phishing content detected with ${confidence}% confidence in email: "${subject}"${reason ? ` - ${reason}` : ''}`;
|
||||
const violation = `A policy violation was detected. Please contact support for more details.`;
|
||||
|
||||
// Log critical security event
|
||||
signale.error(
|
||||
@@ -1006,7 +1006,7 @@ ${strippedBody.substring(0, 2000)}`,
|
||||
landingUrl: LANDING_URI,
|
||||
});
|
||||
await Promise.all(
|
||||
emails.map(email => sendPlatformEmail(email, 'Project Disabled - Phishing Detected', template)),
|
||||
emails.map(email => sendPlatformEmail(email, 'Project Disabled', template)),
|
||||
);
|
||||
}
|
||||
} catch (emailError) {
|
||||
|
||||
Reference in New Issue
Block a user