death-notifier/src/main/php/com/fwdekker/deathnotifier/user/VerifyEmailAction.php

86 lines
3.3 KiB
PHP

<?php
namespace com\fwdekker\deathnotifier\user;
use com\fwdekker\deathnotifier\Action;
use com\fwdekker\deathnotifier\Util;
use com\fwdekker\deathnotifier\validation\InvalidTypeException;
use com\fwdekker\deathnotifier\validation\InvalidValueException;
use com\fwdekker\deathnotifier\validation\IsEmailRule;
use com\fwdekker\deathnotifier\validation\IsStringRule;
use com\fwdekker\deathnotifier\validation\IsValidCsrfTokenRule;
use com\fwdekker\deathnotifier\validation\RuleSet;
/**
* Verifies the user's email address.
*/
class VerifyEmailAction extends Action
{
/**
* @var UserList the list to verify the email address in
*/
private readonly UserList $user_list;
/**
* Constructs a new `VerifyEmailAction`.
*
* @param UserList $user_list the list to verify the email address in
*/
public function __construct(UserList $user_list)
{
$this->user_list = $user_list;
}
/**
* Verifies the user's email address.
*
* Requires that a valid CSRF token is present. Does not require the user to be logged in or out.
*
* @param array<int|string, mixed> $inputs `"token": string`: a valid CSRF token, `"email"`: the email address to
* verify, `"verify_token": string`: the token to verify the email address with
* @return null
* @throws InvalidTypeException if any of the inputs has the incorrect type
* @throws InvalidValueException if no valid CSRF token is present, if no account with the given email address
* exists, if the reset token is invalid, or if the reset token has expired
*/
public function handle(array $inputs): mixed
{
(new RuleSet([
"token" => [new IsValidCsrfTokenRule()],
"email" => [new IsEmailRule()],
"verify_token" => [new IsStringRule()],
]))->check($inputs);
$this->user_list->transaction(function () use ($inputs) {
$user_data = $this->user_list->get_user_by_email($inputs["email"]);
if ($user_data === null)
throw new InvalidValueException("No user with that email address has been registered.");
if ($user_data["email_verification_token"] === null)
throw new InvalidValueException("Your email address is already verified. You can close this page.");
if ($inputs["verify_token"] !== $user_data["email_verification_token"])
throw new InvalidValueException(
"This verification link is invalid. " .
"This may happen if you recently changed your email address or you requested another " .
"verification link, in which case a new verification link should arrive in your inbox soon. " .
"If this does not happen, log in and request a new verification email."
);
$minutes_left = Util::minutes_until_interval_elapsed(
$user_data["email_verification_token_timestamp"],
UserList::MINUTES_VALID_VERIFICATION
);
if ($minutes_left < 0)
throw new InvalidValueException(
"This email verification link has expired. Log in and request a new verification email."
);
$this->user_list->set_email_verified($_SESSION["uuid"]);
});
return null;
}
}