diff options
author | diosmosis <diosmosis@users.noreply.github.com> | 2019-05-16 03:12:05 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-05-16 03:12:05 +0300 |
commit | 05017ba88ec611f63bf223728990351212ff560f (patch) | |
tree | 79c20127a6584a1316bb864b329d0cba713add10 | |
parent | cecec674a65e4dc2a1aa7c33722a5380be2fd719 (diff) |
Require password confirmation before setting/removing superuser access. (#13975)
* Require password confirmation for changing superuser access and fix issue where getSiteAccess is called w/ superuser when toggling superuser access.
* apply review feedback
* Allow bypassing password confirmation in certain scenarios.
* Fixing tests & adding UI test.
* Update submodule.
* test fixes + remove return; from 2fa tests.
* update submodule
* Fixing tests
* Couple tweaks for screenshot testing.
* test fixes
* Fix TwoFactorAuthUsersManager test.
* More test fixes.
* try to disable all transitions
* More UI test fixes + disable materialize animations globally in UI tests.
* 2fa ui tests now working
54 files changed, 302 insertions, 477 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index ea193eb4e8..43151a6369 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ The Product Changelog at **[matomo.org/changelog](https://matomo.org/changelog)* ## Matomo 3.10.0 ### Breaking Changes +* When giving a user superuser access through the `UsersManager.setSuperUserAccess` API, a new parameter `passwordConfirmation` needs to be sent along with the request containing the current password of the user issuing the API request. * Website referrer URLs are now detected using domain only instead of domain and path. This means if you have two different websites on the same domain, but different paths, and a visitor visits from one to the other, it won't have a referrer website set. ### New APIs diff --git a/plugins/Actions/tests/UI/ActionsDataTable_spec.js b/plugins/Actions/tests/UI/ActionsDataTable_spec.js index 3778bd3cf1..b09a55eb7c 100644 --- a/plugins/Actions/tests/UI/ActionsDataTable_spec.js +++ b/plugins/Actions/tests/UI/ActionsDataTable_spec.js @@ -32,6 +32,7 @@ describe("ActionsDataTable", function () { await page.mouse.move(-10, -10); await page.waitForNetworkIdle(); + await page.waitFor(250); // rendering expect(await page.screenshot({ fullPage: true })).to.matchImage('subtables_loaded'); }); diff --git a/plugins/Dashboard/tests/UI/Dashboard_spec.js b/plugins/Dashboard/tests/UI/Dashboard_spec.js index af060caac9..f539219829 100644 --- a/plugins/Dashboard/tests/UI/Dashboard_spec.js +++ b/plugins/Dashboard/tests/UI/Dashboard_spec.js @@ -168,8 +168,8 @@ describe("Dashboard", function () { var button = await page.jQuery('.modal.open .modal-footer a:contains(Yes)'); await button.click(); - await page.waitFor(250); await page.mouse.move(-10, -10); + await page.waitFor(250); expect(await page.screenshot({ fullPage: true })).to.matchImage('widget_move_removed'); }); @@ -181,6 +181,7 @@ describe("Dashboard", function () { var button = await page.jQuery('.modal.open .modal-footer a:contains(Save)'); await button.click(); await page.mouse.move(-10, -10); + await page.waitFor(500); // animation expect(await page.screenshot({ fullPage: true })).to.matchImage('change_layout'); }); @@ -263,6 +264,7 @@ describe("Dashboard", function () { await page.type('#createDashboardName', 'newdash2'); var button = await page.jQuery('.modal.open .modal-footer a:contains(Ok)'); await button.click(); + await page.mouse.move(-10, -10); await page.waitForNetworkIdle(); expect(await page.screenshot({ fullPage: true })).to.matchImage('create_new'); diff --git a/plugins/Dashboard/tests/UI/expected-screenshots/DashboardManager_create_new.png b/plugins/Dashboard/tests/UI/expected-screenshots/DashboardManager_create_new.png index d3b0e150b5..c0429584d7 100644 --- a/plugins/Dashboard/tests/UI/expected-screenshots/DashboardManager_create_new.png +++ b/plugins/Dashboard/tests/UI/expected-screenshots/DashboardManager_create_new.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e17ceb26b2b536e9a0f90eb78aed0681a38bd1748d569d3f0db003fcbf76cba9 -size 249197 +oid sha256:03a4cb2baeafcf12b51121737f80187f3a26dafb5bc4cc3df946c4c8f975d80f +size 247542 diff --git a/plugins/Dashboard/tests/UI/expected-screenshots/Dashboard_change_layout.png b/plugins/Dashboard/tests/UI/expected-screenshots/Dashboard_change_layout.png index 495e8a6c80..dceb3257f8 100644 --- a/plugins/Dashboard/tests/UI/expected-screenshots/Dashboard_change_layout.png +++ b/plugins/Dashboard/tests/UI/expected-screenshots/Dashboard_change_layout.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:595d831aa440d54ddd8a6a8cf4b8f731646dbc35846f22cde7f13cfa513c8d6f -size 29673 +oid sha256:26908474390de37b62d846f9a560c78286a8b0b431402a5a1c94e3006905adbd +size 28570 diff --git a/plugins/Installation/Controller.php b/plugins/Installation/Controller.php index 8dd65f6899..ee9160af07 100644 --- a/plugins/Installation/Controller.php +++ b/plugins/Installation/Controller.php @@ -26,6 +26,7 @@ use Piwik\Plugins\Diagnostics\DiagnosticService; use Piwik\Plugins\LanguagesManager\LanguagesManager; use Piwik\Plugins\SitesManager\API as APISitesManager; use Piwik\Plugins\UsersManager\API as APIUsersManager; +use Piwik\Plugins\UsersManager\UserUpdater; use Piwik\ProxyHeaders; use Piwik\SettingsPiwik; use Piwik\Tracker\TrackerCodeGenerator; @@ -680,11 +681,12 @@ class Controller extends \Piwik\Plugin\ControllerAdmin private function createSuperUser($login, $password, $email) { - $self = $this; - Access::doAsSuperUser(function () use ($self, $login, $password, $email) { + Access::doAsSuperUser(function () use ($login, $password, $email) { $api = APIUsersManager::getInstance(); $api->addUser($login, $password, $email); - $api->setSuperUserAccess($login, true); + + $userUpdater = new UserUpdater(); + $userUpdater->setSuperUserAccessWithoutCurrentPassword($login, true); }); } diff --git a/plugins/Login/tests/Integration/LoginTest.php b/plugins/Login/tests/Integration/LoginTest.php index 9f43512f0b..9ef38b17a9 100644 --- a/plugins/Login/tests/Integration/LoginTest.php +++ b/plugins/Login/tests/Integration/LoginTest.php @@ -15,6 +15,7 @@ use Piwik\DbHelper; use Piwik\NoAccessException; use Piwik\Plugins\Login\Auth; use Piwik\Plugins\UsersManager\API; +use Piwik\Plugins\UsersManager\UserUpdater; use Piwik\Tests\Framework\Mock\FakeAccess; use Piwik\Tests\Framework\TestCase\IntegrationTestCase; @@ -346,7 +347,8 @@ class LoginTest extends IntegrationTestCase private function _setUpSuperUserAccessViaDb() { - API::getInstance()->setSuperUserAccess('user', true); + $userUpdater = new UserUpdater(); + $userUpdater->setSuperUserAccessWithoutCurrentPassword('user', true); } private function authenticate($login, $tokenAuth) diff --git a/plugins/LoginLdap b/plugins/LoginLdap -Subproject c2de63df1887ec0409dceb5fa64f7fb735bce8e +Subproject 84b2d67b762ffbb66c26392c52acc7463534e0c diff --git a/plugins/TestRunner/Commands/TestsSetupFixture.php b/plugins/TestRunner/Commands/TestsSetupFixture.php index e97319b633..294a08c41c 100644 --- a/plugins/TestRunner/Commands/TestsSetupFixture.php +++ b/plugins/TestRunner/Commands/TestsSetupFixture.php @@ -10,6 +10,7 @@ namespace Piwik\Plugins\TestRunner\Commands; use Piwik\Application\Environment; use Piwik\Config; +use Piwik\Db; use Piwik\Plugin\ConsoleCommand; use Piwik\Tests\Framework\TestingEnvironmentManipulator; use Piwik\Tests\Framework\TestingEnvironmentVariables; @@ -113,7 +114,7 @@ class TestsSetupFixture extends ConsoleCommand $this->requireFixtureFiles($input); $this->setIncludePathAsInTestBootstrap(); - $host = Url::getHost(); + $host = Config::getHostname(); if (empty($host)) { $host = 'localhost'; Url::setHost('localhost'); diff --git a/plugins/TwoFactorAuth/tests/Fixtures/TwoFactorFixture.php b/plugins/TwoFactorAuth/tests/Fixtures/TwoFactorFixture.php index 37e2777214..3b71c0eba7 100644 --- a/plugins/TwoFactorAuth/tests/Fixtures/TwoFactorFixture.php +++ b/plugins/TwoFactorAuth/tests/Fixtures/TwoFactorFixture.php @@ -12,6 +12,7 @@ use Piwik\Date; use Piwik\Plugins\TwoFactorAuth\Dao\RecoveryCodeDao; use Piwik\Plugins\TwoFactorAuth\TwoFactorAuthentication; use Piwik\Plugins\UsersManager\Model; +use Piwik\Plugins\UsersManager\UserUpdater; use Piwik\Tests\Framework\Fixture; use Piwik\Plugins\UsersManager\API as UsersAPI; @@ -26,6 +27,7 @@ class TwoFactorFixture extends Fixture private $userWithout2Fa = 'without2FA'; private $userNo2Fa = 'no2FA'; private $userPassword = '123abcDk3_l3'; + private $superUserWith2Fa = 'superWith2FA'; const USER_2FA_SECRET = '1111111111111111'; @@ -68,6 +70,11 @@ class TwoFactorFixture extends Fixture public function setUpUsers() { + \Piwik\Plugins\UsersManager\API::getInstance()->addUser($this->superUserWith2Fa, $this->userPassword, + $this->superUserWith2Fa . '@matomo.org'); + $userUpdater = new UserUpdater(); + $userUpdater->setSuperUserAccessWithoutCurrentPassword($this->superUserWith2Fa, true); + foreach ([$this->userWith2Fa, $this->userWithout2Fa, $this->userWith2FaDisable, $this->userNo2Fa] as $user) { \Piwik\Plugins\UsersManager\API::getInstance()->addUser($user, $this->userPassword, $user . '@matomo.org'); // we cannot set superuser as logme won't work for super user @@ -79,7 +86,7 @@ class TwoFactorFixture extends Fixture } } - foreach ([$this->userWith2Fa, $this->userWith2FaDisable] as $user) { + foreach ([$this->userWith2Fa, $this->userWith2FaDisable, $this->superUserWith2Fa] as $user) { $this->dao->insertRecoveryCode($user, '123456'); $this->dao->insertRecoveryCode($user, '234567'); $this->dao->insertRecoveryCode($user, '345678'); diff --git a/plugins/TwoFactorAuth/tests/Integration/TwoFactorAuthTest.php b/plugins/TwoFactorAuth/tests/Integration/TwoFactorAuthTest.php index 2df336f491..07429e2916 100644 --- a/plugins/TwoFactorAuth/tests/Integration/TwoFactorAuthTest.php +++ b/plugins/TwoFactorAuth/tests/Integration/TwoFactorAuthTest.php @@ -15,6 +15,7 @@ use Piwik\Plugins\TwoFactorAuth\Dao\TwoFaSecretRandomGenerator; use Piwik\Plugins\TwoFactorAuth\SystemSettings; use Piwik\Plugins\TwoFactorAuth\TwoFactorAuthentication; use Piwik\Plugins\UsersManager\API; +use Piwik\Plugins\UsersManager\UserUpdater; use Piwik\Tests\Framework\TestCase\IntegrationTestCase; /** @@ -49,7 +50,8 @@ class TwoFactorAuthTest extends IntegrationTestCase foreach ([$this->userWith2Fa, $this->userWithout2Fa] as $user) { API::getInstance()->addUser($user, $this->userPassword, $user . '@matomo.org'); - API::getInstance()->setSuperUserAccess($user, 1); + $userUpdater = new UserUpdater(); + $userUpdater->setSuperUserAccessWithoutCurrentPassword($user, 1); } $this->dao = StaticContainer::get(RecoveryCodeDao::class); diff --git a/plugins/TwoFactorAuth/tests/UI/TwoFactorAuthUsersManager_spec.js b/plugins/TwoFactorAuth/tests/UI/TwoFactorAuthUsersManager_spec.js index 4e07f7cc97..4d5a405dbd 100644 --- a/plugins/TwoFactorAuth/tests/UI/TwoFactorAuthUsersManager_spec.js +++ b/plugins/TwoFactorAuth/tests/UI/TwoFactorAuthUsersManager_spec.js @@ -8,8 +8,6 @@ */ describe("TwoFactorAuthUsersManager", function () { - this.timeout(0); - this.fixture = "Piwik\\Plugins\\TwoFactorAuth\\tests\\Fixtures\\TwoFactorUsersManagerFixture"; var generalParams = 'idSite=1&period=day&date=2010-01-03', @@ -37,19 +35,21 @@ describe("TwoFactorAuthUsersManager", function () { await page.evaluate(function () { $('.userEditForm .menuUserTwoFa a').click(); }); + await page.waitFor(250); + await page.waitFor('.twofa-reset > p', { visible: true }); expect(await page.screenshotSelector('#content,#notificationContainer')).to.matchImage('edit_with_2fa'); }); it('should ask for confirmation before resetting 2fa', async function () { await page.click('.userEditForm .twofa-reset .resetTwoFa .btn'); - await page.waitFor(500); - const modal = await page.$('.modal.open'); + const modal = await page.waitFor('.modal.open', { visible: true }); + await page.waitFor(1000); // animation expect(await modal.screenshot()).to.matchImage('edit_with_2fa_reset_confirm'); }); it('should be possible to confirm the reset', async function () { await page.click('.twofa-confirm-modal .modal-close:not(.modal-no)'); - await page.waitFor(250); // wait for modal to close + await page.waitFor(500); // wait for modal to close expect(await page.screenshotSelector('#content,#notificationContainer')).to.matchImage('edit_with_2fa_reset_confirmed'); }); diff --git a/plugins/TwoFactorAuth/tests/UI/TwoFactorAuth_spec.js b/plugins/TwoFactorAuth/tests/UI/TwoFactorAuth_spec.js index 5e216d793d..8b702b230f 100644 --- a/plugins/TwoFactorAuth/tests/UI/TwoFactorAuth_spec.js +++ b/plugins/TwoFactorAuth/tests/UI/TwoFactorAuth_spec.js @@ -19,7 +19,7 @@ describe("TwoFactorAuth", function () { async function selectModalButton(button) { - await page.click('.modal.open .modal-footer a:contains('+button+')'); + await (await page.jQuery('.modal.open .modal-footer a:contains('+button+')')).click(); } async function loginUser(username, doAuth) @@ -70,11 +70,13 @@ describe("TwoFactorAuth", function () { async function confirmPassword() { + await page.waitFor('.confirmPasswordForm'); await page.evaluate(function(){ $('.confirmPasswordForm #login_form_password').val('123abcDk3_l3'); $('.confirmPasswordForm #login_form_submit').click(); }); - await page.waitFor(750); + await page.waitForNetworkIdle(); + await page.waitFor(100); } it('a user with 2fa can open the widgetized view by token without needing to verify', async function () { @@ -86,7 +88,7 @@ describe("TwoFactorAuth", function () { await loginUser('with2FA', false); expect(await page.screenshotSelector('.loginSection')).to.matchImage('logme_not_verified'); }); -return; + it('when logging in and providing wrong code an error is shown', async function () { await page.type('.loginTwoFaForm #login_form_authcode', '555555'); await page.evaluate(function(){ @@ -101,14 +103,18 @@ return; await page.evaluate(function(){ $('.loginTwoFaForm #login_form_submit').click(); }); - await page.waitFor(1500); - expect(await page.screenshotSelector('#content')).to.matchImage('logme_verified'); + await page.waitForNetworkIdle(); + await page.waitFor('.widget'); + expect(await page.screenshotSelector('.pageWrap')).to.matchImage('logme_verified'); }); it('should show user settings when two-fa enabled', async function () { await loginUser('with2FA'); await page.goto(userSettings); - expect(await page.screenshotSelector('.userSettings2FA')).to.matchImage('usersettings_twofa_enabled'); + await page.waitFor('.userSettings2FA', { visible: true }); + await page.waitFor(500); // animation + const elem = await page.$('.userSettings2FA'); + expect(await elem.screenshot()).to.matchImage('usersettings_twofa_enabled'); }); it('should be possible to show recovery codes step1 authentication', async function () { @@ -145,7 +151,9 @@ return; it('should be possible to disable two factor step 3 verified', async function () { await confirmPassword(); - expect(await page.screenshotSelector('.userSettings2FA')).to.matchImage('usersettings_twofa_disable_step3'); + await page.waitFor('.userSettings2FA'); + const elem = await page.$('.userSettings2FA'); + expect(await elem.screenshot()).to.matchImage('usersettings_twofa_disable_step3'); }); it('should show setup screen - step 1', async function () { @@ -157,21 +165,15 @@ return; }); it('should move to second step in setup - step 2', async function () { - console.log('start'); await page.evaluate(function(){ $('.setupTwoFactorAuthentication .backupRecoveryCode:first').click(); }); - console.log(0); await page.waitForNetworkIdle(); - console.log(1); await page.click('.setupTwoFactorAuthentication .goToStep2'); - console.log(2); await page.waitForNetworkIdle(); - console.log(3); await page.evaluate(function () { $('#qrcode').hide(); }); - console.log(4); expect(await page.screenshotSelector('#content')).to.matchImage('twofa_setup_step2'); }); @@ -190,6 +192,9 @@ return; await page.evaluate(function () { $('.setupConfirmAuthCodeForm .confirmAuthCode').click(); }); + await page.waitForNetworkIdle(); + await page.waitFor('.widget', { visible: true }); + await page.waitForNetworkIdle(); expect(await page.screenshotSelector('#content')).to.matchImage('twofa_setup_step4'); }); @@ -220,6 +225,7 @@ return; await page.evaluate(function () { $('.setupConfirmAuthCodeForm .confirmAuthCode').click(); }); + await page.waitForNetworkIdle(); expect(await page.screenshotSelector('.loginSection,#content,#notificationContainer')).to.matchImage('twofa_forced_step4'); }); diff --git a/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuthUsersManager_edit_with_2fa_reset_confirmed.png b/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuthUsersManager_edit_with_2fa_reset_confirmed.png index 631b48a8e7..820faa151d 100644 --- a/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuthUsersManager_edit_with_2fa_reset_confirmed.png +++ b/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuthUsersManager_edit_with_2fa_reset_confirmed.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e51ce8c2d7cf9e6e81b84e89e83a0f6a453196102265b52da8be1eac7aa13b83 -size 28365 +oid sha256:99b7384aaf0b2a6c63fdda6611b323883bc735ecebd29e6f181f07d16a724fce +size 30075 diff --git a/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuthUsersManager_list.png b/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuthUsersManager_list.png index dd1ee87fdd..1a7af9b184 100644 --- a/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuthUsersManager_list.png +++ b/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuthUsersManager_list.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7b94002780dbc44e7382858defa946a81fe67239ea2deccfeeb75217de7aa71f -size 53075 +oid sha256:baac8634397639a2ad11797e1390d5ed467ec1fe11a1c14dbe0033f78e67dbb0 +size 58717 diff --git a/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuth_logme_not_verified_wrong_code.png b/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuth_logme_not_verified_wrong_code.png index 6409ebc3c6..613960079c 100644 --- a/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuth_logme_not_verified_wrong_code.png +++ b/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuth_logme_not_verified_wrong_code.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:69c1dbbf415620f8d133bfd5894d5e698a732f5f82aa3aa90d3a142f14b03c0d -size 49008 +oid sha256:7b830596d955d1db652a5877e1591e616dd611d9422dad8475271ae175964833 +size 49340 diff --git a/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuth_logme_verified.png b/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuth_logme_verified.png index db5c9c5d34..26f8a16927 100644 --- a/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuth_logme_verified.png +++ b/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuth_logme_verified.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:432d04719b40530913c1c0230d3a36c98a7d04f76977ff5f4795055f3b0d395d -size 139500 +oid sha256:276d31c54153cd889f9ff5a7095c0ba0311a75f4d15a3579653e3379e4730943 +size 137776 diff --git a/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuth_show_recovery_codes_step1.png b/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuth_show_recovery_codes_step1.png index 5a439faa51..d511b3665a 100644 --- a/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuth_show_recovery_codes_step1.png +++ b/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuth_show_recovery_codes_step1.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b6d5c8f0591b7c3455ec903881f1f0466b6b63029f2a950d83a7a2f51d304a7a -size 13390 +oid sha256:bf4e7b2dd1d68df9db0826eb9051f796bf3c25426659a9e84792ae4879835f17 +size 13422 diff --git a/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuth_show_recovery_codes_step2.png b/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuth_show_recovery_codes_step2.png index 1fe16418ca..7a0f177274 100644 --- a/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuth_show_recovery_codes_step2.png +++ b/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuth_show_recovery_codes_step2.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:80a3c4babfdfbf6040181cdf4d7059502d3af8df0c0572a16f17cda3e852dc22 -size 63846 +oid sha256:9c10cc5cb40f56bd3a71513c262d91d99a474ff8f975ea67ad24ee1bb8ead0a9 +size 60823 diff --git a/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuth_twofa_forced_step1.png b/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuth_twofa_forced_step1.png index 40e3aad93f..07e63fa139 100644 --- a/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuth_twofa_forced_step1.png +++ b/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuth_twofa_forced_step1.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:750bbc270525ea990e3a541b7d4ce5e819aefe1a05e937dd538af5d2cec34178 -size 103348 +oid sha256:db93961069bfc3e3fb3f2fb7204921eb835545c2ce7535b068f5502474822591 +size 93376 diff --git a/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuth_twofa_forced_step4.png b/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuth_twofa_forced_step4.png index db5c9c5d34..07e63fa139 100644 --- a/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuth_twofa_forced_step4.png +++ b/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuth_twofa_forced_step4.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:432d04719b40530913c1c0230d3a36c98a7d04f76977ff5f4795055f3b0d395d -size 139500 +oid sha256:db93961069bfc3e3fb3f2fb7204921eb835545c2ce7535b068f5502474822591 +size 93376 diff --git a/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuth_twofa_setup_step1.png b/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuth_twofa_setup_step1.png index 2b525ac946..bab5330078 100644 --- a/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuth_twofa_setup_step1.png +++ b/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuth_twofa_setup_step1.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d0bc9e697dff2fd9f91451a033ba778c3742e397c2d6f934a8a6b780fa5f02aa -size 74454 +oid sha256:66a49cb6fc2e73a20ac31e54911199f3b3c8646bea27c43c66b2597f73c249ed +size 67812 diff --git a/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuth_twofa_setup_step2.png b/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuth_twofa_setup_step2.png index 474486f7df..239a6747b4 100644 --- a/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuth_twofa_setup_step2.png +++ b/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuth_twofa_setup_step2.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f5a3d9c0bf5c0cacfbcf1b7062a9741a5f2b3cbe093448dd3ffac81202c84f3b -size 93330 +oid sha256:7816b91a497e36536fcae8c6a361ea5b1e1ddce8c03361746de5e5e06b947a40 +size 86881 diff --git a/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuth_twofa_setup_step3.png b/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuth_twofa_setup_step3.png index 6960b50d5b..e53a9cbd52 100644 --- a/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuth_twofa_setup_step3.png +++ b/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuth_twofa_setup_step3.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ea30e34f67d85fad191e90f6d10f63275bd243a7357b020e9875babd1a2e2f47 -size 121508 +oid sha256:428605cbed55a690c110dd4db5c863b352d55a9add141e565398f1e7d728239e +size 115196 diff --git a/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuth_usersettings_twofa_disable_step1.png b/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuth_usersettings_twofa_disable_step1.png index 95fcf8073c..2fb49cb840 100644 --- a/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuth_usersettings_twofa_disable_step1.png +++ b/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuth_usersettings_twofa_disable_step1.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:035f9173979d5650c2ae6dbca4a19c80601b62c4f984c2be912b03cdf57e304a -size 21734 +oid sha256:bdd3ba9255f3e954c863fcb73e3437e8e1fcc80aa54279f67a07375d4d2021a7 +size 14250 diff --git a/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuth_usersettings_twofa_disable_step2.png b/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuth_usersettings_twofa_disable_step2.png index a98ade64c8..d511b3665a 100644 --- a/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuth_usersettings_twofa_disable_step2.png +++ b/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuth_usersettings_twofa_disable_step2.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9dddb94c30224362115ae13ebd5170c96caa80be88b18583f7920e0fd213117a -size 15127 +oid sha256:bf4e7b2dd1d68df9db0826eb9051f796bf3c25426659a9e84792ae4879835f17 +size 13422 diff --git a/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuth_usersettings_twofa_disable_step3.png b/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuth_usersettings_twofa_disable_step3.png index 0418149865..b3b8979820 100644 --- a/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuth_usersettings_twofa_disable_step3.png +++ b/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuth_usersettings_twofa_disable_step3.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8af9fbcce1498486fd7f42bf18bed791db6dc49e9fb5e9f94f21ea31ab105383 -size 45375 +oid sha256:d81de0a72d903346c4525603144ba753c40a76c3beb90031978226dc6f9fdd06 +size 43691 diff --git a/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuth_usersettings_twofa_enabled.png b/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuth_usersettings_twofa_enabled.png index 8d7197e95b..98a68ce59f 100644 --- a/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuth_usersettings_twofa_enabled.png +++ b/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuth_usersettings_twofa_enabled.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d11dc17a3b0d891e8dbee1734ec31ff22230d71aa0bedab23f4389e0bb8e8e1e -size 46583 +oid sha256:34c0c73879e1a8ba3a300ba70f7dcf3b07f4713e6a411e8ca3217f38d24eb3eb +size 46631 diff --git a/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuth_usersettings_twofa_enabled_required.png b/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuth_usersettings_twofa_enabled_required.png index 2639572760..b7f9641396 100644 --- a/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuth_usersettings_twofa_enabled_required.png +++ b/plugins/TwoFactorAuth/tests/UI/expected-screenshots/TwoFactorAuth_usersettings_twofa_enabled_required.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9d6bba78762b389d8902269840b1bb590918c7bbfe17ec62f452e19411a268fc -size 52910 +oid sha256:1c6bc6770a97cd4b571f1fae0a2d21a2c43d01c302eb8f4e3d5fc170b40a9b50 +size 51621 diff --git a/plugins/UsersManager/API.php b/plugins/UsersManager/API.php index fb3fa2e3c6..2696c9ffe2 100644 --- a/plugins/UsersManager/API.php +++ b/plugins/UsersManager/API.php @@ -48,6 +48,7 @@ class API extends \Piwik\Plugin\API const OPTION_NAME_PREFERENCE_SEPARATOR = '_'; public static $UPDATE_USER_REQUIRE_PASSWORD_CONFIRMATION = true; + public static $SET_SUPERUSER_ACCESS_REQUIRE_PASSWORD_CONFIRMATION = true; /** * @var Model @@ -701,12 +702,23 @@ class API extends \Piwik\Plugin\API * @param string $userLogin the user login. * @param bool|int $hasSuperUserAccess true or '1' to grant Super User access, false or '0' to remove Super User * access. + * @param string $passwordConfirmation the current user's password. * @throws \Exception */ - public function setSuperUserAccess($userLogin, $hasSuperUserAccess) + public function setSuperUserAccess($userLogin, $hasSuperUserAccess, $passwordConfirmation = null) { Piwik::checkUserHasSuperUserAccess(); $this->checkUserIsNotAnonymous($userLogin); + + $requirePasswordConfirmation = self::$SET_SUPERUSER_ACCESS_REQUIRE_PASSWORD_CONFIRMATION; + self::$SET_SUPERUSER_ACCESS_REQUIRE_PASSWORD_CONFIRMATION = true; + + $isCliMode = Common::isPhpCliMode() && !(defined('PIWIK_TEST_MODE') && PIWIK_TEST_MODE); + if (!$isCliMode + && $requirePasswordConfirmation + ) { + $this->confirmCurrentUserPassword($passwordConfirmation); + } $this->checkUserExists($userLogin); if (!$hasSuperUserAccess && $this->isUserTheOnlyUserHavingSuperUserAccess($userLogin)) { @@ -853,9 +865,10 @@ class API extends \Piwik\Plugin\API $_isPasswordHashed = false, $passwordConfirmation = false) { $requirePasswordConfirmation = self::$UPDATE_USER_REQUIRE_PASSWORD_CONFIRMATION; - $isEmailNotificationOnInConfig = Config::getInstance()->General['enable_update_users_email']; self::$UPDATE_USER_REQUIRE_PASSWORD_CONFIRMATION = true; + $isEmailNotificationOnInConfig = Config::getInstance()->General['enable_update_users_email']; + Piwik::checkUserHasSuperUserAccessOrIsTheUser($userLogin); $this->checkUserIsNotAnonymous($userLogin); $this->checkUserExists($userLogin); @@ -901,16 +914,7 @@ class API extends \Piwik\Plugin\API } if ($changeShouldRequirePasswordConfirmation && $requirePasswordConfirmation) { - if (empty($passwordConfirmation)) { - throw new Exception(Piwik::translate('UsersManager_ConfirmWithPassword')); - } - - $passwordConfirmation = Common::unsanitizeInputValue($passwordConfirmation); - - $loginCurrentUser = Piwik::getCurrentUserLogin(); - if (!$this->passwordVerifier->isPasswordCorrect($loginCurrentUser, $passwordConfirmation)) { - throw new Exception(Piwik::translate('UsersManager_CurrentPasswordNotCorrect')); - } + $this->confirmCurrentUserPassword($passwordConfirmation); } $alias = $this->getCleanAlias($alias, $userLogin); @@ -1392,6 +1396,20 @@ class API extends \Piwik\Plugin\API return [$roles, $capabilities]; } + private function confirmCurrentUserPassword($passwordConfirmation) + { + if (empty($passwordConfirmation)) { + throw new Exception(Piwik::translate('UsersManager_ConfirmWithPassword')); + } + + $passwordConfirmation = Common::unsanitizeInputValue($passwordConfirmation); + + $loginCurrentUser = Piwik::getCurrentUserLogin(); + if (!$this->passwordVerifier->isPasswordCorrect($loginCurrentUser, $passwordConfirmation)) { + throw new Exception(Piwik::translate('UsersManager_CurrentPasswordNotCorrect')); + } + } + private function sendEmailChangedEmail($user, $newEmail) { // send the mail to both the old email and the new email diff --git a/plugins/UsersManager/UserUpdater.php b/plugins/UsersManager/UserUpdater.php index 87d748a6dd..4d49b5a50f 100644 --- a/plugins/UsersManager/UserUpdater.php +++ b/plugins/UsersManager/UserUpdater.php @@ -41,4 +41,16 @@ class UserUpdater } } + public function setSuperUserAccessWithoutCurrentPassword($userLogin, $hasSuperUserAccess) + { + API::$SET_SUPERUSER_ACCESS_REQUIRE_PASSWORD_CONFIRMATION = false; + try { + Request::processRequest('UsersManager.setSuperUserAccess', [ + 'userLogin' => $userLogin, + 'hasSuperUserAccess' => $hasSuperUserAccess, + ], $default = []); + } finally { + API::$SET_SUPERUSER_ACCESS_REQUIRE_PASSWORD_CONFIRMATION = true; + } + } }
\ No newline at end of file diff --git a/plugins/UsersManager/angularjs/user-edit-form/user-edit-form.component.html b/plugins/UsersManager/angularjs/user-edit-form/user-edit-form.component.html index a92fbd4b95..8c831c87c5 100644 --- a/plugins/UsersManager/angularjs/user-edit-form/user-edit-form.component.html +++ b/plugins/UsersManager/angularjs/user-edit-form/user-edit-form.component.html @@ -4,6 +4,7 @@ class="userEditForm" ng-class="{ loading: $ctrl.isSavingUserInfo }" > + <div class="row" piwik-form> <div class="col m2 entityList" ng-if="!$ctrl.isAdd"> <ul class="listCircle"> @@ -98,8 +99,8 @@ <div ng-if="!$ctrl.isAdd" ng-show="$ctrl.activeTab === 'permissions'" class="user-permissions"> <piwik-user-permissions-edit - user-login="$ctrl.user.login" ng-if="!$ctrl.user.superuser_access" + user-login="$ctrl.user.login" on-user-has-access-detected="$ctrl.userHasAccess = hasAccess" on-access-change="$ctrl.isUserModified = true" access-levels="$ctrl.accessLevels" @@ -120,7 +121,7 @@ piwik-field uicontrol="checkbox" name="superuser_access" - ng-model="$ctrl.user.superuser_access" + ng-model="$ctrl.superUserAccessChecked" ng-attr-title="{{:: 'UsersManager_HasSuperUserAccess'|translate }}" ng-click="$ctrl.confirmSuperUserChange()" data-disabled="$ctrl.isSavingUserInfo" @@ -130,21 +131,28 @@ <div class="superuser-confirm-modal modal"> <div class="modal-content"> <h2>{{:: 'UsersManager_AreYouSure'|translate }}</h2> - <p ng-if="!$ctrl.user.superuser_access"> + <p ng-if="$ctrl.user.superuser_access"> {{:: 'UsersManager_RemoveSuperuserAccessConfirm'|translate }} </p> - <p ng-if="$ctrl.user.superuser_access"> + <p ng-if="!$ctrl.user.superuser_access"> {{:: 'UsersManager_AddSuperuserAccessConfirm'|translate }} </p> + + <div piwik-field uicontrol="password" name="currentUserPasswordForSuperUser" autocomplete="off" + ng-model="$ctrl.passwordConfirmationForSuperUser" + full-width="true" + title="{{ 'UsersManager_YourCurrentPassword'|translate }}" + value=""> + </div> </div> <div class="modal-footer"> <a href="" class="modal-action modal-close btn" ng-click="$ctrl.toggleSuperuserAccess()">{{:: 'General_Yes'|translate }}</a> - <a href="" class="modal-action modal-close modal-no" ng-click="$ctrl.user.superuser_access = !$ctrl.user.superuser_access">{{:: 'General_No'|translate }}</a> + <a href="" class="modal-action modal-close modal-no" ng-click="$ctrl.setSuperUserAccessChecked()">{{:: 'General_No'|translate }}</a> </div> </div> </div> - <div ng-if="$ctrl.activeTab === '2fa' && $ctrl.currentUserRole == 'superuser' && !$ctrl.isAdd" class="twofa-reset"> + <div ng-show="$ctrl.activeTab === '2fa'" ng-if="$ctrl.currentUserRole == 'superuser' && !$ctrl.isAdd" class="twofa-reset"> <p>{{:: 'UsersManager_ResetTwoFactorAuthenticationInfo'|translate }}</p> <div piwik-save-button @@ -168,6 +176,7 @@ </div> </div> + <div class="change-password-modal modal"> <div class="modal-content"> <h2 piwik-translate="UsersManager_AreYouSureChangeDetails"><strong>{{ $ctrl.user.login }}</strong></h2> @@ -185,4 +194,5 @@ <a href="" class="modal-action modal-close modal-no">{{:: 'General_No'|translate }}</a> </div> </div> -</div> + +</div>
\ No newline at end of file diff --git a/plugins/UsersManager/angularjs/user-edit-form/user-edit-form.component.js b/plugins/UsersManager/angularjs/user-edit-form/user-edit-form.component.js index bb929d5749..852469dbc1 100644 --- a/plugins/UsersManager/angularjs/user-edit-form/user-edit-form.component.js +++ b/plugins/UsersManager/angularjs/user-edit-form/user-edit-form.component.js @@ -46,6 +46,7 @@ vm.saveUserInfo = saveUserInfo; vm.reset2FA = reset2FA; vm.updateUser = updateUser; + vm.setSuperUserAccessChecked = setSuperUserAccessChecked; function $onInit() { vm.firstSiteAccess = { @@ -65,6 +66,8 @@ if (!vm.isAdd) { vm.user.password = 'XXXXXXXX'; // make sure password is not stored in the client after update/save } + + setSuperUserAccessChecked(); } function getFormTitle() { @@ -105,15 +108,24 @@ method: 'UsersManager.setSuperUserAccess' }, { userLogin: vm.user.login, - hasSuperUserAccess: vm.user.superuser_access ? '1' : '0' + hasSuperUserAccess: vm.user.superuser_access ? '0' : '1', + passwordConfirmation: vm.passwordConfirmationForSuperUser, + }).then(function () { + vm.user.superuser_access = !vm.user.superuser_access; }).catch(function () { // ignore error (still displayed to user) }).then(function () { vm.isSavingUserInfo = false; vm.isUserModified = true; + vm.passwordConfirmationForSuperUser = null; + setSuperUserAccessChecked(); }); } + function setSuperUserAccessChecked() { + vm.superUserAccessChecked = !! vm.user.superuser_access; + } + function saveUserInfo() { if (vm.isAdd) { createUser(); diff --git a/plugins/UsersManager/lang/en.json b/plugins/UsersManager/lang/en.json index 69179b7cf5..866b52567a 100644 --- a/plugins/UsersManager/lang/en.json +++ b/plugins/UsersManager/lang/en.json @@ -127,8 +127,8 @@ "SuperUserIntro2": "Please use this feature carefully.", "HasSuperUserAccess": "Has Superuser Access", "AreYouSure": "Are you sure?", - "RemoveSuperuserAccessConfirm": "Removing superuser access will leave the user with no permissions (you will have to add them afterwards). Do you wish to continue?", - "AddSuperuserAccessConfirm": "Giving a user superuser access will allow the user to have full control over Matomo and should be done sparingly. Do you wish to continue?", + "RemoveSuperuserAccessConfirm": "Removing superuser access will leave the user with no permissions (you will have to add them afterwards). Enter your password to continue.", + "AddSuperuserAccessConfirm": "Giving a user superuser access will allow the user to have full control over Matomo and should be done sparingly. Enter your password to continue.", "DeleteUsers": "Delete Users", "UserSearch": "User search", "FilterByAccess": "Filter by access", diff --git a/plugins/UsersManager/tests/Fixtures/ManyUsers.php b/plugins/UsersManager/tests/Fixtures/ManyUsers.php index 13a998e456..1382a55fd2 100644 --- a/plugins/UsersManager/tests/Fixtures/ManyUsers.php +++ b/plugins/UsersManager/tests/Fixtures/ManyUsers.php @@ -9,6 +9,7 @@ namespace Piwik\Plugins\UsersManager\tests\Fixtures; use Piwik\Plugins\UsersManager\API; use Piwik\Plugins\UsersManager\Model; +use Piwik\Plugins\UsersManager\UserUpdater; use Piwik\Tests\Framework\Fixture; /** @@ -121,7 +122,8 @@ class ManyUsers extends Fixture } if ($access == 'superuser') { - $api->setSuperUserAccess($login, true); + $userUpdater = new UserUpdater(); + $userUpdater->setSuperUserAccessWithoutCurrentPassword($login, true); } else { $api->setUserAccess($login, $access, $idSites); } diff --git a/plugins/UsersManager/tests/Integration/APITest.php b/plugins/UsersManager/tests/Integration/APITest.php index a512660e6b..27c83ec306 100644 --- a/plugins/UsersManager/tests/Integration/APITest.php +++ b/plugins/UsersManager/tests/Integration/APITest.php @@ -20,6 +20,7 @@ use Piwik\Plugins\SitesManager\API as SitesManagerAPI; use Piwik\Plugins\UsersManager\API; use Piwik\Plugins\UsersManager\Model; use Piwik\Plugins\UsersManager\UsersManager; +use Piwik\Plugins\UsersManager\UserUpdater; use Piwik\Tests\Framework\Fixture; use Piwik\Tests\Framework\Mock\FakeAccess; use Piwik\Tests\Framework\TestCase\IntegrationTestCase; @@ -381,7 +382,8 @@ class APITest extends IntegrationTestCase $access = $this->api->getSitesAccessFromUser($user2); $this->assertEmpty($access); - $this->api->setSuperUserAccess($user2, true); + $userUpdater = new UserUpdater(); + $userUpdater->setSuperUserAccessWithoutCurrentPassword($user2, true); // super user has admin access for every site $access = $this->api->getSitesAccessFromUser($user2); @@ -546,7 +548,8 @@ class APITest extends IntegrationTestCase public function test_getUsersPlusRole_shouldSearchForSuperUsersCorrectly() { $this->addUserWithAccess('userLogin2', 'admin', 1); - $this->api->setSuperUserAccess('userLogin2', true); + $userUpdater = new UserUpdater(); + $userUpdater->setSuperUserAccessWithoutCurrentPassword('userLogin2', true); $this->addUserWithAccess('userLogin3', 'view', 1); $this->addUserWithAccess('userLogin4', 'superuser', 1); $this->addUserWithAccess('userLogin5', null, 1); @@ -983,6 +986,15 @@ class APITest extends IntegrationTestCase $this->assertEquals(array(View::ID, TestCap1::ID), $access); } + /** + * @expectedException \Exception + * @expectedExceptionMessage abc + */ + public function test_setSuperUserAccess_failsIfCurrentPasswordIsIncorrect() + { + $this->api->setSuperUserAccess($this->login, true, 'asldfkjds'); + } + private function getAccessInSite($login, $idSite) { $access = $this->model->getSitesAccessFromUser($login); @@ -1018,7 +1030,8 @@ class APITest extends IntegrationTestCase { $this->api->addUser($username, 'password', $email ?: "$username@password.de", $alias); if ($accessLevel == 'superuser') { - $this->api->setSuperUserAccess($username, true); + $userUpdater = new UserUpdater(); + $userUpdater->setSuperUserAccessWithoutCurrentPassword($username, true); } else if ($accessLevel) { $this->api->setUserAccess($username, $accessLevel, $idSite); } diff --git a/plugins/UsersManager/tests/Integration/UsersManagerTest.php b/plugins/UsersManager/tests/Integration/UsersManagerTest.php index abaf5d6590..43d4bbb5ee 100644 --- a/plugins/UsersManager/tests/Integration/UsersManagerTest.php +++ b/plugins/UsersManager/tests/Integration/UsersManagerTest.php @@ -10,10 +10,12 @@ namespace Piwik\Plugins\UsersManager\tests\Integration; use Piwik\Access; use Piwik\Auth\Password; +use Piwik\Common; use Piwik\Plugins\SitesManager\API as APISitesManager; use Piwik\Plugins\UsersManager\API; use Piwik\Plugins\UsersManager\Model; use Piwik\Plugins\UsersManager\UsersManager; +use Piwik\Plugins\UsersManager\UserUpdater; use Piwik\Tests\Framework\Fixture; use Piwik\Tests\Framework\Mock\FakeAccess; use Piwik\Tests\Framework\TestCase\IntegrationTestCase; @@ -380,7 +382,8 @@ class UsersManagerTest extends IntegrationTestCase //add user and set some rights $this->api->addUser("regularuser", "geqgeagae1", "test1@test.com", "alias1"); $this->api->addUser("superuser", "geqgeagae2", "test2@test.com", "alias2"); - $this->api->setSuperUserAccess('superuser', true); + $userUpdater = new UserUpdater(); + $userUpdater->setSuperUserAccessWithoutCurrentPassword('superuser', true); // delete the user $this->api->deleteUser("superuser"); @@ -604,7 +607,8 @@ class UsersManagerTest extends IntegrationTestCase public function testSetUserAccess_ShouldFail_IfLoginIsUserWithSuperUserAccess() { $this->api->addUser("gegg4564eqgeqag", "geqgegagae", "tegst@tesgt.com", "alias"); - $this->api->setSuperUserAccess('gegg4564eqgeqag', true); + $userUpdater = new UserUpdater(); + $userUpdater->setSuperUserAccessWithoutCurrentPassword('gegg4564eqgeqag', true); FakeAccess::clearAccess($superUser = false, $idSitesAdmin = array(1)); $this->api->setUserAccess('gegg4564eqgeqag', 'view', 1); @@ -806,8 +810,10 @@ class UsersManagerTest extends IntegrationTestCase */ public function testSetSuperUserAccess_ShouldFail_IfUserHasNotSuperUserPermission() { + $pwd = $this->createCurrentUser(); + FakeAccess::$superUser= false; - $this->api->setSuperUserAccess('nologin', false); + $this->api->setSuperUserAccess('nologin', false, $pwd); } /** @@ -816,7 +822,8 @@ class UsersManagerTest extends IntegrationTestCase */ public function testSetSuperUserAccess_ShouldFail_IfUserWithGivenLoginDoesNotExist() { - $this->api->setSuperUserAccess('nologin', false); + $pwd = $this->createCurrentUser(); + $this->api->setSuperUserAccess('nologin', false, $pwd); } /** @@ -825,7 +832,8 @@ class UsersManagerTest extends IntegrationTestCase */ public function testSetSuperUserAccess_ShouldFail_IfUserIsAnonymous() { - $this->api->setSuperUserAccess('anonymous', true); + $pwd = $this->createCurrentUser(); + $this->api->setSuperUserAccess('anonymous', true, $pwd); } /** @@ -834,14 +842,18 @@ class UsersManagerTest extends IntegrationTestCase */ public function testSetSuperUserAccess_ShouldFail_IfUserIsOnlyRemainingUserWithSuperUserAccess() { + $pwd = $this->createCurrentUser(); + $this->api->addUser('login1', 'password1', 'test@example.com', false); - $this->api->setSuperUserAccess('login1', true); + $this->api->setSuperUserAccess('login1', true, $pwd); - $this->api->setSuperUserAccess('login1', false); + $this->api->setSuperUserAccess('login1', false, $pwd); } public function testSetSuperUserAccess_ShouldDeleteAllExistingAccessEntries() { + $pwd = $this->createCurrentUser(); + list($id1, $id2) = $this->addSites(2); $this->api->addUser('login1', 'password1', 'test@example.com', false); $this->api->setUserAccess('login1', 'view', array($id1)); @@ -851,7 +863,7 @@ class UsersManagerTest extends IntegrationTestCase $access = $this->_flatten($this->api->getSitesAccessFromUser('login1')); $this->assertEquals(array($id1 => 'view', $id2 => 'admin'), $access); - $this->api->setSuperUserAccess('login1', true); + $this->api->setSuperUserAccess('login1', true, $pwd); // verify no longer any access $this->assertEquals(array(), $this->model->getSitesAccessFromUser('login1')); @@ -859,11 +871,13 @@ class UsersManagerTest extends IntegrationTestCase public function testSetSuperUserAccess_ShouldAddAndRemoveSuperUserAccessOnlyForGivenLogin() { + $pwd = $this->createCurrentUser(); + $this->api->addUser('login1', 'password1', 'test1@example.com', false); $this->api->addUser('login2', 'password2', 'test2@example.com', false); $this->api->addUser('login3', 'password3', 'test3@example.com', false); - $this->api->setSuperUserAccess('login2', true); + $this->api->setSuperUserAccess('login2', true, $pwd); // test add Super User access $users = $this->api->getUsers(); @@ -874,9 +888,9 @@ class UsersManagerTest extends IntegrationTestCase $this->assertEquals(0, $users[2]['superuser_access']); // should also accept string '1' to add Super User access - $this->api->setSuperUserAccess('login1', '1'); + $this->api->setSuperUserAccess('login1', '1', $pwd); // test remove Super User access - $this->api->setSuperUserAccess('login2', false); + $this->api->setSuperUserAccess('login2', false, $pwd); $users = $this->api->getUsers(); $this->assertEquals(1, $users[0]['superuser_access']); @@ -884,9 +898,9 @@ class UsersManagerTest extends IntegrationTestCase $this->assertEquals(0, $users[1]['superuser_access']); $this->assertEquals(0, $users[2]['superuser_access']); - $this->api->setSuperUserAccess('login3', true); + $this->api->setSuperUserAccess('login3', true, $pwd); // should also accept string '0' to remove Super User access - $this->api->setSuperUserAccess('login1', '0'); + $this->api->setSuperUserAccess('login1', '0', $pwd); $users = $this->api->getUsers(); $this->assertEquals(0, $users[0]['superuser_access']); @@ -1203,4 +1217,20 @@ class UsersManagerTest extends IntegrationTestCase $this->assertRegExp("(UsersManager_ExceptionUserDoesNotExist)", $expected->getMessage()); } } + + private function createCurrentUser() + { + $identity = FakeAccess::$identity; + FakeAccess::$identity = 'lskfjs'; + + $pwd = 'testpwd'; + + try { + $this->api->addUser($identity, $pwd, 'someuser@email.com'); + } finally { + FakeAccess::$identity = $identity; + } + + return $pwd; + } } diff --git a/plugins/UsersManager/tests/UI/UsersManager_spec.js b/plugins/UsersManager/tests/UI/UsersManager_spec.js index 6a7482ba5d..9ba0556c3e 100644 --- a/plugins/UsersManager/tests/UI/UsersManager_spec.js +++ b/plugins/UsersManager/tests/UI/UsersManager_spec.js @@ -74,9 +74,9 @@ describe("UsersManager", function () { }); it('should select rows when individual row select is clicked', async function () { - await (await page.jQuery('td.select-cell label:eq(0)')).click(); - await (await page.jQuery('td.select-cell label:eq(3)')).click(); - await (await page.jQuery('td.select-cell label:eq(8)')).click(); + await (await page.jQuery('td.select-cell label:eq(0)', { waitFor: true })).click(); + await (await page.jQuery('td.select-cell label:eq(3)', { waitFor: true })).click(); + await (await page.jQuery('td.select-cell label:eq(8)', { waitFor: true })).click(); await page.mouse.move(0, 0); await page.waitFor(500); // for checkbox animations @@ -116,7 +116,7 @@ describe("UsersManager", function () { await page.click('.toggle-select-all-in-search'); // reselect all in search await page.click('.bulk-actions.btn'); - await (await page.jQuery('#user-list-bulk-actions>li:first')).hover(); + await (await page.jQuery('#user-list-bulk-actions>li:first > a')).hover(); await (await page.jQuery('#bulk-set-access a:contains(Admin)')).click(); await page.waitFor(350); // wait for animation @@ -231,7 +231,7 @@ describe("UsersManager", function () { it('should add access to all websites when bulk access is used on all websites in search', async function () { await page.click('.userPermissionsEdit .bulk-actions > .dropdown-trigger.btn'); - await (await page.jQuery('#user-permissions-edit-bulk-actions>li:first')).hover(); + await (await page.jQuery('#user-permissions-edit-bulk-actions>li:first>a')).hover(); await (await page.jQuery('#user-permissions-edit-bulk-actions a:contains(Write)')).click(); await page.waitFor('.change-access-confirm-modal', { visible: true }); @@ -277,7 +277,7 @@ describe("UsersManager", function () { it('should set access to selected sites when set bulk access is used', async function () { await page.click('.userPermissionsEdit .bulk-actions > .dropdown-trigger.btn'); await page.waitFor(250); // animation - await (await page.jQuery('#user-permissions-edit-bulk-actions>li:first:visible', { waitFor: true })).hover(); + await page.evaluate(() => $('#user-permissions-edit-bulk-actions>li:first > a:visible').mouseenter()); await page.waitFor(250); // animation await (await page.jQuery('#user-permissions-edit-bulk-actions a:contains(Admin):visible', { waitFor: true })).click(); @@ -291,11 +291,12 @@ describe("UsersManager", function () { }); it('should filter the permissions when the filters are used', async function () { - await page.type('div.site-filter>input', 'nova'); await page.evaluate(function () { - $('.access-filter select').val('string:admin').change(); + $('.userPermissionsEdit .access-filter select').val('string:admin').change(); }); await page.waitForNetworkIdle(); + await page.type('.userPermissionsEdit div.site-filter>input', 'hunter'); + await page.waitForNetworkIdle(); await page.waitFor('#sitesForPermission tr', { visible: true }); await page.waitFor(1000); @@ -311,18 +312,20 @@ describe("UsersManager", function () { it('should set access to all sites selected when set bulk access is used', async function () { await page.click('.userPermissionsEdit .bulk-actions > .dropdown-trigger.btn'); - await page.waitFor(100); // animation - await (await page.jQuery('#user-permissions-edit-bulk-actions>li:first', { waitFor: true })).hover(); - await page.waitFor(100); // animation + await page.waitFor(250); // animation + await page.evaluate(() => $('#user-permissions-edit-bulk-actions>li:first > a:visible').mouseenter()); + await page.waitFor(250); // animation await (await page.jQuery('#user-permissions-edit-bulk-actions a:contains(View)', { waitFor: true })).click(); await page.waitFor(250); // animation await page.evaluate(() => $('.change-access-confirm-modal .modal-close:not(.modal-no):visible').click()); + await page.waitForNetworkIdle(); await page.evaluate(function () { // remove filter $('.access-filter select').val('string:some').change(); }); await page.waitForNetworkIdle(); + await page.waitFor(250); // animation expect(await page.screenshotSelector('.usersManager')).to.matchImage('permissions_bulk_access_set_all'); }); @@ -347,12 +350,12 @@ describe("UsersManager", function () { await page.waitFor(250); // animation - await page.evaluate(() => $('.confirmCapabilityToggle .modal-close:not(.modal-no):visible').click()); + await page.evaluate(() => $('.userPermissionsEdit .confirmCapabilityToggle .modal-close:not(.modal-no):visible').click()); await page.waitForNetworkIdle(); await page.waitFor(250); // animation - expect(await page.screenshotSelector('.admin#content')).to.matchImage('permissions_capability_single_site'); + expect(await page.screenshotSelector('.usersManager')).to.matchImage('permissions_capability_single_site'); }); it('should remove access to displayed rows when remove bulk access is clicked', async function () { @@ -394,7 +397,22 @@ describe("UsersManager", function () { expect(await elem.screenshot()).to.matchImage('superuser_confirm'); }); + it('should fail to set superuser access if password is wrong', async function () { + await page.type('input#currentUserPasswordForSuperUser', 'wrongpassword'); + await page.evaluate(() => $('.superuser-confirm-modal .modal-close:not(.modal-no):visible').click()); + await page.waitForNetworkIdle(); + + await page.waitFor('.notification-error', { visible: true }); + + const notificationHtml = await page.evaluate(() => $('.notification-error>div').html()); + expect(notificationHtml).to.equal('The current password you entered is not correct.'); + }); + it('should give the user superuser access when the superuser modal is confirmed', async function () { + await page.click('.userEditForm #superuser_access+label'); + await page.waitFor(500); + + await page.type('input#currentUserPasswordForSuperUser', 'superUserPass'); await page.evaluate(() => $('.superuser-confirm-modal .modal-close:not(.modal-no):visible').click()); await page.waitForNetworkIdle(); await page.waitFor(500); diff --git a/plugins/UsersManager/tests/UI/expected-screenshots/UsersManager_manage_users_back.png b/plugins/UsersManager/tests/UI/expected-screenshots/UsersManager_manage_users_back.png index 9ffaaa81a1..228c7cc0cd 100644 --- a/plugins/UsersManager/tests/UI/expected-screenshots/UsersManager_manage_users_back.png +++ b/plugins/UsersManager/tests/UI/expected-screenshots/UsersManager_manage_users_back.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f16ad832b1d64c645664e7e64408f25e491c31f3926e2da9773cc40916193009 -size 147836 +oid sha256:434264e176f6f4aa217c247fdcf032fca1d7304d8a33359e28505dc867231fcc +size 147842 diff --git a/plugins/UsersManager/tests/UI/expected-screenshots/UsersManager_permissions_bulk_access_set_all.png b/plugins/UsersManager/tests/UI/expected-screenshots/UsersManager_permissions_bulk_access_set_all.png index 323e7bce5e..117d590b71 100644 --- a/plugins/UsersManager/tests/UI/expected-screenshots/UsersManager_permissions_bulk_access_set_all.png +++ b/plugins/UsersManager/tests/UI/expected-screenshots/UsersManager_permissions_bulk_access_set_all.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4af9d284d62698df449b104597006d73dc06855761fad90333def4febc11506c -size 85673 +oid sha256:6806c1587d23ff706a62b908aeb141b98a052440f8220d14a21b688faae8b33c +size 78284 diff --git a/plugins/UsersManager/tests/UI/expected-screenshots/UsersManager_permissions_capability_single_site.png b/plugins/UsersManager/tests/UI/expected-screenshots/UsersManager_permissions_capability_single_site.png index f2623bd5fb..c12b0af534 100644 --- a/plugins/UsersManager/tests/UI/expected-screenshots/UsersManager_permissions_capability_single_site.png +++ b/plugins/UsersManager/tests/UI/expected-screenshots/UsersManager_permissions_capability_single_site.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:750fa07d8b3c6b5d7da0e68ede73131af3c1460c00aee070f2f1eda0e310d036 -size 96385 +oid sha256:c700040d1c3a9c7288d7a1f5d3354089709762dffb4764aa5f114f3bbca7c65f +size 91417 diff --git a/plugins/UsersManager/tests/UI/expected-screenshots/UsersManager_permissions_filters.png b/plugins/UsersManager/tests/UI/expected-screenshots/UsersManager_permissions_filters.png index 1cda86e3aa..28b8a16607 100644 --- a/plugins/UsersManager/tests/UI/expected-screenshots/UsersManager_permissions_filters.png +++ b/plugins/UsersManager/tests/UI/expected-screenshots/UsersManager_permissions_filters.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0dbb9ad0fad0e51c572ce7b84cc59db7dea7083b702fc663fd3ab5cccffdb245 -size 28695 +oid sha256:595839d882d0c1d20f5ccd23dff2dbab68b24940e01683b9da44dfbea28e4cdb +size 65467 diff --git a/plugins/UsersManager/tests/UI/expected-screenshots/UsersManager_permissions_select_all.png b/plugins/UsersManager/tests/UI/expected-screenshots/UsersManager_permissions_select_all.png index 9ffa892dc0..462864ba99 100644 --- a/plugins/UsersManager/tests/UI/expected-screenshots/UsersManager_permissions_select_all.png +++ b/plugins/UsersManager/tests/UI/expected-screenshots/UsersManager_permissions_select_all.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ad2b46f639d5a1d0d59299444b791011be309a71883f764cf1a22f7d712c5bbc -size 29843 +oid sha256:4162bd79000733235fe891ccf4fa90f60af9862d6a39b02cc6ef6c35d96874a1 +size 67291 diff --git a/plugins/UsersManager/tests/UI/expected-screenshots/UsersManager_permissions_single_site_access.png b/plugins/UsersManager/tests/UI/expected-screenshots/UsersManager_permissions_single_site_access.png index 2d2a9d7736..93d4420205 100644 --- a/plugins/UsersManager/tests/UI/expected-screenshots/UsersManager_permissions_single_site_access.png +++ b/plugins/UsersManager/tests/UI/expected-screenshots/UsersManager_permissions_single_site_access.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5606bd6b54b2776f8a0df93ff31d5cd7a4f527e9b24fc0727a6e33286d234c01 -size 92464 +oid sha256:ae69632d1e3c8c2c8cae6d6d1bc3d0142ba4d5ff870e85d23637e149fad76311 +size 87826 diff --git a/plugins/UsersManager/tests/UI/expected-screenshots/UsersManager_superuser_confirm.png b/plugins/UsersManager/tests/UI/expected-screenshots/UsersManager_superuser_confirm.png index 604d4b89c1..d30c26ebb8 100644 --- a/plugins/UsersManager/tests/UI/expected-screenshots/UsersManager_superuser_confirm.png +++ b/plugins/UsersManager/tests/UI/expected-screenshots/UsersManager_superuser_confirm.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:556e3e32f67793bfb45a7fb1b618bc3f20a5c81fca3cc8049374c88674a5ee91 -size 15764 +oid sha256:8aca0c9d68a8f97ac9a9c82947fb3dc00ce51455a8f3abb34c5e055a1004471c +size 19858 diff --git a/tests/PHPUnit/Fixtures/UITestFixture.php b/tests/PHPUnit/Fixtures/UITestFixture.php index c1a30680d1..92e852e87d 100644 --- a/tests/PHPUnit/Fixtures/UITestFixture.php +++ b/tests/PHPUnit/Fixtures/UITestFixture.php @@ -33,6 +33,7 @@ use Piwik\Plugins\SegmentEditor\API as APISegmentEditor; use Piwik\Plugins\UserCountry\LocationProvider; use Piwik\Plugins\UsersManager\API as UsersManagerAPI; use Piwik\Plugins\SitesManager\API as SitesManagerAPI; +use Piwik\Plugins\UsersManager\UserUpdater; use Piwik\Plugins\VisitsSummary\API as VisitsSummaryAPI; use Piwik\ReportRenderer; use Piwik\Tests\Framework\XssTesting; @@ -86,7 +87,8 @@ class UITestFixture extends SqlDump $this->addNewSitesForSiteSelector(); DbHelper::createAnonymousUser(); - UsersManagerAPI::getInstance()->setSuperUserAccess('superUserLogin', true); + $userUpdater = new UserUpdater(); + $userUpdater->setSuperUserAccessWithoutCurrentPassword('superUserLogin', true); SitesManagerAPI::getInstance()->updateSite(1, null, null, true); // create non super user diff --git a/tests/UI/expected-screenshots/UIIntegrationTest_api_listing.png b/tests/UI/expected-screenshots/UIIntegrationTest_api_listing.png index a8c7414941..9189c559c4 100644 --- a/tests/UI/expected-screenshots/UIIntegrationTest_api_listing.png +++ b/tests/UI/expected-screenshots/UIIntegrationTest_api_listing.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:491bb5a3a774c5335bb8dcc92f37d04296f7af131baf9148d875d3ec97893d0c -size 4881326 +oid sha256:1820962c24945baba500fe1bd3e4243f1f7e52007dd82fe61535950b87887306 +size 4882671 diff --git a/tests/UI/expected-screenshots/UIIntegrationTest_dashboard2.png b/tests/UI/expected-screenshots/UIIntegrationTest_dashboard2.png index 5df28e26ad..a2c94a3749 100644 --- a/tests/UI/expected-screenshots/UIIntegrationTest_dashboard2.png +++ b/tests/UI/expected-screenshots/UIIntegrationTest_dashboard2.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7c3c13d4bd60e3a468d9fd701ba39f75ba3b863fa90ac7d5db8eb063ff4241e1 -size 1567444 +oid sha256:52b600afb2ff5333ccdf3caba0458a5a8dd158365c83f2ef36e956ff126ac0d9 +size 1567745 diff --git a/tests/lib/screenshot-testing/package-lock.json b/tests/lib/screenshot-testing/package-lock.json index 3359ee74fa..d65ea5f0a5 100644 --- a/tests/lib/screenshot-testing/package-lock.json +++ b/tests/lib/screenshot-testing/package-lock.json @@ -4,11 +4,6 @@ "lockfileVersion": 1, "requires": true, "dependencies": { - "abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" - }, "accepts": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", @@ -62,20 +57,6 @@ "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=" }, - "aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" - }, - "are-we-there-yet": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", - "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, "array-filter": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-0.0.1.tgz", @@ -181,14 +162,6 @@ "resolved": "https://registry.npmjs.org/bytes/-/bytes-2.4.0.tgz", "integrity": "sha1-fZcZb51br39pNeJZhVSe3SpsIzk=" }, - "canvas-prebuilt": { - "version": "1.6.11", - "resolved": "https://registry.npmjs.org/canvas-prebuilt/-/canvas-prebuilt-1.6.11.tgz", - "integrity": "sha512-ayBAayYLgFbGBX+cwtOzM4iEQP4XB5DuBbtjgvAwQ66/FMzSR7DhlCqtDZIq9UBbpFCb1QpyDgUNVclHDdBixg==", - "requires": { - "node-pre-gyp": "^0.10.0" - } - }, "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", @@ -264,11 +237,6 @@ "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=" }, - "chownr": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz", - "integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==" - }, "cli-cursor": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", @@ -298,11 +266,6 @@ "type-is": "~1.6.6" } }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" - }, "color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -345,11 +308,6 @@ "typedarray": "^0.0.6" } }, - "console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" - }, "content-disposition": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", @@ -413,11 +371,6 @@ "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=" }, - "deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" - }, "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -438,11 +391,6 @@ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" }, - "detect-libc": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", - "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=" - }, "detect-port-alt": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/detect-port-alt/-/detect-port-alt-1.1.3.tgz", @@ -655,54 +603,11 @@ "universalify": "^0.1.0" } }, - "fs-minipass": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz", - "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==", - "requires": { - "minipass": "^2.2.1" - } - }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, - "gauge": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", - "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", - "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - }, - "dependencies": { - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - } - } - }, "get-func-name": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", @@ -806,11 +711,6 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" }, - "has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" - }, "he": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", @@ -873,24 +773,6 @@ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.13.tgz", "integrity": "sha1-H4irpKsLFQjoMSrMOTRfNumS4vI=" }, - "ignore-walk": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz", - "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", - "requires": { - "minimatch": "^3.0.4" - }, - "dependencies": { - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "requires": { - "brace-expansion": "^1.1.7" - } - } - } - }, "inflation": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/inflation/-/inflation-2.0.0.tgz", @@ -1273,30 +1155,6 @@ "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" }, - "minipass": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz", - "integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==", - "requires": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" - }, - "dependencies": { - "yallist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", - "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==" - } - } - }, - "minizlib": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.2.1.tgz", - "integrity": "sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==", - "requires": { - "minipass": "^2.2.1" - } - }, "mkdirp": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", @@ -1361,87 +1219,11 @@ "thenify-all": "^1.0.0" } }, - "needle": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/needle/-/needle-2.2.4.tgz", - "integrity": "sha512-HyoqEb4wr/rsoaIDfTH2aVL9nWtQqba2/HvMv+++m8u0dz808MaagKILxtfeSN7QU7nvbQ79zk3vYOJp9zsNEA==", - "requires": { - "debug": "^2.1.2", - "iconv-lite": "^0.4.4", - "sax": "^1.2.4" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - } - } - }, "negotiator": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" }, - "node-pre-gyp": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.10.3.tgz", - "integrity": "sha512-d1xFs+C/IPS8Id0qPTZ4bUT8wWryfR/OzzAFxweG+uLN85oPzyo2Iw6bVlLQ/JOdgNonXLCoRyqDzDWq4iw72A==", - "requires": { - "detect-libc": "^1.0.2", - "mkdirp": "^0.5.1", - "needle": "^2.2.1", - "nopt": "^4.0.1", - "npm-packlist": "^1.1.6", - "npmlog": "^4.0.2", - "rc": "^1.2.7", - "rimraf": "^2.6.1", - "semver": "^5.3.0", - "tar": "^4" - } - }, - "nopt": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", - "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", - "requires": { - "abbrev": "1", - "osenv": "^0.1.4" - } - }, - "npm-bundled": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.5.tgz", - "integrity": "sha512-m/e6jgWu8/v5niCUKQi9qQl8QdeEduFA96xHDDzFGqly0OOjI7c+60KM/2sppfnUU9JJagf+zs+yGhqSOFj71g==" - }, - "npm-packlist": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.1.12.tgz", - "integrity": "sha512-WJKFOVMeAlsU/pjXuqVdzU0WfgtIBCupkEVwn+1Y0ERAbUfWw8R4GjgVbaKnUjRoD2FoQbHOCbOyT5Mbs9Lw4g==", - "requires": { - "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1" - } - }, - "npmlog": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", - "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" - }, "oauth-sign": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", @@ -1497,25 +1279,11 @@ "url-parse": "^1.4.3" } }, - "os-homedir": { - "version": "1.0.2", - "resolved": "http://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" - }, "os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" }, - "osenv": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", - "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, "parse-passwd": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", @@ -1634,24 +1402,6 @@ "unpipe": "1.0.0" } }, - "rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" - } - } - }, "react-dev-utils": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-4.2.3.tgz", @@ -1791,14 +1541,6 @@ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" }, - "resemblejs": { - "version": "2.10.3", - "resolved": "https://registry.npmjs.org/resemblejs/-/resemblejs-2.10.3.tgz", - "integrity": "sha512-Qt4vEIjpJd/XmpnbIcbLBuO3Fj2bVUOi3hsTSoRJAP0oC3bkTOgPuxFqT00QkDogF0qWEFUtidf/1S6XqOVG3w==", - "requires": { - "canvas-prebuilt": "^1.6.5-prerelease.1" - } - }, "resolve-dir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", @@ -1865,21 +1607,6 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, - "sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" - }, - "semver": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", - "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==" - }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" - }, "setprototypeof": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", @@ -2003,37 +1730,11 @@ "ansi-regex": "^2.0.0" } }, - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" - }, "supports-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" }, - "tar": { - "version": "4.4.8", - "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.8.tgz", - "integrity": "sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==", - "requires": { - "chownr": "^1.1.1", - "fs-minipass": "^1.2.5", - "minipass": "^2.3.4", - "minizlib": "^1.1.1", - "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.2", - "yallist": "^3.0.2" - }, - "dependencies": { - "yallist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", - "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==" - } - } - }, "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -2189,14 +1890,6 @@ "isexe": "^2.0.0" } }, - "wide-align": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", - "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", - "requires": { - "string-width": "^1.0.2 || 2" - } - }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", diff --git a/tests/lib/screenshot-testing/package.json b/tests/lib/screenshot-testing/package.json index 40a5302ea6..902c7fe3a0 100644 --- a/tests/lib/screenshot-testing/package.json +++ b/tests/lib/screenshot-testing/package.json @@ -5,7 +5,6 @@ "author": "Matomo Team", "license": "GPL-3.0+", "dependencies": { - "canvas-prebuilt": "^1.6.11", "chai": "^4.1.2", "chai-files": "^1.4.0", "chai-image-assert": "^1.2.0", @@ -14,7 +13,6 @@ "puppeteer": "^1.15.0-next.1556321762762", "request": "^2.88.0", "request-promise": "^4.2.2", - "resemblejs": "^2.10.3", "url-parse": "^1.4.3" } } diff --git a/tests/lib/screenshot-testing/run-tests.js b/tests/lib/screenshot-testing/run-tests.js index 8175bf9c2c..5d32024b72 100644 --- a/tests/lib/screenshot-testing/run-tests.js +++ b/tests/lib/screenshot-testing/run-tests.js @@ -15,7 +15,6 @@ const setUpGlobals = require('./support/globals.js'); const Mocha = require('mocha'); const chai = require('chai'); const chaiFiles = require('chai-files'); -const resemble = require('resemblejs'); require('./support/fs-extras'); main(); @@ -52,36 +51,6 @@ async function main() { chai.use(imageAssert()); chai.use(chaiFiles); - // TODO: outputSettings is deprecated, should use in chai - resemble.outputSettings({ - errorColor: { - red: 255, - green: 0, - blue: 0, - alpha: 125 - }, - errorType: 'movement', - transparency: 0.3, - largeImageThreshold: 20000, - }); - - // TODO: implement load timeout? not sure if it's needed. - /* TODO: timeout should be global mocha timeout - timeout = setTimeout(function () { - var timeoutDetails = ""; - timeoutDetails += "Page is loading: " + self._isLoading + "\n"; - timeoutDetails += "Initializing: " + self._isInitializing + "\n"; - timeoutDetails += "Navigation requested: " + self._isNavigationRequested + "\n"; - timeoutDetails += "Pending AJAX request count: " + self._getAjaxRequestCount() + "\n"; - timeoutDetails += "Loading images count: " + self._getImageLoadingCount() + "\n"; - timeoutDetails += "Remaining resources: " + JSON.stringify(self._resourcesRequested) + "\n"; - - self.abort(); - - callback(new Error("Screenshot load timeout. Details:\n" + timeoutDetails)); - }, 240 * 1000); - */ - // run script if (options['help']) { app.printHelpAndExit(); diff --git a/tests/lib/screenshot-testing/support/test-environment.js b/tests/lib/screenshot-testing/support/test-environment.js index 7989bc1f78..5034673c05 100644 --- a/tests/lib/screenshot-testing/support/test-environment.js +++ b/tests/lib/screenshot-testing/support/test-environment.js @@ -171,7 +171,8 @@ TestingEnvironment.prototype.setupFixture = function (fixtureClass, done) { var args = [ fixtureClass || DEFAULT_UI_TEST_FIXTURE_NAME, '--set-phantomjs-symlinks', - '--server-global=' + JSON.stringify(config.phpServer) + '--server-global=' + JSON.stringify(config.phpServer), + '-vvv', ]; if (options['persist-fixture-data']) { @@ -189,8 +190,8 @@ TestingEnvironment.prototype.setupFixture = function (fixtureClass, done) { args.push('--plugins=' + options['plugin']); } - if (options['piwik-domain']) { - args.push('--piwik-domain=' + options['piwik-domain']); + if (options['piwik-domain'] || options['matomo-domain']) { + args.push('--piwik-domain=' + (options['piwik-domain'] || options['matomo-domain'])); } if (options['enable-logging']) { diff --git a/tests/resources/screenshot-override/override.css b/tests/resources/screenshot-override/override.css index 4a148e4fd9..59ad15acf9 100644 --- a/tests/resources/screenshot-override/override.css +++ b/tests/resources/screenshot-override/override.css @@ -48,9 +48,18 @@ body > .widget { display:none; } -html body div *, body * { +*, +*::after, +*::before { -webkit-transition: none !important; transition: none !important; -webkit-animation: none !important; animation: none !important; + transition-delay: 0s !important; + transition-duration: 0s !important; + animation-delay: -0.0001s !important; + animation-duration: 0s !important; + animation-play-state: paused !important; + caret-color: transparent !important; + color-adjust: exact !important; }
\ No newline at end of file diff --git a/tests/resources/screenshot-override/override.js b/tests/resources/screenshot-override/override.js index 37971a600b..5f142f3bbd 100644 --- a/tests/resources/screenshot-override/override.js +++ b/tests/resources/screenshot-override/override.js @@ -4,4 +4,18 @@ $(document).ready(function () { $('[notification-id=ControllerAdmin_HttpIsUsed]').hide(); $.fx.off = true; + + // disable materialize animations (Materialize version > 1) + if (typeof M !== 'undefined' && M.anime) { + var oldAnime = M.anime; + M.anime = function (params) { + if (!params) { + params = {}; + } + params.duration = 0; + return oldAnime(params); + }; + } else if ($.Velocity) { + $.Velocity.mock = true; + } });
\ No newline at end of file |