
<center><h2><strong>Ubuntu</strong></h2>
­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­
<!DOCTYPE html>
<html>
<?php

/**
 * Matomo - free/libre analytics platform
 *
 * @link    https://matomo.org
 * @license https://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
 */
namespace Piwik\Plugins\Login;

use Exception;
use Piwik\Access;
use Piwik\Auth\Password;
use Piwik\Auth\PasswordStrength;
use Piwik\Common;
use Piwik\Config;
use Piwik\Container\StaticContainer;
use Piwik\Date;
use Piwik\Exception\RedirectException;
use Piwik\IP;
use Piwik\Log;
use Piwik\Nonce;
use Piwik\Piwik;
use Piwik\Plugins\CoreAdminHome\Emails\UserAcceptInvitationEmail;
use Piwik\Plugins\CoreAdminHome\Emails\UserDeclinedInvitationEmail;
use Piwik\Plugins\LanguagesManager\LanguagesHelper;
use Piwik\Plugins\Login\Security\BruteForceDetection;
use Piwik\Plugins\PrivacyManager\SystemSettings;
use Piwik\Plugins\UsersManager\API as APIUsersManager;
use Piwik\Plugins\UsersManager\Model as UsersModel;
use Piwik\Plugins\UsersManager\UsersManager;
use Piwik\QuickForm2;
use Piwik\Request;
use Piwik\Session;
use Piwik\Session\SessionInitializer;
use Piwik\SettingsPiwik;
use Piwik\Url;
use Piwik\UrlHelper;
use Piwik\View;
/**
 * Login controller
 * @api
 */
class Controller extends \Piwik\Plugin\ControllerAdmin
{
    public const NONCE_CONFIRMRESETPASSWORD = 'loginConfirmResetPassword';
    public const NONCE_CONFIRMCANCELRESETPASSWORD = 'loginConfirmCancelResetPassword';
    /**
     * @var PasswordResetter
     */
    protected $passwordResetter;
    /**
     * @var \Piwik\Auth
     */
    protected $auth;
    /**
     * @var \Piwik\Session\SessionInitializer
     */
    protected $sessionInitializer;
    /**
     * @var BruteForceDetection
     */
    protected $bruteForceDetection;
    /**
     * @var SystemSettings
     */
    protected $systemSettings;
    /*
     * @var PasswordVerifier
     */
    protected $passwordVerify;
    /**
     * @var PasswordStrength
     */
    private $passwordStrength;
    /**
     * Constructor.
     *
     * @param PasswordResetter $passwordResetter
     * @param \Piwik\Auth $auth
     * @param SessionInitializer $sessionInitializer
     * @param PasswordVerifier $passwordVerify
     * @param BruteForceDetection $bruteForceDetection
     * @param SystemSettings $systemSettings
     * @param PasswordStrength $passwordStrength
     */
    public function __construct($passwordResetter = null, $auth = null, $sessionInitializer = null, $passwordVerify = null, $bruteForceDetection = null, $systemSettings = null, $passwordStrength = null)
    {
        parent::__construct();
        if (empty($passwordResetter)) {
            $passwordResetter = new \Piwik\Plugins\Login\PasswordResetter();
        }
        $this->passwordResetter = $passwordResetter;
        if (empty($auth)) {
            $auth = StaticContainer::get('Piwik\\Auth');
        }
        $this->auth = $auth;
        if (empty($passwordVerify)) {
            $passwordVerify = StaticContainer::get('Piwik\\Plugins\\Login\\PasswordVerifier');
        }
        $this->passwordVerify = $passwordVerify;
        if (empty($sessionInitializer)) {
            $sessionInitializer = new \Piwik\Session\SessionInitializer();
        }
        $this->sessionInitializer = $sessionInitializer;
        if (empty($bruteForceDetection)) {
            $bruteForceDetection = StaticContainer::get('Piwik\\Plugins\\Login\\Security\\BruteForceDetection');
        }
        $this->bruteForceDetection = $bruteForceDetection;
        if (empty($systemSettings)) {
            $systemSettings = StaticContainer::get('Piwik\\Plugins\\Login\\SystemSettings');
        }
        $this->systemSettings = $systemSettings;
        if (empty($passwordStrength)) {
            $passwordStrength = StaticContainer::get('Piwik\\Auth\\PasswordStrength');
        }
        $this->passwordStrength = $passwordStrength;
    }
    /**
     * Default action
     *
     * @return string
     */
    public function index()
    {
        return $this->login();
    }
    /**
     * Login form
     *
     * @param string $messageNoAccess Access error message
     * @param bool $infoMessage
     * @return string
     * @internal param string $currentUrl Current URL
     */
    public function login($messageNoAccess = null, $infoMessage = \false)
    {
        $form = new \Piwik\Plugins\Login\FormLogin();
        if ($form->validate()) {
            $nonce = $form->getSubmitValue('form_nonce');
            $messageNoAccess = Nonce::verifyNonceWithErrorMessage('Login.login', $nonce, null);
            // validate if there is error message
            if ($messageNoAccess === "") {
                $loginOrEmail = $form->getSubmitValue('form_login');
                $login = $this->getLoginFromLoginOrEmail($loginOrEmail);
                $password = $form->getSubmitValue('form_password');
                try {
                    $this->authenticateAndRedirect($login, $password);
                } catch (Exception $e) {
                    $messageNoAccess = $e->getMessage();
                }
            }
        }
        if ($messageNoAccess) {
            http_response_code(403);
        }
        $view = new View('@Login/login');
        $view->AccessErrorString = $messageNoAccess;
        $view->infoMessage = nl2br($infoMessage);
        $view->passwordStrengthValidationRules = $this->passwordStrength->getRules();
        $view->addForm($form);
        $this->configureView($view);
        self::setHostValidationVariablesView($view);
        return $view->render();
    }
    private function getLoginFromLoginOrEmail($loginOrEmail)
    {
        $model = new UsersModel();
        if (!$model->userExists($loginOrEmail)) {
            $user = $model->getUserByEmail($loginOrEmail);
            if (!empty($user)) {
                return $user['login'];
            }
        }
        return $loginOrEmail;
    }
    /**
     * Configure common view properties
     *
     * @param View $view
     */
    protected function configureView($view)
    {
        $this->setBasicVariablesNoneAdminView($view);
        $view->linkTitle = Piwik::getRandomTitle();
        // crsf token: don't trust the submitted value; generate/fetch it from session data
        $view->nonce = Nonce::getNonce('Login.login');
    }
    public function confirmPassword()
    {
        Piwik::checkUserIsNotAnonymous();
        Piwik::checkUserHasSomeViewAccess();
        if (!$this->passwordVerify->hasPasswordVerifyBeenRequested()) {
            throw new Exception('Not available');
        }
        if (!Url::isValidHost()) {
            throw new Exception("Cannot confirm password with untrusted hostname!");
        }
        $nonceKey = 'confirmPassword';
        $messageNoAccess = '';
        if (!empty($_POST)) {
            $nonce = Common::getRequestVar('nonce', null, 'string', $_POST);
            $password = Common::getRequestVar('password', null, 'string', $_POST);
            if ($password) {
                $password = Common::unsanitizeInputValue($password);
            }
            $errorMessage = Nonce::verifyNonceWithErrorMessage($nonceKey, $nonce);
            if ($errorMessage !== "") {
                $messageNoAccess = $errorMessage;
            } elseif ($this->passwordVerify->isPasswordCorrect(Piwik::getCurrentUserLogin(), $password)) {
                $this->passwordVerify->setPasswordVerifiedCorrectly();
                return;
            } else {
                $messageNoAccess = Piwik::translate('Login_WrongPasswordEntered');
            }
        }
        return $this->renderTemplate('@Login/confirmPassword', ['nonce' => Nonce::getNonce($nonceKey), 'AccessErrorString' => $messageNoAccess, 'loginPlugin' => Piwik::getLoginPluginName()]);
    }
    /**
     * Form-less login
     * @see how to use it on https://matomo.org/faq/how-to/faq_30
     * @throws Exception
     * @return void
     */
    public function logme()
    {
        if (Config\GeneralConfig::getConfigValue('login_allow_logme') == 0) {
            throw new Exception('This functionality has been disabled in config');
        }
        $request = Request::fromRequest();
        $password = $request->getStringParameter('password');
        $login = $request->getStringParameter('login');
        $login = Access::doAsSuperUser(function () use($login) {
            try {
                $user = \Piwik\Plugins\UsersManager\API::getInstance()->getUser($login);
            } catch (\Exception $e) {
                // if a user can't be found for any reason we throw a generic exception below to avoid enumeration
            }
            if (empty($user)) {
                throw new Exception(Piwik::translate('Login_LoginPasswordNotCorrect'));
            }
            // Note: Not using Piwik::hasTheUserSuperUserAccess here on purpose as that would require
            // a logged in user to work and wouldn't work correctly within Access::doAsSuperUser
            try {
                $superUsers = APIUsersManager::getInstance()->getUsersHavingSuperUserAccess();
            } catch (\Exception $e) {
                return \false;
            }
            foreach ($superUsers as $superUser) {
                if ($user['login'] === $superUser['login']) {
                    throw new Exception(Piwik::translate('Login_ExceptionInvalidSuperUserAccessAuthenticationMethod', ["logme"]));
                }
            }
            return $user['login'];
        });
        $currentUrl = 'index.php';
        if ($this->idSite) {
            $currentUrl .= '?idSite=' . $this->idSite;
        }
        $urlToRedirect = $request->getStringParameter('url', $currentUrl);
        $this->authenticateAndRedirect($login, $password, $urlToRedirect, $passwordHashed = \true);
    }
    public function bruteForceLog()
    {
        Piwik::checkUserHasSuperUserAccess();
        return $this->renderTemplate('bruteForceLog', ['blockedIps' => $this->bruteForceDetection->getCurrentlyBlockedIps(), 'disallowedIps' => $this->systemSettings->blacklistedBruteForceIps->getValue()]);
    }
    /**
     * Error message shown when an AJAX request has no access
     *
     * @param string $errorMessage
     * @return string
     */
    public function ajaxNoAccess($errorMessage)
    {
        http_response_code(401);
        return sprintf('<div class="alert alert-danger">
                <p><strong>%s:</strong> %s</p>
                <p><a href="%s">%s</a></p>
            </div>', Piwik::translate('General_Error'), htmlentities($errorMessage, Common::HTML_ENCODING_QUOTE_STYLE, 'UTF-8', $doubleEncode = \false), 'index.php?module=' . Piwik::getLoginPluginName(), Piwik::translate('Login_LogIn'));
    }
    /**
     * Authenticate user and password.  Redirect if successful.
     *
     * @param string $login user name
     * @param string $password plain-text or hashed password
     * @param string $urlToRedirect URL to redirect to, if successfully authenticated
     * @param bool $passwordHashed indicates if $password is hashed
     */
    protected function authenticateAndRedirect($login,
#[\SensitiveParameter]
$password, $urlToRedirect = \false,
#[\SensitiveParameter]
$passwordHashed = \false)
    {
        Nonce::discardNonce('Login.login');
        $this->auth->setLogin($login);
        if ($passwordHashed === \false) {
            $this->auth->setPassword($password);
        } else {
            $this->auth->setPasswordHash($password);
        }
        $this->sessionInitializer->initSession($this->auth);
        // remove password reset entry if it exists
        $this->passwordResetter->removePasswordResetInfo($login);
        $parsedUrl = parse_url($urlToRedirect);
        if (!empty($urlToRedirect) && \false === $parsedUrl || !empty($parsedUrl['scheme']) && empty($parsedUrl['host'])) {
            $e = new \Piwik\Exception\Exception('The redirect URL is not valid.');
            $e->setIsHtmlMessage();
            throw $e;
        }
        // only use redirect url if host is trusted
        if (!empty($parsedUrl['host']) && !Url::isValidHost($parsedUrl['host'])) {
            $e = new \Piwik\Exception\Exception('The redirect URL host is not valid, it is not a trusted host. If this URL is trusted, you can allow this in your config.ini.php file by adding the line <i>trusted_hosts[] = "' . Common::sanitizeInputValue($parsedUrl['host']) . '"</i> under <i>[General]</i>');
            $e->setIsHtmlMessage();
            throw $e;
        }
        // We put together the url based on the parsed parameters manually to ensure it might not redirect to unexpected locations
        // unescaped slashes in username or password part for example have unexpected results in browsers
        // for protocol less urls starting with //, we need to prepend the double slash to have a url that passes the valid url check in redirect logic
        $urlToRedirect = (strpos($urlToRedirect, '//') === 0 ? '//' : '') . UrlHelper::getParseUrlReverse($parsedUrl);
        if (empty($urlToRedirect)) {
            $redirect = Request::fromRequest()->getStringParameter('form_redirect', '');
            $module = Request::fromQueryString(UrlHelper::getQueryFromUrl($redirect))->getStringParameter('module', '');
            // when module is login, we redirect to home...
            if (!empty($module) && $module !== 'Login' && $module !== Piwik::getLoginPluginName() && $redirect) {
                $host = Url::getHostFromUrl($redirect);
                $currentHost = Url::getHost();
                $currentHost = explode(':', $currentHost, 2)[0];
                // we only redirect to a trusted host
                if (!empty($host) && !empty($currentHost) && $host == $currentHost && Url::isValidHost($host)) {
                    $urlToRedirect = $redirect;
                }
            }
        }
        if (empty($urlToRedirect)) {
            $urlToRedirect = Url::getCurrentUrlWithoutQueryString();
        }
        Url::redirectToUrl($urlToRedirect);
    }
    /**
     * Reset password action. Stores new password as hash and sends email
     * to confirm use.
     */
    public function resetPassword()
    {
        $form = new \Piwik\Plugins\Login\FormResetPassword();
        if (\false === $form->validate()) {
            return $this->renderResetPasswordView($form->getFormData()['errors']);
        }
        $nonceError = Nonce::verifyNonceWithErrorMessage('Login.login', $form->getSubmitValue('form_nonce'));
        if (!empty($nonceError)) {
            return $this->renderResetPasswordView([$nonceError]);
        }
        $password = $form->getSubmitValue('form_password');
        $brokenRules = $this->passwordStrength->validatePasswordStrength($password);
        if (!empty($brokenRules)) {
            $errorMsg = $this->passwordStrength->formatValidationFailedMessage($brokenRules);
            return $this->renderResetPasswordView([$errorMsg]);
        }
        $firstStepFormErrors = $this->resetPasswordFirstStep($form);
        if (!empty($firstStepFormErrors)) {
            return $this->renderResetPasswordView([$firstStepFormErrors]);
        }
        return $this->renderResetPasswordView([], Piwik::translate('Login_ConfirmationLinkPossiblySent'));
    }
    private function renderResetPasswordView(array $formErrors = [], ?string $responseMessage = null) : string
    {
        $view = new View('@Login/resetPassword');
        $view->formErrors = $formErrors;
        $view->infoMessage = $responseMessage;
        return $view->render();
    }
    /**
     * Saves password reset info and sends confirmation email.
     *
     * @param QuickForm2 $form
     * @return array Error message(s) if an error occurs.
     */
    protected function resetPasswordFirstStep($form)
    {
        $loginMail = $form->getSubmitValue('form_login');
        $password = $form->getSubmitValue('form_password');
        if (!empty($loginMail)) {
            $loginMail = trim($loginMail);
        }
        try {
            $this->passwordResetter->initiatePasswordResetProcess($loginMail, $password);
        } catch (\Piwik\Plugins\Login\PasswordResetUserIsInvalidException $ex) {
            Log::debug($ex);
            return null;
        } catch (Exception $ex) {
            Log::debug($ex);
            return [$ex->getMessage()];
        }
        return null;
    }
    public function initiateCancelResetPassword() : string
    {
        if (!Url::isValidHost()) {
            throw new Exception("Cannot invalidate reset password token with untrusted hostname!");
        }
        $request = Request::fromRequest();
        $login = $request->getStringParameter('login');
        $resetToken = $request->getStringParameter('resetToken');
        $errorMessage = '';
        try {
            $this->passwordResetter->checkValidConfirmPasswordToken($login, $resetToken);
        } catch (Exception $ex) {
            $errorMessage = $ex->getMessage();
        }
        $nonce = Nonce::getNonce(self::NONCE_CONFIRMCANCELRESETPASSWORD);
        return $this->renderTemplateAs('@Login/initiateCancelResetPassword', ['nonce' => $nonce, 'errorMessage' => $errorMessage, 'loginPlugin' => Piwik::getLoginPluginName(), 'login' => $login, 'resetToken' => $resetToken], 'basic');
    }
    /**
     * Password reset cancel action. Invalidates a password reset token.
     * Users visit this action from a link supplied in an email.
     */
    public function cancelResetPassword() : string
    {
        if (!Url::isValidHost()) {
            throw new Exception("Cannot invalidate reset password token with untrusted hostname!");
        }
        $request = Request::fromRequest();
        $login = $request->getStringParameter('login');
        $resetToken = $request->getStringParameter('resetToken');
        try {
            Nonce::checkNonce(self::NONCE_CONFIRMCANCELRESETPASSWORD);
            $this->passwordResetter->cancelPasswordResetProcess($login, $resetToken);
        } catch (Exception $ex) {
            Log::debug($ex);
            $errorMessage = $ex->getMessage();
        }
        if (!empty($errorMessage)) {
            return $this->login($errorMessage);
        }
        $cancelResetPasswordContent = '';
        /**
         * Overwrite the content displayed on the "reset password process cancelled page".
         *
         * Will display default content if no event content returned.
         *
         * @param string $cancelResetPasswordContent The content to render.
         */
        Piwik::postEvent('Template.loginCancelResetPasswordContent', [&$cancelResetPasswordContent]);
        return $this->renderTemplateAs('@Login/cancelResetPassword', ['cancelResetPasswordContent' => $cancelResetPasswordContent], 'basic');
    }
    /**
     * Password reset confirmation action. Finishes the password reset process.
     * Users visit this action from a link supplied in an email.
     */
    public function confirmResetPassword()
    {
        if (!Url::isValidHost()) {
            throw new Exception("Cannot confirm reset password with untrusted hostname!");
        }
        $errorMessage = null;
        $passwordHash = null;
        $login = Common::getRequestVar('login');
        $resetToken = Common::getRequestVar('resetToken');
        try {
            $passwordHash = $this->passwordResetter->checkValidConfirmPasswordToken($login, $resetToken);
        } catch (Exception $ex) {
            $this->bruteForceDetection->addFailedAttempt(IP::getIpFromHeader());
            Log::debug($ex);
            $errorMessage = $ex->getMessage();
        }
        if (!empty($errorMessage)) {
            return $this->login($errorMessage);
        }
        if (!empty($_POST['nonce']) && !empty($_POST['mtmpasswordconfirm']) && !empty($resetToken) && !empty($login) && !empty($passwordHash) && empty($errorMessage)) {
            Nonce::checkNonce(self::NONCE_CONFIRMRESETPASSWORD, $_POST['nonce']);
            if ($this->passwordResetter->doesResetPasswordHashMatchesPassword($_POST['mtmpasswordconfirm'], $passwordHash)) {
                $this->passwordResetter->setHashedPasswordForLogin($login, $passwordHash);
                return $this->resetPasswordSuccess();
            } else {
                $errorMessage = Piwik::translate('Login_ConfirmPasswordResetWrongPassword');
            }
        }
        $nonce = Nonce::getNonce(self::NONCE_CONFIRMRESETPASSWORD);
        return $this->renderTemplateAs('@Login/confirmResetPassword', ['nonce' => $nonce, 'errorMessage' => $errorMessage, 'loginPlugin' => Piwik::getLoginPluginName()], 'basic');
    }
    /**
     * The action used after a password is successfully reset. Displays the login
     * screen with an extra message. A separate action is used instead of returning
     * the HTML in confirmResetPassword so the resetToken won't be in the URL.
     */
    public function resetPasswordSuccess()
    {
        $_POST = [];
        // prevent showing error message username and password is missing
        return $this->login($errorMessage = null, $infoMessage = Piwik::translate('Login_PasswordChanged'));
    }
    /**
     * Clear session information
     *
     * @return void
     */
    public static function clearSession()
    {
        $sessionFingerprint = new Session\SessionFingerprint();
        $sessionFingerprint->clear();
        Session::expireSessionCookie();
    }
    /**
     * Logout current user
     *
     * @return void
     */
    public function logout()
    {
        Piwik::postEvent('Login.logout', [Piwik::getCurrentUserLogin()]);
        self::clearSession();
        $logoutUrl = @Config::getInstance()->General['login_logout_url'];
        if (empty($logoutUrl)) {
            Piwik::redirectToModule('CoreHome');
        } else {
            Url::redirectToUrl($logoutUrl);
        }
    }
    /**
     * Init page for invite user
     * @return string|void
     */
    public function acceptInvitation()
    {
        $model = new UsersModel();
        $passwordHelper = new Password();
        $view = new View('@Login/invitation');
        $request = Request::fromRequest();
        $token = $request->getStringParameter('token');
        $form = $request->getStringParameter('invitation_form', '');
        $settings = new SystemSettings();
        $termsAndConditionUrl = $settings->termsAndConditionUrl->getValue();
        $privacyPolicyUrl = $settings->privacyPolicyUrl->getValue();
        $user = $model->getUserByInviteToken($token);
        // if no user matches the invite token
        if (!$user) {
            $this->bruteForceDetection->addFailedAttempt(IP::getIpFromHeader());
            throw new RedirectException(Piwik::translate('Login_InvalidOrExpiredTokenV2'), SettingsPiwik::getPiwikUrl(), 3);
        }
        if (!empty($user['invite_expired_at']) && Date::factory($user['invite_expired_at'])->isEarlier(Date::now())) {
            throw new RedirectException(Piwik::translate('Login_InvalidOrExpiredTokenV2'), SettingsPiwik::getPiwikUrl(), 3);
        }
        // if form was sent
        if (!empty($form)) {
            $error = null;
            $password = $request->getStringParameter('password', '');
            $passwordConfirmation = $request->getStringParameter('passwordConfirmation', '');
            $conditionCheck = $request->getBoolParameter('conditionCheck', \false);
            if (empty($password)) {
                $error = Piwik::translate('Login_PasswordRequired');
            }
            // check if terms accepted and privacy
            if (!$conditionCheck && ($privacyPolicyUrl || $termsAndConditionUrl)) {
                if ($privacyPolicyUrl && $termsAndConditionUrl) {
                    $error = Piwik::translate('Login_AcceptPrivacyPolicyAndTermsAndCondition');
                } elseif ($privacyPolicyUrl) {
                    $error = Piwik::translate('Login_AcceptPrivacyPolicy');
                } elseif ($termsAndConditionUrl) {
                    $error = Piwik::translate('Login_AcceptTermsAndCondition');
                }
            }
            // validate password
            try {
                UsersManager::checkPassword($password);
            } catch (\Exception $e) {
                $error = $e->getMessage();
            }
            // check password strength
            $brokenRules = $this->passwordStrength->validatePasswordStrength($password);
            if (!empty($brokenRules)) {
                $error = $this->passwordStrength->formatValidationFailedMessage($brokenRules);
            }
            // confirm matching passwords
            if ($password !== $passwordConfirmation) {
                $error = Piwik::translate('Login_PasswordsDoNotMatch');
            }
            if (!$error) {
                $password = UsersManager::getPasswordHash($password);
                $password = $passwordHelper->hash($password);
                // update pending user to active user
                $model->updateUserFields($user['login'], ['password' => $password, 'invite_token' => null, 'invite_link_token' => null, 'invite_accept_at' => Date::now()->getDatetime(), 'invite_expired_at' => null]);
                // send e-mail to inviter
                if (!empty($user['invited_by'])) {
                    $invitedBy = $model->getUser($user['invited_by']);
                    if ($invitedBy) {
                        LanguagesHelper::doWithUserLanguage($invitedBy['email'], function () use($user, $invitedBy) {
                            $mail = StaticContainer::getContainer()->make(UserAcceptInvitationEmail::class, ['login' => $user['invited_by'], 'emailAddress' => $invitedBy['email'], 'userLogin' => $user['login']]);
                            $mail->safeSend();
                        });
                    }
                }
                /**
                 * Triggered after a user accepted an invite
                 *
                 * @param string $userLogin The invited user's login.
                 * @param string $email The invited user's e-mail.
                 * @param string $inviterLogin The login of the user, who invited this user
                 */
                Piwik::postEvent('UsersManager.inviteUser.accepted', [$user['login'], $user['email'], $user['invited_by']]);
                $this->authenticateAndRedirect($user['login'], $passwordConfirmation);
            }
            $view->AccessErrorString = $error;
        }
        $view->user = $user;
        $view->termsAndCondition = $termsAndConditionUrl;
        $view->privacyPolicyUrl = $privacyPolicyUrl;
        $view->token = $token;
        $view->loginPlugin = Piwik::getLoginPluginName();
        $view->passwordStrengthValidationRules = $this->passwordStrength->getRules();
        $this->configureView($view);
        self::setHostValidationVariablesView($view);
        return $view->render();
    }
    public function declineInvitation()
    {
        $model = new UsersModel();
        $token = Common::getRequestVar('token', null, 'string');
        $form = Common::getRequestVar('invitation_form', \false, 'string');
        $user = $model->getUserByInviteToken($token);
        // if no user matches the invite token
        if (!$user) {
            $this->bruteForceDetection->addFailedAttempt(IP::getIpFromHeader());
            throw new Exception(Piwik::translate('Login_InvalidOrExpiredToken'));
        }
        if (!empty($user['invite_expired_at']) && Date::factory($user['invite_expired_at'])->isEarlier(Date::now())) {
            throw new Exception(Piwik::translate('Login_InvalidOrExpiredToken'));
        }
        $view = new View('@Login/invitationDecline');
        if ($form) {
            // remove user
            try {
                $model->deleteUser($user['login']);
            } catch (\Exception $e) {
                // deleting the user triggers an event, which might call methods that require a user to be logged in
                // as those operations might not be needed for a pending user, we simply ignore any errors here
            }
            // send e-mail to inviter
            if (!empty($user['invited_by'])) {
                $invitedBy = $model->getUser($user['invited_by']);
                if ($invitedBy) {
                    $mail = StaticContainer::getContainer()->make(UserDeclinedInvitationEmail::class, ['login' => $user['invited_by'], 'emailAddress' => $invitedBy['email'], 'userLogin' => $user['login']]);
                    $mail->safeSend();
                }
            }
            $view = new View('@Login/invitationDeclineSuccess');
            /**
             * Triggered after a user accepted an invite
             *
             * @param string $userLogin The invited user's login.
             * @param string $email The invited user's e-mail.
             * @param string $inviterLogin The login of the user, who invited this user
             */
            Piwik::postEvent('UsersManager.inviteUser.declined', [$user['login'], $user['email'], $user['invited_by']]);
        }
        $view->token = $token;
        $view->loginPlugin = Piwik::getLoginPluginName();
        $this->configureView($view);
        self::setHostValidationVariablesView($view);
        return $view->render();
    }
}
