fix: Add additional checks for disabled projects

This commit is contained in:
Dries Augustyns
2025-12-16 11:52:53 +01:00
parent 780741e37f
commit 863e784e1c
5 changed files with 51 additions and 3 deletions
+10
View File
@@ -121,6 +121,16 @@ SMTP_DOMAIN=smtp.example.com
# PLUNK_API_KEY=
# PLUNK_FROM_ADDRESS=
# ========================================
# OPTIONAL: Security Settings
# ========================================
# Controls whether projects are automatically disabled when bounce/complaint rate thresholds are exceeded
# When enabled (default), projects exceeding security limits will be automatically suspended
# When disabled, violations will be logged and notifications sent, but projects won't be auto-disabled
# Recommended for self-hosters: false (manage project status manually)
# Default: true
# AUTO_PROJECT_DISABLE=false
# ========================================
# ADVANCED (rarely needed)
# ========================================
+8
View File
@@ -76,3 +76,11 @@ STRIPE_WEBHOOK_SECRET=
STRIPE_PRICE_ONBOARDING= # Optional: One-time onboarding fee price ID (e.g., price_xxxxx)
STRIPE_PRICE_EMAIL_USAGE= # Required: Metered price ID for pay-per-email billing
STRIPE_METER_EVENT_NAME=emails # Meter event name (API key from your Stripe meter, default: emails)
# ==============================================================================
# Security (Optional)
# ==============================================================================
# Controls whether projects are automatically disabled when bounce/complaint rate thresholds are exceeded
# Set to 'false' to disable automatic project suspension (useful for self-hosters who manage manually)
# Default: true (automatic project disabling enabled)
# AUTO_PROJECT_DISABLE=true
+5
View File
@@ -98,3 +98,8 @@ export const SMTP_ENABLED =
export const PLUNK_API_KEY = validateEnv('PLUNK_API_KEY', '');
export const PLUNK_FROM_ADDRESS = validateEnv('PLUNK_FROM_ADDRESS', '');
export const PLUNK_ENABLED = PLUNK_API_KEY !== '' && PLUNK_FROM_ADDRESS !== '';
// Security (optional)
// Controls whether projects are automatically disabled when bounce/complaint rate thresholds are exceeded
// Useful for self-hosters who want to manage project status manually
export const AUTO_PROJECT_DISABLE = validateEnv('AUTO_PROJECT_DISABLE', 'true') === 'true';
+25 -3
View File
@@ -7,7 +7,7 @@ import {redis} from '../database/redis.js';
import {Keys} from './keys.js';
import {NtfyService} from './NtfyService.js';
import {QueueService} from './QueueService.js';
import {DASHBOARD_URI, LANDING_URI} from '../app/constants.js';
import {AUTO_PROJECT_DISABLE, DASHBOARD_URI, LANDING_URI} from '../app/constants.js';
/**
* Security thresholds for bounce and complaint rates
@@ -110,9 +110,31 @@ export class SecurityService {
// Get current security status
const status = await this.getSecurityStatus(projectId);
// If project should be disabled, disable it
if (status.shouldDisable) {
// If project should be disabled, disable it (only if auto-disable is enabled)
if (status.shouldDisable && AUTO_PROJECT_DISABLE) {
await this.disableProject(projectId, status);
} else if (status.shouldDisable && !AUTO_PROJECT_DISABLE) {
// Log critical violations but don't auto-disable (self-hosted mode)
const project = await prisma.project.findUnique({
where: {id: projectId},
select: {name: true},
});
if (project) {
signale.error(
`[SECURITY] Project ${projectId} (${project.name}) has CRITICAL security violations but auto-disable is turned off:`,
status.violations,
);
signale.info(
`[SECURITY] 7-day stats: ${status.sevenDay.bounces} bounces, ${status.sevenDay.complaints} complaints out of ${status.sevenDay.total} emails`,
);
signale.info(
`[SECURITY] All-time stats: ${status.allTime.bounces} bounces, ${status.allTime.complaints} complaints out of ${status.allTime.total} emails`,
);
// Send notification about critical security violations
await NtfyService.notifySecurityWarning(project.name, projectId, status.violations);
}
} else if (status.warnings.length > 0) {
// Log warnings for monitoring
signale.warn(`[SECURITY] Project ${projectId} has security warnings:`, status.warnings);
+3
View File
@@ -187,6 +187,9 @@ services:
PLUNK_API_KEY: ${PLUNK_API_KEY:-}
PLUNK_FROM_ADDRESS: ${PLUNK_FROM_ADDRESS:-}
# Security
AUTO_PROJECT_DISABLE: ${AUTO_PROJECT_DISABLE:-false}
volumes:
# Persistent storage for application data
- plunk_data:/app/data