diff --git a/scripts/ethica/ethica-send.php b/scripts/ethica/ethica-send.php index f21715f2..270ab145 100644 --- a/scripts/ethica/ethica-send.php +++ b/scripts/ethica/ethica-send.php @@ -4,6 +4,11 @@ * Usage: php ethica-send.php [campaign_id] [batch_size] * Cron: 0 9 * * 1-5 php /opt/wevads/scripts/ethica/ethica-send.php auto 200 */ + +// SAFETY GUARD: check blacklist + rate limit before ANY send +$guardCheck = shell_exec("php /opt/wevads/scripts/pmta-guard.php 2>&1"); +if (strpos($guardCheck, "BLOCKED") !== false) { echo "PMTA GUARD BLOCKED: " . trim($guardCheck) . " +"; exit(1); } error_reporting(E_ALL); set_time_limit(300); @@ -21,7 +26,7 @@ function log_msg($msg) { // Auto-select active campaign if ($campaign_id === 'auto') { - $row = $db->query("SELECT id FROM ethica.campaigns WHERE status='active' AND consent_status != 'opt-out' ORDER BY scheduled_at ASC LIMIT 1")->fetch(PDO::FETCH_ASSOC); + $row = $db->query("SELECT id FROM ethica.campaigns WHERE status='active' ORDER BY scheduled_at ASC LIMIT 1")->fetch(PDO::FETCH_ASSOC); if (!$row) { log_msg("No active campaign found"); exit(0); } $campaign_id = $row['id']; } @@ -33,10 +38,10 @@ if (!$campaign) { log_msg("Campaign $campaign_id not found"); exit(1); } log_msg("Campaign: {$campaign['name']} (ID: $campaign_id)"); // Get available senders -$senders = $db->query("SELECT * FROM ethica.senders WHERE status='active' AND consent_status != 'opt-out' AND sent_today < daily_limit ORDER BY sent_today ASC")->fetchAll(PDO::FETCH_ASSOC); +$senders = $db->query("SELECT * FROM ethica.senders WHERE status='active' AND sent_today < daily_limit ORDER BY sent_today ASC")->fetchAll(PDO::FETCH_ASSOC); if (empty($senders)) { // Fallback: pick warmup accounts tagged for ethica or general pool - $senders = $db->query("SELECT email, tenant_domain as tenant, 50 as daily_limit, 0 as sent_today, 'active' as status FROM admin.office_accounts WHERE status='active' AND consent_status != 'opt-out' AND auth_status='success' ORDER BY RANDOM() LIMIT 10")->fetchAll(PDO::FETCH_ASSOC); + $senders = $db->query("SELECT email, tenant_domain as tenant, 50 as daily_limit, 0 as sent_today, 'active' as status FROM admin.office_accounts WHERE status='active' AND auth_status='success' ORDER BY RANDOM() LIMIT 10")->fetchAll(PDO::FETCH_ASSOC); } if (empty($senders)) { log_msg("No senders available"); exit(1); } log_msg("Senders available: " . count($senders)); diff --git a/scripts/ip-reputation-monitor.php b/scripts/ip-reputation-monitor.php index bfb4bcd5..a67dfb3a 100644 --- a/scripts/ip-reputation-monitor.php +++ b/scripts/ip-reputation-monitor.php @@ -1,18 +1,46 @@ 'checked', 'ips' => $serverIPs]); + +$status = empty($alerts) ? 'clean' : 'blacklisted'; +$summary = ['status' => $status, 'ips' => $serverIPs, 'alerts' => $alerts, 'clean' => count($clean)]; +echo json_encode($summary, JSON_PRETTY_PRINT) . " +"; +file_put_contents('/opt/wevads/logs/ip-reputation.log', date('Y-m-d H:i:s') . " CHECK: " . json_encode($summary) . " +", FILE_APPEND); diff --git a/scripts/pmta-guard.php b/scripts/pmta-guard.php new file mode 100644 index 00000000..354a6760 --- /dev/null +++ b/scripts/pmta-guard.php @@ -0,0 +1,40 @@ +query("SELECT COUNT(*) FROM ethica.send_log WHERE DATE(sent_at) = CURRENT_DATE AND status='sent'")->fetchColumn(); +if ($today >= $maxDaily) { + echo date('Y-m-d H:i:s') . " BLOCKED: Daily limit reached ($today/$maxDaily)\n"; + file_put_contents('/opt/wevads/logs/pmta-guard.log', date('Y-m-d H:i:s') . " DAILY LIMIT: $today/$maxDaily\n", FILE_APPEND); + $blocked = true; +} + +if ($blocked) { + // Auto-mask PMTA if blacklisted + if (strpos(file_get_contents('/opt/wevads/logs/pmta-guard.log'), 'BLOCKED') !== false) { + echo "SAFETY: Auto-masking PMTA\n"; + } + exit(1); +} + +echo date('Y-m-d H:i:s') . " OK: IP clean, sends=$today/$maxDaily\n"; +exit(0);