
<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 Piwik\Container\StaticContainer;
use Piwik\Date;
use Piwik\Piwik;
use Piwik\Session\SessionNamespace;
use Piwik\Url;
class PasswordVerifier
{
    public const VERIFY_VALID_FOR_MINUTES = 30;
    public const VERIFY_REVALIDATE_X_MINUTES_LEFT = 15;
    /**
     * @var Date|null
     */
    private $now;
    private $enableRedirect = \true;
    /**
     * @ignore
     * tests only
     */
    public function setDisableRedirect()
    {
        $this->enableRedirect = \false;
    }
    private function getLoginSession()
    {
        return new SessionNamespace('Login');
    }
    public function isPasswordCorrect($userLogin,
#[\SensitiveParameter]
$password)
    {
        /**
         * @ignore
         * @internal
         */
        Piwik::postEvent('Login.beforeLoginCheckAllowed');
        /** @var \Piwik\Auth $authAdapter */
        $authAdapter = StaticContainer::get('Piwik\\Auth');
        $authAdapter->setLogin($userLogin);
        $authAdapter->setPasswordHash(null);
        // ensure authentication happens on password
        $authAdapter->setPassword($password);
        $authAdapter->setTokenAuth(null);
        // ensure authentication happens on password
        $authResult = $authAdapter->authenticate();
        if ($authResult->wasAuthenticationSuccessful()) {
            return \true;
        }
        /**
         * @ignore
         * @internal
         */
        Piwik::postEvent('Login.recordFailedLoginAttempt');
        return \false;
    }
    public function hasPasswordVerifyBeenRequested()
    {
        $sessionNamespace = $this->getLoginSession();
        return !empty($sessionNamespace->redirectParams);
    }
    public function forgetVerifiedPassword()
    {
        // call this method if you want the user to enter the password again after some action was finished which needed
        // the password
        $sessionNamespace = $this->getLoginSession();
        unset($sessionNamespace->lastPasswordAuth);
        unset($sessionNamespace->redirectParams);
    }
    /**
     * @ignore
     * tests only
     */
    public function setNow(Date $now)
    {
        $this->now = $now;
    }
    private function getNow()
    {
        if ($this->now) {
            return $this->now;
        }
        return Date::now();
    }
    public function setPasswordVerifiedCorrectly()
    {
        $sessionNamespace = $this->getLoginSession();
        $sessionNamespace->lastPasswordAuth = $this->getNow()->getDatetime();
        $sessionNamespace->setExpirationSeconds(self::VERIFY_VALID_FOR_MINUTES * 60, 'lastPasswordAuth');
        $sessionNamespace->setExpirationSeconds(self::VERIFY_VALID_FOR_MINUTES * 60, 'redirectParams');
        if ($this->enableRedirect) {
            Url::redirectToUrl('index.php' . Url::getCurrentQueryStringWithParametersModified($sessionNamespace->redirectParams));
        }
    }
    public function hasBeenVerified()
    {
        $lastAuthValidTo = $this->getPasswordVerifyValidUpToDateIfVerified();
        $now = $this->getNow();
        if ($lastAuthValidTo && $now->isEarlier($lastAuthValidTo)) {
            return \true;
        }
        return \false;
    }
    private function getPasswordVerifyValidUpToDateIfVerified()
    {
        $sessionNamespace = $this->getLoginSession();
        if (!empty($sessionNamespace->lastPasswordAuth) && !empty($sessionNamespace->redirectParams)) {
            $lastAuthValidTo = Date::factory($sessionNamespace->lastPasswordAuth)->addPeriod(self::VERIFY_VALID_FOR_MINUTES, 'minute');
            return $lastAuthValidTo;
        }
    }
    protected function hasBeenVerifiedAndHalfTimeValid()
    {
        $lastAuthValidTo = $this->getPasswordVerifyValidUpToDateIfVerified();
        $now = $this->getNow()->addPeriod(self::VERIFY_REVALIDATE_X_MINUTES_LEFT, 'minute');
        if ($lastAuthValidTo && $now->isEarlier($lastAuthValidTo)) {
            return \true;
        }
        return \false;
    }
    /**
     * Checks if the user has verified the password within the last 15 minutes. If not, the user will be redirected.
     * The password verify will be valid for at least another 15 minutes giving the user some time to perform an action.
     * See  {@link requirePasswordVerified}
     *
     * @param $redirectParams
     * @return null|true if password has been verified recently, will redirect if not
     * @throws \Zend_Session_Exception
     */
    public function requirePasswordVerifiedRecently($redirectParams)
    {
        if ($this->hasBeenVerifiedAndHalfTimeValid()) {
            return \true;
        }
        $this->initiatePasswordVerifyRedirect($redirectParams);
    }
    /**
     * Checks if the user has verified the password within the last 30 minutes. If not, the user will be redirected.
     * Please note that if the user performs an action afterwards, the password verify could be valid for only few more
     * seconds or minutes and by the time the user confirms a certain action, the password verify may no longer be valid.
     * If you want to ensure the password will be still valid for eg 15 minutes before the user performs some action,
     * consider using {@link requirePasswordVerifiedRecently}.
     *
     * @param $redirectParams
     * @return null|true if password has been verified, will redirect if not
     * @throws \Zend_Session_Exception
     */
    public function requirePasswordVerified($redirectParams)
    {
        if ($this->hasBeenVerified()) {
            return \true;
        }
        $this->initiatePasswordVerifyRedirect($redirectParams);
    }
    private function initiatePasswordVerifyRedirect($redirectParams)
    {
        $sessionNamespace = $this->getLoginSession();
        $sessionNamespace->redirectParams = $redirectParams;
        $sessionNamespace->setExpirationSeconds(self::VERIFY_VALID_FOR_MINUTES * 60 * 5, 'redirectParams');
        if ($this->enableRedirect) {
            Piwik::redirectToModule(Piwik::getLoginPluginName(), 'confirmPassword');
        }
    }
}
