|
|
|
|
@ -2,6 +2,7 @@
|
|
|
|
|
|
|
|
|
|
use App\Mail\CuratedRegisterNotifyAdmin;
|
|
|
|
|
use App\Mail\CuratedRegisterNotifyAdminUserResponse;
|
|
|
|
|
use App\Mail\CuratedRegisterRequestDetailsFromUser;
|
|
|
|
|
use App\Models\CuratedRegister;
|
|
|
|
|
use App\Models\CuratedRegisterActivity;
|
|
|
|
|
use Illuminate\Foundation\Testing\LazilyRefreshDatabase;
|
|
|
|
|
@ -43,3 +44,27 @@ it('escapes user-provided content in the admin notification emails', function ()
|
|
|
|
|
expect($responseHtml)->not->toContain('<script>alert(2)</script>');
|
|
|
|
|
expect($responseHtml)->toContain('<script>');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
| request-details-from-user is rendered as an HTTP response by the admin
|
|
|
|
|
| previewDetailsMessageShow endpoint, which reflects a GET `message` param into
|
|
|
|
|
| $activity->message. It must escape the message to prevent reflected XSS, the
|
|
|
|
|
| same way its sibling admin templates do.
|
|
|
|
|
*/
|
|
|
|
|
it('escapes the message in the request-details-from-user mailable', function () {
|
|
|
|
|
$verify = new CuratedRegister;
|
|
|
|
|
$verify->username = 'attacker';
|
|
|
|
|
$verify->email = 'attacker@example.com';
|
|
|
|
|
$verify->save();
|
|
|
|
|
|
|
|
|
|
$activity = new CuratedRegisterActivity;
|
|
|
|
|
$activity->register_id = $verify->id;
|
|
|
|
|
$activity->message = '<img src=x onerror=alert(1)>';
|
|
|
|
|
$activity->save();
|
|
|
|
|
|
|
|
|
|
$detailsHtml = (new CuratedRegisterRequestDetailsFromUser($verify, $activity))->render();
|
|
|
|
|
|
|
|
|
|
// The raw <img> tag and its onerror handler must not survive as live HTML.
|
|
|
|
|
expect($detailsHtml)->not->toContain('<img src=x onerror=');
|
|
|
|
|
expect($detailsHtml)->toContain('<img src=x onerror=alert(1)>');
|
|
|
|
|
});
|
|
|
|
|
|