1<?php
2/**
3 * Matomo - free/libre analytics platform
4 *
5 * @link https://matomo.org
6 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
7 *
8 */
9namespace Piwik\Plugins\UsersManager;
10
11use Exception;
12use Piwik\API\Request;
13use Piwik\API\ResponseBuilder;
14use Piwik\Common;
15use Piwik\Container\StaticContainer;
16use Piwik\Date;
17use Piwik\Nonce;
18use Piwik\Notification;
19use Piwik\Option;
20use Piwik\Piwik;
21use Piwik\Plugin;
22use Piwik\Plugin\ControllerAdmin;
23use Piwik\Plugins\LanguagesManager\API as APILanguagesManager;
24use Piwik\Plugins\LanguagesManager\LanguagesManager;
25use Piwik\Plugins\Login\PasswordVerifier;
26use Piwik\Plugins\TagManager\Validators\TriggerIds;
27use Piwik\Plugins\UsersManager\API as APIUsersManager;
28use Piwik\SettingsPiwik;
29use Piwik\Site;
30use Piwik\Tracker\IgnoreCookie;
31use Piwik\Translation\Translator;
32use Piwik\Url;
33use Piwik\Validators\BaseValidator;
34use Piwik\Validators\CharacterLength;
35use Piwik\Validators\NotEmpty;
36use Piwik\View;
37use Piwik\Session\SessionInitializer;
38use Piwik\Plugins\CoreAdminHome\Emails\TokenAuthCreatedEmail;
39use Piwik\Plugins\CoreAdminHome\Emails\TokenAuthDeletedEmail;
40
41class Controller extends ControllerAdmin
42{
43    const NONCE_CHANGE_PASSWORD = 'changePasswordNonce';
44    const NONCE_ADD_AUTH_TOKEN = 'addAuthTokenNonce';
45    const NONCE_DELETE_AUTH_TOKEN = 'deleteAuthTokenNonce';
46
47    /**
48     * @var Translator
49     */
50    private $translator;
51
52    /**
53     * @var PasswordVerifier
54     */
55    private $passwordVerify;
56
57    /**
58     * @var Model
59     */
60    private $userModel;
61
62    public function __construct(Translator $translator, PasswordVerifier $passwordVerify, Model $userModel)
63    {
64        $this->translator = $translator;
65        $this->passwordVerify = $passwordVerify;
66        $this->userModel = $userModel;
67
68        parent::__construct();
69    }
70
71    static function orderByName($a, $b)
72    {
73        return strcmp($a['name'], $b['name']);
74    }
75
76    /**
77     * The "Manage Users and Permissions" Admin UI screen
78     */
79    public function index()
80    {
81        Piwik::checkUserIsNotAnonymous();
82        Piwik::checkUserHasSomeAdminAccess();
83        UsersManager::dieIfUsersAdminIsDisabled();
84
85        $view = new View('@UsersManager/index');
86
87        $IdSitesAdmin = Request::processRequest('SitesManager.getSitesIdWithAdminAccess');
88        $idSiteSelected = 1;
89
90        if (count($IdSitesAdmin) > 0) {
91            $defaultWebsiteId = $IdSitesAdmin[0];
92            $idSiteSelected = $this->idSite ?: $defaultWebsiteId;
93        }
94
95        if (!Piwik::isUserHasAdminAccess($idSiteSelected) && count($IdSitesAdmin) > 0) {
96            // make sure to show a website where user actually has admin access
97            $idSiteSelected = $IdSitesAdmin[0];
98        }
99
100        $defaultReportSiteName = Site::getNameFor($idSiteSelected);
101
102        $view->idSiteSelected = $idSiteSelected;
103        $view->defaultReportSiteName = $defaultReportSiteName;
104        $view->currentUserRole = Piwik::hasUserSuperUserAccess() ? 'superuser' : 'admin';
105        $view->accessLevels = [
106            ['key' => 'noaccess', 'value' => Piwik::translate('UsersManager_PrivNone')],
107            ['key' => 'view', 'value' => Piwik::translate('UsersManager_PrivView')],
108            ['key' => 'write', 'value' => Piwik::translate('UsersManager_PrivWrite')],
109            ['key' => 'admin', 'value' => Piwik::translate('UsersManager_PrivAdmin')],
110            ['key' => 'superuser', 'value' => Piwik::translate('Installation_SuperUser'), 'disabled' => true],
111        ];
112        $view->filterAccessLevels = [
113            ['key' => '', 'value' => Piwik::translate('UsersManager_ShowAll')],
114            ['key' => 'noaccess', 'value' => Piwik::translate('UsersManager_PrivNone')],
115            ['key' => 'some', 'value' => Piwik::translate('UsersManager_AtLeastView')],
116            ['key' => 'view', 'value' => Piwik::translate('UsersManager_PrivView')],
117            ['key' => 'write', 'value' => Piwik::translate('UsersManager_PrivWrite')],
118            ['key' => 'admin', 'value' => Piwik::translate('UsersManager_PrivAdmin')],
119            ['key' => 'superuser', 'value' => Piwik::translate('Installation_SuperUser')],
120        ];
121
122        $capabilities = Request::processRequest('UsersManager.getAvailableCapabilities', [], []);
123        foreach ($capabilities as $capability) {
124            $capabilityEntry = [
125                'key' => $capability['id'], 'value' => $capability['category'] . ': ' . $capability['name'],
126            ];
127            $view->accessLevels[] = $capabilityEntry;
128            $view->filterAccessLevels[] = $capabilityEntry;
129        }
130
131        $this->setBasicVariablesView($view);
132
133        return $view->render();
134    }
135
136    /**
137     * Returns default date for Piwik reports
138     *
139     * @param string $user
140     * @return string today, yesterday, week, month, year
141     */
142    protected function getDefaultDateForUser($user)
143    {
144        return APIUsersManager::getInstance()->getUserPreference(APIUsersManager::PREFERENCE_DEFAULT_REPORT_DATE, $user);
145    }
146
147    /**
148     * Returns the enabled dates that users can select,
149     * in their User Settings page "Report date to load by default"
150     *
151     * @throws
152     * @return array
153     */
154    protected function getDefaultDates()
155    {
156        $dates = array(
157            'today'      => $this->translator->translate('Intl_Today'),
158            'yesterday'  => $this->translator->translate('Intl_Yesterday'),
159            'previous7'  => $this->translator->translate('General_PreviousDays', 7),
160            'previous30' => $this->translator->translate('General_PreviousDays', 30),
161            'last7'      => $this->translator->translate('General_LastDays', 7),
162            'last30'     => $this->translator->translate('General_LastDays', 30),
163            'week'       => $this->translator->translate('General_CurrentWeek'),
164            'month'      => $this->translator->translate('General_CurrentMonth'),
165            'year'       => $this->translator->translate('General_CurrentYear'),
166        );
167
168        $mappingDatesToPeriods = array(
169            'today' => 'day',
170            'yesterday' => 'day',
171            'previous7' => 'range',
172            'previous30' => 'range',
173            'last7' => 'range',
174            'last30' => 'range',
175            'week' => 'week',
176            'month' => 'month',
177            'year' => 'year',
178        );
179
180        // assertion
181        if (count($dates) != count($mappingDatesToPeriods)) {
182            throw new Exception("some metadata is missing in getDefaultDates()");
183        }
184
185        $allowedPeriods = self::getEnabledPeriodsInUI();
186        $allowedDates = array_intersect($mappingDatesToPeriods, $allowedPeriods);
187        $dates = array_intersect_key($dates, $allowedDates);
188
189        /**
190         * Triggered when the list of available dates is requested, for example for the
191         * User Settings > Report date to load by default.
192         *
193         * @param array &$dates Array of (date => translation)
194         */
195        Piwik::postEvent('UsersManager.getDefaultDates', array(&$dates));
196
197        return $dates;
198    }
199
200    /**
201     * The "User Settings" admin UI screen view
202     */
203    public function userSettings()
204    {
205        Piwik::checkUserIsNotAnonymous();
206
207        $view = new View('@UsersManager/userSettings');
208
209        $userLogin = Piwik::getCurrentUserLogin();
210        $user = Request::processRequest('UsersManager.getUser', array('userLogin' => $userLogin));
211        $view->userEmail = $user['email'];
212        $view->userTokenAuth = Piwik::getCurrentUserTokenAuth();
213        $view->ignoreSalt = $this->getIgnoreCookieSalt();
214        $view->isUsersAdminEnabled = UsersManager::isUsersAdminEnabled();
215
216        $newsletterSignupOptionKey = NewsletterSignup::NEWSLETTER_SIGNUP_OPTION . $userLogin;
217        $view->showNewsletterSignup = Option::get($newsletterSignupOptionKey) === false
218                                    && SettingsPiwik::isInternetEnabled();
219
220        $userPreferences = new UserPreferences();
221        $defaultReport   = $userPreferences->getDefaultReport();
222
223        if ($defaultReport === false) {
224            $defaultReport = $userPreferences->getDefaultWebsiteId();
225        }
226
227        $view->defaultReport = $defaultReport;
228
229        if ($defaultReport == 'MultiSites') {
230
231            $defaultSiteId = $userPreferences->getDefaultWebsiteId();
232            $reportOptionsValue = $defaultSiteId;
233
234            $view->defaultReportIdSite   = $defaultSiteId;
235            $view->defaultReportSiteName = Site::getNameFor($defaultSiteId);
236        } else {
237            $reportOptionsValue = $defaultReport;
238            $view->defaultReportIdSite   = $defaultReport;
239            $view->defaultReportSiteName = Site::getNameFor($defaultReport);
240        }
241
242        $defaultReportOptions = array();
243        if (Plugin\Manager::getInstance()->isPluginActivated('MultiSites')) {
244            $defaultReportOptions[] = array('key' => 'MultiSites', 'value' => Piwik::translate('General_AllWebsitesDashboard'));
245        }
246
247        $defaultReportOptions[] = array('key' => $reportOptionsValue, 'value' => Piwik::translate('General_DashboardForASpecificWebsite'));
248
249        $view->defaultReportOptions = $defaultReportOptions;
250        $view->defaultDate = $this->getDefaultDateForUser($userLogin);
251        $view->availableDefaultDates = $this->getDefaultDates();
252
253        $languages = APILanguagesManager::getInstance()->getAvailableLanguageNames();
254        $languageOptions = array();
255        foreach ($languages as $language) {
256            $languageOptions[] = array(
257                'key' => $language['code'],
258                'value' => $language['name']
259            );
260        }
261
262        $view->languageOptions = $languageOptions;
263        $view->currentLanguageCode = LanguagesManager::getLanguageCodeForCurrentUser();
264        $view->currentTimeformat = (int) LanguagesManager::uses12HourClockForCurrentUser();
265        $view->ignoreCookieSet = IgnoreCookie::isIgnoreCookieFound();
266        $view->piwikHost = Url::getCurrentHost();
267        $this->setBasicVariablesView($view);
268
269        $view->timeFormats = array(
270            '1' => Piwik::translate('General_12HourClock'),
271            '0' => Piwik::translate('General_24HourClock')
272        );
273
274        return $view->render();
275    }
276
277    /**
278     * The "User Security" admin UI screen view
279     */
280    public function userSecurity()
281    {
282        Piwik::checkUserIsNotAnonymous();
283
284        $tokens = $this->userModel->getAllNonSystemTokensForLogin(Piwik::getCurrentUserLogin());
285        $tokens = array_map(function ($token){
286            foreach (['date_created', 'last_used', 'date_expired'] as $key) {
287                if (!empty($token[$key])) {
288                    $token[$key] = Date::factory($token[$key])->getLocalized(Date::DATE_FORMAT_LONG);
289                }
290            }
291
292            return $token;
293        }, $tokens);
294        $hasTokensWithExpireDate = !empty(array_filter(array_column($tokens, 'date_expired')));
295
296        return $this->renderTemplate('userSecurity', array(
297            'isUsersAdminEnabled' => UsersManager::isUsersAdminEnabled(),
298            'changePasswordNonce' => Nonce::getNonce(self::NONCE_CHANGE_PASSWORD),
299            'deleteTokenNonce' => Nonce::getNonce(self::NONCE_DELETE_AUTH_TOKEN),
300            'hasTokensWithExpireDate' => $hasTokensWithExpireDate,
301            'tokens' => $tokens
302        ));
303    }
304
305    /**
306     * The "User Security" admin UI screen view
307     */
308    public function deleteToken()
309    {
310        Piwik::checkUserIsNotAnonymous();
311
312        $idTokenAuth = Common::getRequestVar('idtokenauth', '', 'string');
313
314        if (!empty($idTokenAuth)) {
315            $params = array(
316                'module' => 'UsersManager',
317                'action' => 'deleteToken',
318                'idtokenauth' => $idTokenAuth,
319                'nonce' => Nonce::getNonce(self::NONCE_DELETE_AUTH_TOKEN)
320            );
321
322            if (!$this->passwordVerify->requirePasswordVerifiedRecently($params)) {
323                throw new Exception('Not allowed');
324            }
325
326            Nonce::checkNonce(self::NONCE_DELETE_AUTH_TOKEN);
327
328            if ($idTokenAuth === 'all') {
329                $this->userModel->deleteAllTokensForUser(Piwik::getCurrentUserLogin());
330
331                $notification = new Notification(Piwik::translate('UsersManager_TokensSuccessfullyDeleted'));
332                $notification->context = Notification::CONTEXT_SUCCESS;
333                Notification\Manager::notify('successdeletetokens', $notification);
334
335                $container = StaticContainer::getContainer();
336                $email = $container->make(TokenAuthDeletedEmail::class, array(
337                    'login' => Piwik::getCurrentUserLogin(),
338                    'emailAddress' => Piwik::getCurrentUserEmail(),
339                    'tokenDescription' => '',
340                    'all' => true
341                ));
342                $email->safeSend();
343            } elseif (is_numeric($idTokenAuth)) {
344                $description = $this->userModel->getUserTokenDescriptionByIdTokenAuth($idTokenAuth, Piwik::getCurrentUserLogin());
345                $this->userModel->deleteToken($idTokenAuth, Piwik::getCurrentUserLogin());
346
347                $notification = new Notification(Piwik::translate('UsersManager_TokenSuccessfullyDeleted'));
348                $notification->context = Notification::CONTEXT_SUCCESS;
349                Notification\Manager::notify('successdeletetoken', $notification);
350
351                $container = StaticContainer::getContainer();
352                $email = $container->make(TokenAuthDeletedEmail::class, array(
353                    'login' => Piwik::getCurrentUserLogin(),
354                    'emailAddress' => Piwik::getCurrentUserEmail(),
355                    'tokenDescription' => $description
356                ));
357                $email->safeSend();
358            }
359        }
360
361        $this->redirectToIndex('UsersManager', 'userSecurity');
362    }
363
364    /**
365     * The "User Security" admin UI screen view
366     */
367    public function addNewToken()
368    {
369        Piwik::checkUserIsNotAnonymous();
370
371        $params = array('module' => 'UsersManager', 'action' => 'addNewToken');
372
373        if (!$this->passwordVerify->requirePasswordVerifiedRecently($params)) {
374            throw new Exception('Not allowed');
375        }
376
377        $noDescription = false;
378
379        if (!empty($_POST['description'])) {
380            Nonce::checkNonce(self::NONCE_ADD_AUTH_TOKEN);
381
382            $description = Common::getRequestVar('description', '', 'string');
383            $login = Piwik::getCurrentUserLogin();
384
385            $generatedToken = $this->userModel->generateRandomTokenAuth();
386
387            $this->userModel->addTokenAuth($login, $generatedToken, $description, Date::now()->getDatetime());
388
389            $container = StaticContainer::getContainer();
390            $email = $container->make(TokenAuthCreatedEmail::class, array(
391                'login' => Piwik::getCurrentUserLogin(),
392                'emailAddress' => Piwik::getCurrentUserEmail(),
393                'tokenDescription' => $description
394            ));
395            $email->safeSend();
396
397            return $this->renderTemplate('addNewTokenSuccess', array('generatedToken' => $generatedToken));
398        } elseif (isset($_POST['description'])) {
399            $noDescription = true;
400        }
401
402        return $this->renderTemplate('addNewToken', array(
403           'nonce' => Nonce::getNonce(self::NONCE_ADD_AUTH_TOKEN),
404           'noDescription' => $noDescription
405        ));
406    }
407
408    /**
409     * The "Anonymous Settings" admin UI screen view
410     */
411    public function anonymousSettings()
412    {
413        Piwik::checkUserHasSuperUserAccess();
414
415        $view = new View('@UsersManager/anonymousSettings');
416
417        $view->availableDefaultDates = $this->getDefaultDates();
418
419        $this->initViewAnonymousUserSettings($view);
420        $this->setBasicVariablesView($view);
421
422        return $view->render();
423    }
424
425    public function setIgnoreCookie()
426    {
427        Piwik::checkUserHasSomeViewAccess();
428        Piwik::checkUserIsNotAnonymous();
429
430        $salt = Common::getRequestVar('ignoreSalt', false, 'string');
431        if ($salt !== $this->getIgnoreCookieSalt()) {
432            throw new Exception("Not authorized");
433        }
434
435        IgnoreCookie::setIgnoreCookie();
436        Piwik::redirectToModule('UsersManager', 'userSettings', array('token_auth' => false));
437    }
438
439    /**
440     * The Super User can modify Anonymous user settings
441     * @param View $view
442     */
443    protected function initViewAnonymousUserSettings($view)
444    {
445        if (!Piwik::hasUserSuperUserAccess()) {
446            return;
447        }
448
449        $userLogin = 'anonymous';
450
451        // Which websites are available to the anonymous users?
452
453        $anonymousSitesAccess = Request::processRequest('UsersManager.getSitesAccessFromUser', array('userLogin' => $userLogin));
454        $anonymousSites = array();
455        $idSites = array();
456        foreach ($anonymousSitesAccess as $info) {
457            $idSite = $info['site'];
458            $idSites[] = $idSite;
459
460            $site = Request::processRequest('SitesManager.getSiteFromId', array('idSite' => $idSite));
461            // Work around manual website deletion
462            if (!empty($site)) {
463                $anonymousSites[] = array('key' => $idSite, 'value' => Common::unsanitizeInputValue($site['name']));
464            }
465        }
466        $view->anonymousSites = $anonymousSites;
467
468        $anonymousDefaultSite = '';
469
470        // Which report is displayed by default to the anonymous user?
471        $anonymousDefaultReport = Request::processRequest('UsersManager.getUserPreference', array('userLogin' => $userLogin, 'preferenceName' => APIUsersManager::PREFERENCE_DEFAULT_REPORT));
472        if ($anonymousDefaultReport === false) {
473            if (empty($anonymousSites)) {
474                $anonymousDefaultReport = Piwik::getLoginPluginName();
475            } else {
476                // we manually imitate what would happen, in case the anonymous user logs in
477                // and is redirected to the first website available to them in the list
478                // @see getDefaultWebsiteId()
479                $anonymousDefaultReport = '1';
480                $anonymousDefaultSite = $anonymousSites[0]['key'];
481            }
482        }
483
484        if (is_numeric($anonymousDefaultReport)) {
485            $anonymousDefaultSite = $anonymousDefaultReport;
486            $anonymousDefaultReport = '1'; // a website is selected, we make sure "Dashboard for a specific site" gets pre-selected
487        }
488
489        if ((empty($anonymousDefaultSite) || !in_array($anonymousDefaultSite, $idSites)) && !empty($idSites)) {
490            $anonymousDefaultSite = $anonymousSites[0]['key'];
491        }
492
493        $view->anonymousDefaultReport = $anonymousDefaultReport;
494        $view->anonymousDefaultSite = $anonymousDefaultSite;
495        $view->anonymousDefaultDate = $this->getDefaultDateForUser($userLogin);
496
497        $view->defaultReportOptions = array(
498            array('key' => 'Login', 'value' => Piwik::translate('UsersManager_TheLoginScreen')),
499            array('key' => 'MultiSites', 'value' => Piwik::translate('General_AllWebsitesDashboard'), 'disabled' => empty($anonymousSites)),
500            array('key' => '1', 'value' => Piwik::translate('General_DashboardForASpecificWebsite')),
501        );
502    }
503
504    /**
505     * Records settings for the anonymous users (default report, default date)
506     */
507    public function recordAnonymousUserSettings()
508    {
509        $response = new ResponseBuilder(Common::getRequestVar('format'));
510        try {
511            Piwik::checkUserHasSuperUserAccess();
512            $this->checkTokenInUrl();
513
514            $anonymousDefaultReport = Common::getRequestVar('anonymousDefaultReport');
515            $anonymousDefaultDate = Common::getRequestVar('anonymousDefaultDate');
516            $userLogin = 'anonymous';
517            APIUsersManager::getInstance()->setUserPreference($userLogin,
518                APIUsersManager::PREFERENCE_DEFAULT_REPORT,
519                $anonymousDefaultReport);
520            APIUsersManager::getInstance()->setUserPreference($userLogin,
521                APIUsersManager::PREFERENCE_DEFAULT_REPORT_DATE,
522                $anonymousDefaultDate);
523            $toReturn = $response->getResponse();
524        } catch (Exception $e) {
525            $toReturn = $response->getResponseException($e);
526        }
527
528        return $toReturn;
529    }
530
531    /**
532     * Records settings from the "User Settings" page
533     * @throws Exception
534     */
535    public function recordUserSettings()
536    {
537        $response = new ResponseBuilder(Common::getRequestVar('format'));
538        try {
539            $this->checkTokenInUrl();
540
541            $defaultReport = Common::getRequestVar('defaultReport');
542            $defaultDate = Common::getRequestVar('defaultDate');
543            $language = Common::getRequestVar('language');
544            $timeFormat = Common::getRequestVar('timeformat');
545            $userLogin = Piwik::getCurrentUserLogin();
546
547            Piwik::checkUserHasSuperUserAccessOrIsTheUser($userLogin);
548
549            $this->processEmailChange($userLogin);
550
551            LanguagesManager::setLanguageForSession($language);
552
553            Request::processRequest('LanguagesManager.setLanguageForUser', [
554                'login' => $userLogin,
555                'languageCode' => $language,
556            ]);
557            Request::processRequest('LanguagesManager.set12HourClockForUser', [
558                'login' => $userLogin,
559                'use12HourClock' => $timeFormat,
560            ]);
561
562            APIUsersManager::getInstance()->setUserPreference($userLogin,
563                APIUsersManager::PREFERENCE_DEFAULT_REPORT,
564                $defaultReport);
565            APIUsersManager::getInstance()->setUserPreference($userLogin,
566                APIUsersManager::PREFERENCE_DEFAULT_REPORT_DATE,
567                $defaultDate);
568            $toReturn = $response->getResponse();
569        } catch (Exception $e) {
570            $toReturn = $response->getResponseException($e);
571        }
572
573        return $toReturn;
574    }
575
576
577    /**
578     * Records settings from the "User Settings" page
579     * @throws Exception
580     */
581    public function recordPasswordChange()
582    {
583        $userLogin = Piwik::getCurrentUserLogin();
584
585        Piwik::checkUserHasSuperUserAccessOrIsTheUser($userLogin);
586        Nonce::checkNonce(self::NONCE_CHANGE_PASSWORD);
587
588        $this->processPasswordChange($userLogin);
589
590        $notification = new Notification(Piwik::translate('CoreAdminHome_SettingsSaveSuccess'));
591        $notification->context = Notification::CONTEXT_SUCCESS;
592        Notification\Manager::notify('successpass', $notification);
593        $this->redirectToIndex('UsersManager',  'userSecurity');
594    }
595
596    private function noAdminAccessToWebsite($idSiteSelected, $defaultReportSiteName, $message)
597    {
598        $view = new View('@UsersManager/noWebsiteAdminAccess');
599
600        $view->idSiteSelected = $idSiteSelected;
601        $view->defaultReportSiteName = $defaultReportSiteName;
602        $view->message = $message;
603        $this->setBasicVariablesView($view);
604
605        return $view->render();
606    }
607
608    private function processEmailChange($userLogin)
609    {
610        if (!UsersManager::isUsersAdminEnabled()) {
611            return;
612        }
613
614        if (!Url::isValidHost()) {
615            throw new Exception("Cannot change email with untrusted hostname!");
616        }
617
618        $email = Common::getRequestVar('email');
619        $passwordCurrent = Common::getRequestvar('passwordConfirmation', false);
620
621        // UI disables password change on invalid host, but check here anyway
622        Request::processRequest('UsersManager.updateUser', [
623            'userLogin' => $userLogin,
624            'email' => $email,
625            'passwordConfirmation' => $passwordCurrent
626        ], $default = []);
627    }
628
629    private function processPasswordChange($userLogin)
630    {
631        if (!UsersManager::isUsersAdminEnabled()) {
632            return;
633        }
634
635        if (!Url::isValidHost()) {
636            // UI disables password change on invalid host, but check here anyway
637            throw new Exception("Cannot change password with untrusted hostname!");
638        }
639
640        $newPassword = Common::getRequestvar('password', false);
641        $passwordBis = Common::getRequestvar('passwordBis', false);
642        $passwordCurrent = Common::getRequestvar('passwordConfirmation', false);
643
644        if ($newPassword !== $passwordBis) {
645            throw new Exception($this->translator->translate('Login_PasswordsDoNotMatch'));
646        }
647
648        Request::processRequest('UsersManager.updateUser', [
649            'userLogin' => $userLogin,
650            'password' => $newPassword,
651            'passwordConfirmation' => $passwordCurrent
652        ], $default = []);
653
654        // logs the user in with the new password
655        $newPassword = Common::unsanitizeInputValue($newPassword);
656        $sessionInitializer = new SessionInitializer();
657        $auth = StaticContainer::get('Piwik\Auth');
658        $auth->setTokenAuth(null); // ensure authenticated through password
659        $auth->setLogin($userLogin);
660        $auth->setPassword($newPassword);
661        $sessionInitializer->initSession($auth);
662    }
663
664    /**
665     * @return string
666     */
667    private function getIgnoreCookieSalt()
668    {
669        return md5(SettingsPiwik::getSalt());
670    }
671}
672