83 lines
4.3 KiB
PHP
83 lines
4.3 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
require __DIR__ . '/tracking.php';
|
|
|
|
$policy = new \Box\Mod\Mailgateway\InboundPolicy();
|
|
$cases = [
|
|
[['auto_submitted' => 'auto-replied'], 'auto_submitted'],
|
|
[['auto_submitted' => 'Auto-Generated; owner-email="support@example.com"'], 'auto_submitted'],
|
|
[['headers' => ['AUTO-SUBMITTED' => ['no', 'auto-replied']]], 'auto_submitted'],
|
|
[['return_path' => '<>'], 'null_return_path'],
|
|
[['content_type' => 'multipart/report; report-type=delivery-status; boundary=abc'], 'delivery_report'],
|
|
[['content_type' => 'message/disposition-notification'], 'delivery_report'],
|
|
[['precedence' => 'bulk'], 'bulk_mail'],
|
|
[['precedence' => 'LIST'], 'bulk_mail'],
|
|
[['list_id' => 'Announcements <list.example.com>'], 'mailing_list'],
|
|
[['x_auto_response_suppress' => 'All'], 'response_suppressed'],
|
|
[['x_auto_response_suppress' => 'DR, OOF, AutoReply'], 'response_suppressed'],
|
|
[['x_autoreply' => 'yes'], 'legacy_autoresponder'],
|
|
[['x_autorespond' => 'true'], 'legacy_autoresponder'],
|
|
];
|
|
$messageCount = (int) $connection->fetchOne('SELECT COUNT(*) FROM test_messages');
|
|
$notifications = $trackingService->notifications;
|
|
foreach ($cases as $index => [$fields, $reason]) {
|
|
$input = array_merge([
|
|
'mailbox' => 'support@dev.sebs.space',
|
|
'message_id' => '<automatic-' . $index . '@example.com>',
|
|
// Would normally reject this mismatched reply and send a notification.
|
|
'subject' => 'Re: [Ticket #41] Test',
|
|
'sender_email' => 'wrong@example.com',
|
|
'content' => 'Away from the office',
|
|
], $fields);
|
|
$result = $tracker->process($input, $trackingService);
|
|
if ($result !== ['action' => 'ignored', 'reason' => $reason, 'duplicate' => false]) {
|
|
throw new RuntimeException('Automatic message was not ignored: ' . $index);
|
|
}
|
|
$repeat = $tracker->process($input, $trackingService);
|
|
if (!$repeat['duplicate'] || $repeat['action'] !== 'ignored') {
|
|
throw new RuntimeException('Ignored message retry was not deduplicated');
|
|
}
|
|
$row = $connection->fetchAssociative('SELECT ticket_id FROM mailgateway_message WHERE message_id = ?', [$input['message_id']]);
|
|
if (!$row || $row['ticket_id'] !== null) {
|
|
throw new RuntimeException('Ignored mail acquired a ticket association');
|
|
}
|
|
// The underlying service methods must also skip without database or mail access.
|
|
$guardedService = new \Box\Mod\Mailgateway\Service();
|
|
foreach (['import', 'reply'] as $method) {
|
|
if ($guardedService->$method($fields) !== ['action' => 'ignored', 'reason' => $reason]) {
|
|
throw new RuntimeException('Service method responded to automatic mail');
|
|
}
|
|
}
|
|
}
|
|
$minimal = $tracker->process([
|
|
'mailbox' => 'support@dev.sebs.space', 'message_id' => '<minimal-auto@example.com>',
|
|
'auto_submitted' => 'auto-replied',
|
|
], $trackingService);
|
|
if ($minimal['action'] !== 'ignored'
|
|
|| (int) $connection->fetchOne('SELECT COUNT(*) FROM test_messages') !== $messageCount
|
|
|| $trackingService->notifications !== $notifications) {
|
|
throw new RuntimeException('Automatic mail created a message or sent a notification');
|
|
}
|
|
foreach ([[], ['auto_submitted' => 'NO'], ['auto_submitted' => 'no; extension=value'],
|
|
['return_path' => '<customer@example.com>'], ['content_type' => 'text/plain; charset=utf-8'],
|
|
['x_auto_response_suppress' => 'None'], ['x_autoreply' => 'false']] as $fields) {
|
|
if ($policy->ignoreReason($policy->headers($fields)) !== null) {
|
|
throw new RuntimeException('Normal message classified as automatic');
|
|
}
|
|
}
|
|
$folded = $policy->headers(['headers' => ['Auto-Submitted' => "auto-replied;\r\n owner=test"]]);
|
|
if ($policy->ignoreReason($folded) !== 'auto_submitted') {
|
|
throw new RuntimeException('Folded header failed');
|
|
}
|
|
try {
|
|
$policy->headers(['auto_submitted' => "no\r\nInjected: value"]);
|
|
throw new RuntimeException('Header injection accepted');
|
|
} catch (\FOSSBilling\InformationException) {}
|
|
try {
|
|
$tracker->process(array_merge($input, ['auto_submitted' => 'no']), $trackingService);
|
|
throw new RuntimeException('Changed detection headers bypassed deduplication');
|
|
} catch (\FOSSBilling\InformationException) {}
|
|
echo "Passed automatic-message filtering, repeated/mixed/folded headers, ignored-message deduplication, no ticket writes or notifications, service method protection, and normal-mail exceptions.\n";
|