CluPilotCloud/tests/Feature/Security/SecurityBlockMailTest.php

70 lines
2.9 KiB
PHP

<?php
// tests/Feature/Security/SecurityBlockMailTest.php
use App\Mail\SecurityBlockMail;
use App\Models\Instance;
use App\Models\Mailbox;
use App\Models\SecurityBlock;
use App\Services\Mail\MailPurpose;
use App\Services\Mail\MailRoute;
use App\Services\Security\BlockAddress;
use App\Support\Settings;
use Illuminate\Support\Facades\Mail;
// Blank slate statt der migrationseigenen fuenf Postfaecher (no-reply,
// support, billing, office, info): der letzte Test unten legt selbst eines
// mit dem Schluessel 'no-reply' an, und das kollidiert sonst mit
// mailboxes.key's Unique-Constraint gegen die von RefreshDatabase stehen
// gelassene Saat (siehe MailRoutingTest, derselbe Helfer aus tests/Pest.php).
beforeEach(fn () => clearMailboxSeed());
it('schickt dem Inhaber eine Mail, wenn seine Instanz gesperrt wird', function () {
Mail::fake();
$instance = Instance::factory()->create(['status' => 'active', 'vmid' => 101]);
app(BlockAddress::class)->forInstance($instance, '203.0.113.7', 12);
Mail::assertQueued(SecurityBlockMail::class, fn ($m) => $m->hasTo($instance->customer->email));
});
it('schickt hoechstens eine Mail je Instanz und Stunde', function () {
// Ein Angreifer, der Adressen durchwechselt, erzeugt sonst zwanzig Mails —
// und die zwanzigste liest niemand mehr.
Mail::fake();
$instance = Instance::factory()->create(['status' => 'active', 'vmid' => 101]);
app(BlockAddress::class)->forInstance($instance, '203.0.113.7', 12);
app(BlockAddress::class)->forInstance($instance, '203.0.113.8', 12);
app(BlockAddress::class)->forInstance($instance, '203.0.113.9', 12);
Mail::assertQueuedCount(1);
});
it('laesst die Sperre stehen, wenn die Mail scheitert', function () {
// Zustellung ist nicht die Bedingung fuer Schutz. Eine Sperre, die von einem
// kaputten Postfach abhinge, waere genau dann weg, wenn ohnehin schon etwas
// im Argen liegt.
Mail::shouldReceive('to')->andThrow(new RuntimeException('Postfach kaputt'));
$instance = Instance::factory()->create(['status' => 'active', 'vmid' => 101]);
$block = app(BlockAddress::class)->forInstance($instance, '203.0.113.7', 12);
expect($block)->not->toBeNull()
->and(SecurityBlock::count())->toBe(1);
});
it('geht standardmaessig aus dem System-Postfach und folgt der Wegwahl', function () {
Mailbox::factory()->create(['key' => 'no-reply', 'address' => 'no-reply@clupilot.com', 'active' => true]);
$info = Mailbox::factory()->create(['key' => 'info', 'active' => true]);
Settings::set(MailPurpose::settingKey(MailPurpose::SYSTEM), 'no-reply');
$block = SecurityBlock::factory()->create();
expect((new SecurityBlockMail($block))->envelope()->from->address)->toBe('no-reply@clupilot.com');
Settings::set(MailRoute::settingKey('security-block'), 'info');
expect((new SecurityBlockMail($block))->envelope()->from->address)->toBe($info->address);
});