Files
huntingclubroster/classes/MfaSecurityNotifications.php

29 lines
2.1 KiB
PHP

<?php
/** Security notices contain event details, never authenticator or recovery secrets. */
class MfaSecurityNotifications extends Base {
public function send(array $account,string $event): bool {
$events=[
'enrolled'=>'An authenticator was added to your account.',
'replacement_started'=>'An authenticator replacement was requested. Your existing authenticator remains active until replacement is confirmed.',
'replacement_started_recovery'=>'A single-use recovery code was used to request authenticator replacement. Your existing authenticator remains active until replacement is confirmed.',
'replaced'=>'Your authenticator was replaced. Old recovery codes and other sign-in sessions have been revoked.',
'recovery_used'=>'A single-use recovery code was used to authenticate your account.'
];
if(!isset($events[$event]))throw new LogicException('Unknown MFA notification event.');
$h=static fn($text)=>htmlspecialchars((string)$text,ENT_QUOTES,'UTF-8');
$body='<p>'.$h($events[$event]).'</p><p>Account: '.$h($account['user_email']).'<br>Time (UTC): '.$h(gmdate('Y-m-d H:i:s')).'</p><p>If you did not authorize this activity, contact your site administrator immediately and secure your account.</p>';
$ok=false;
try{$ok=$this->deliver((string)$account['user_email'],self::APPLICATION_NAME.' - Account security notice',$body);}
catch(Throwable $error){/* Keep secrets and provider diagnostics out of this event log. */}
if(!$ok)error_log('MFA security notification failed user='.(int)$account['user_serial'].' event='.$event);
return $ok;
}
protected function deliver(string $to,string $subject,string $body): bool {return (new Email())->sendEmail($to,$subject,$body);}
public static function notice(): string {
if(empty($_SESSION['mfa_notification_warning']))return '';
unset($_SESSION['mfa_notification_warning']);
return '<p class="alert alert-warning" role="alert">Your security action succeeded, but its notification email could not be sent. Please contact support.</p>';
}
}