aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--application/front/controller/admin/PasswordController.php100
-rw-r--r--application/front/controller/admin/ShaarliAdminController.php59
-rw-r--r--application/front/controller/visitor/ShaarliVisitorController.php8
-rw-r--r--application/front/exceptions/OpenShaarliPasswordException.php18
-rw-r--r--application/front/exceptions/ShaarliFrontException.php4
-rw-r--r--application/front/exceptions/WrongTokenException.php18
-rw-r--r--application/render/PageBuilder.php26
-rw-r--r--application/security/SessionManager.php4
-rw-r--r--index.php54
-rw-r--r--tests/front/controller/admin/FrontAdminControllerMockHelper.php3
-rw-r--r--tests/front/controller/admin/LogoutControllerTest.php2
-rw-r--r--tests/front/controller/admin/PasswordControllerTest.php186
-rw-r--r--tests/front/controller/admin/SessionFilterControllerTest.php18
-rw-r--r--tests/front/controller/admin/ToolsControllerTest.php4
-rw-r--r--tests/front/controller/visitor/DailyControllerTest.php14
-rw-r--r--tests/front/controller/visitor/FeedControllerTest.php6
-rw-r--r--tests/front/controller/visitor/FrontControllerMockHelper.php8
-rw-r--r--tests/front/controller/visitor/LoginControllerTest.php10
-rw-r--r--tests/front/controller/visitor/OpenSearchControllerTest.php2
-rw-r--r--tests/front/controller/visitor/PictureWallControllerTest.php4
-rw-r--r--tests/front/controller/visitor/ShaarliPublicControllerTest.php18
-rw-r--r--tests/front/controller/visitor/TagCloudControllerTest.php12
-rw-r--r--tests/front/controller/visitor/TagControllerTest.php26
-rw-r--r--tpl/default/page.header.html28
24 files changed, 450 insertions, 182 deletions
diff --git a/application/front/controller/admin/PasswordController.php b/application/front/controller/admin/PasswordController.php
new file mode 100644
index 00000000..6e8f0bcb
--- /dev/null
+++ b/application/front/controller/admin/PasswordController.php
@@ -0,0 +1,100 @@
1<?php
2
3declare(strict_types=1);
4
5namespace Shaarli\Front\Controller\Admin;
6
7use Shaarli\Container\ShaarliContainer;
8use Shaarli\Front\Exception\OpenShaarliPasswordException;
9use Shaarli\Front\Exception\ShaarliFrontException;
10use Slim\Http\Request;
11use Slim\Http\Response;
12use Throwable;
13
14/**
15 * Class PasswordController
16 *
17 * Slim controller used to handle passwords update.
18 */
19class PasswordController extends ShaarliAdminController
20{
21 public function __construct(ShaarliContainer $container)
22 {
23 parent::__construct($container);
24
25 $this->assignView(
26 'pagetitle',
27 t('Change password') .' - '. $this->container->conf->get('general.title', 'Shaarli')
28 );
29 }
30
31 /**
32 * GET /password - Displays the change password template
33 */
34 public function index(Request $request, Response $response): Response
35 {
36 return $response->write($this->render('changepassword'));
37 }
38
39 /**
40 * POST /password - Change admin password - existing and new passwords need to be provided.
41 */
42 public function change(Request $request, Response $response): Response
43 {
44 $this->checkToken($request);
45
46 if ($this->container->conf->get('security.open_shaarli', false)) {
47 throw new OpenShaarliPasswordException();
48 }
49
50 $oldPassword = $request->getParam('oldpassword');
51 $newPassword = $request->getParam('setpassword');
52
53 if (empty($newPassword) || empty($oldPassword)) {
54 $this->saveErrorMessage(t('You must provide the current and new password to change it.'));
55
56 return $response
57 ->withStatus(400)
58 ->write($this->render('changepassword'))
59 ;
60 }
61
62 // Make sure old password is correct.
63 $oldHash = sha1(
64 $oldPassword .
65 $this->container->conf->get('credentials.login') .
66 $this->container->conf->get('credentials.salt')
67 );
68
69 if ($oldHash !== $this->container->conf->get('credentials.hash')) {
70 $this->saveErrorMessage(t('The old password is not correct.'));
71
72 return $response
73 ->withStatus(400)
74 ->write($this->render('changepassword'))
75 ;
76 }
77
78 // Save new password
79 // Salt renders rainbow-tables attacks useless.
80 $this->container->conf->set('credentials.salt', sha1(uniqid('', true) .'_'. mt_rand()));
81 $this->container->conf->set(
82 'credentials.hash',
83 sha1(
84 $newPassword
85 . $this->container->conf->get('credentials.login')
86 . $this->container->conf->get('credentials.salt')
87 )
88 );
89
90 try {
91 $this->container->conf->write($this->container->loginManager->isLoggedIn());
92 } catch (Throwable $e) {
93 throw new ShaarliFrontException($e->getMessage(), 500, $e);
94 }
95
96 $this->saveSuccessMessage(t('Your password has been changed'));
97
98 return $response->write($this->render('changepassword'));
99 }
100}
diff --git a/application/front/controller/admin/ShaarliAdminController.php b/application/front/controller/admin/ShaarliAdminController.php
index ea703f62..3385006c 100644
--- a/application/front/controller/admin/ShaarliAdminController.php
+++ b/application/front/controller/admin/ShaarliAdminController.php
@@ -7,7 +7,19 @@ namespace Shaarli\Front\Controller\Admin;
7use Shaarli\Container\ShaarliContainer; 7use Shaarli\Container\ShaarliContainer;
8use Shaarli\Front\Controller\Visitor\ShaarliVisitorController; 8use Shaarli\Front\Controller\Visitor\ShaarliVisitorController;
9use Shaarli\Front\Exception\UnauthorizedException; 9use Shaarli\Front\Exception\UnauthorizedException;
10use Shaarli\Front\Exception\WrongTokenException;
11use Shaarli\Security\SessionManager;
12use Slim\Http\Request;
10 13
14/**
15 * Class ShaarliAdminController
16 *
17 * All admin controllers (for logged in users) MUST extend this abstract class.
18 * It makes sure that the user is properly logged in, and otherwise throw an exception
19 * which will redirect to the login page.
20 *
21 * @package Shaarli\Front\Controller\Admin
22 */
11abstract class ShaarliAdminController extends ShaarliVisitorController 23abstract class ShaarliAdminController extends ShaarliVisitorController
12{ 24{
13 public function __construct(ShaarliContainer $container) 25 public function __construct(ShaarliContainer $container)
@@ -18,4 +30,51 @@ abstract class ShaarliAdminController extends ShaarliVisitorController
18 throw new UnauthorizedException(); 30 throw new UnauthorizedException();
19 } 31 }
20 } 32 }
33
34 /**
35 * Any persistent action to the config or data store must check the XSRF token validity.
36 */
37 protected function checkToken(Request $request): void
38 {
39 if (!$this->container->sessionManager->checkToken($request->getParam('token'))) {
40 throw new WrongTokenException();
41 }
42 }
43
44 /**
45 * Save a SUCCESS message in user session, which will be displayed on any template page.
46 */
47 protected function saveSuccessMessage(string $message): void
48 {
49 $this->saveMessage(SessionManager::KEY_SUCCESS_MESSAGES, $message);
50 }
51
52 /**
53 * Save a WARNING message in user session, which will be displayed on any template page.
54 */
55 protected function saveWarningMessage(string $message): void
56 {
57 $this->saveMessage(SessionManager::KEY_WARNING_MESSAGES, $message);
58 }
59
60 /**
61 * Save an ERROR message in user session, which will be displayed on any template page.
62 */
63 protected function saveErrorMessage(string $message): void
64 {
65 $this->saveMessage(SessionManager::KEY_ERROR_MESSAGES, $message);
66 }
67
68 /**
69 * Use the sessionManager to save the provided message using the proper type.
70 *
71 * @param string $type successed/warnings/errors
72 */
73 protected function saveMessage(string $type, string $message): void
74 {
75 $messages = $this->container->sessionManager->getSessionParameter($type) ?? [];
76 $messages[] = $message;
77
78 $this->container->sessionManager->setSessionParameter($type, $messages);
79 }
21} 80}
diff --git a/application/front/controller/visitor/ShaarliVisitorController.php b/application/front/controller/visitor/ShaarliVisitorController.php
index 655b3baa..f12915c1 100644
--- a/application/front/controller/visitor/ShaarliVisitorController.php
+++ b/application/front/controller/visitor/ShaarliVisitorController.php
@@ -9,6 +9,14 @@ use Shaarli\Container\ShaarliContainer;
9use Slim\Http\Request; 9use Slim\Http\Request;
10use Slim\Http\Response; 10use Slim\Http\Response;
11 11
12/**
13 * Class ShaarliVisitorController
14 *
15 * All controllers accessible by visitors (non logged in users) should extend this abstract class.
16 * Contains a few helper function for template rendering, plugins, etc.
17 *
18 * @package Shaarli\Front\Controller\Visitor
19 */
12abstract class ShaarliVisitorController 20abstract class ShaarliVisitorController
13{ 21{
14 /** @var ShaarliContainer */ 22 /** @var ShaarliContainer */
diff --git a/application/front/exceptions/OpenShaarliPasswordException.php b/application/front/exceptions/OpenShaarliPasswordException.php
new file mode 100644
index 00000000..a6f0b3ae
--- /dev/null
+++ b/application/front/exceptions/OpenShaarliPasswordException.php
@@ -0,0 +1,18 @@
1<?php
2
3declare(strict_types=1);
4
5namespace Shaarli\Front\Exception;
6
7/**
8 * Class OpenShaarliPasswordException
9 *
10 * Raised if the user tries to change the admin password on an open shaarli instance.
11 */
12class OpenShaarliPasswordException extends ShaarliFrontException
13{
14 public function __construct()
15 {
16 parent::__construct(t('You are not supposed to change a password on an Open Shaarli.'), 403);
17 }
18}
diff --git a/application/front/exceptions/ShaarliFrontException.php b/application/front/exceptions/ShaarliFrontException.php
index fc8eb92b..73847e6d 100644
--- a/application/front/exceptions/ShaarliFrontException.php
+++ b/application/front/exceptions/ShaarliFrontException.php
@@ -9,11 +9,11 @@ use Throwable;
9/** 9/**
10 * Class ShaarliException 10 * Class ShaarliException
11 * 11 *
12 * Abstract exception class used to defined any custom exception thrown during front rendering. 12 * Exception class used to defined any custom exception thrown during front rendering.
13 * 13 *
14 * @package Front\Exception 14 * @package Front\Exception
15 */ 15 */
16abstract class ShaarliFrontException extends \Exception 16class ShaarliFrontException extends \Exception
17{ 17{
18 /** Override parent constructor to force $message and $httpCode parameters to be set. */ 18 /** Override parent constructor to force $message and $httpCode parameters to be set. */
19 public function __construct(string $message, int $httpCode, Throwable $previous = null) 19 public function __construct(string $message, int $httpCode, Throwable $previous = null)
diff --git a/application/front/exceptions/WrongTokenException.php b/application/front/exceptions/WrongTokenException.php
new file mode 100644
index 00000000..42002720
--- /dev/null
+++ b/application/front/exceptions/WrongTokenException.php
@@ -0,0 +1,18 @@
1<?php
2
3declare(strict_types=1);
4
5namespace Shaarli\Front\Exception;
6
7/**
8 * Class OpenShaarliPasswordException
9 *
10 * Raised if the user tries to perform an action with an invalid XSRF token.
11 */
12class WrongTokenException extends ShaarliFrontException
13{
14 public function __construct()
15 {
16 parent::__construct(t('Wrong token.'), 403);
17 }
18}
diff --git a/application/render/PageBuilder.php b/application/render/PageBuilder.php
index f4fefda8..264cd33b 100644
--- a/application/render/PageBuilder.php
+++ b/application/render/PageBuilder.php
@@ -7,6 +7,7 @@ use RainTPL;
7use Shaarli\ApplicationUtils; 7use Shaarli\ApplicationUtils;
8use Shaarli\Bookmark\BookmarkServiceInterface; 8use Shaarli\Bookmark\BookmarkServiceInterface;
9use Shaarli\Config\ConfigManager; 9use Shaarli\Config\ConfigManager;
10use Shaarli\Security\SessionManager;
10use Shaarli\Thumbnailer; 11use Shaarli\Thumbnailer;
11 12
12/** 13/**
@@ -136,17 +137,28 @@ class PageBuilder
136 $this->tpl->assign('thumbnails_width', $this->conf->get('thumbnails.width')); 137 $this->tpl->assign('thumbnails_width', $this->conf->get('thumbnails.width'));
137 $this->tpl->assign('thumbnails_height', $this->conf->get('thumbnails.height')); 138 $this->tpl->assign('thumbnails_height', $this->conf->get('thumbnails.height'));
138 139
139 if (!empty($_SESSION['warnings'])) {
140 $this->tpl->assign('global_warnings', $_SESSION['warnings']);
141 unset($_SESSION['warnings']);
142 }
143
144 $this->tpl->assign('formatter', $this->conf->get('formatter', 'default')); 140 $this->tpl->assign('formatter', $this->conf->get('formatter', 'default'));
145 141
146 // To be removed with a proper theme configuration. 142 // To be removed with a proper theme configuration.
147 $this->tpl->assign('conf', $this->conf); 143 $this->tpl->assign('conf', $this->conf);
148 } 144 }
149 145
146 protected function finalize(): void
147 {
148 // TODO: use the SessionManager
149 $messageKeys = [
150 SessionManager::KEY_SUCCESS_MESSAGES,
151 SessionManager::KEY_WARNING_MESSAGES,
152 SessionManager::KEY_ERROR_MESSAGES
153 ];
154 foreach ($messageKeys as $messageKey) {
155 if (!empty($_SESSION[$messageKey])) {
156 $this->tpl->assign('global_' . $messageKey, $_SESSION[$messageKey]);
157 unset($_SESSION[$messageKey]);
158 }
159 }
160 }
161
150 /** 162 /**
151 * The following assign() method is basically the same as RainTPL (except lazy loading) 163 * The following assign() method is basically the same as RainTPL (except lazy loading)
152 * 164 *
@@ -196,6 +208,8 @@ class PageBuilder
196 $this->initialize(); 208 $this->initialize();
197 } 209 }
198 210
211 $this->finalize();
212
199 $this->tpl->draw($page); 213 $this->tpl->draw($page);
200 } 214 }
201 215
@@ -213,6 +227,8 @@ class PageBuilder
213 $this->initialize(); 227 $this->initialize();
214 } 228 }
215 229
230 $this->finalize();
231
216 return $this->tpl->draw($page, true); 232 return $this->tpl->draw($page, true);
217 } 233 }
218 234
diff --git a/application/security/SessionManager.php b/application/security/SessionManager.php
index 8b77d362..0ac17d9a 100644
--- a/application/security/SessionManager.php
+++ b/application/security/SessionManager.php
@@ -12,6 +12,10 @@ class SessionManager
12 public const KEY_VISIBILITY = 'visibility'; 12 public const KEY_VISIBILITY = 'visibility';
13 public const KEY_UNTAGGED_ONLY = 'untaggedonly'; 13 public const KEY_UNTAGGED_ONLY = 'untaggedonly';
14 14
15 public const KEY_SUCCESS_MESSAGES = 'successes';
16 public const KEY_WARNING_MESSAGES = 'warnings';
17 public const KEY_ERROR_MESSAGES = 'errors';
18
15 /** @var int Session expiration timeout, in seconds */ 19 /** @var int Session expiration timeout, in seconds */
16 public static $SHORT_TIMEOUT = 3600; // 1 hour 20 public static $SHORT_TIMEOUT = 3600; // 1 hour
17 21
diff --git a/index.php b/index.php
index f4c8b391..ae56b800 100644
--- a/index.php
+++ b/index.php
@@ -507,56 +507,8 @@ function renderPage($conf, $pluginManager, $bookmarkService, $history, $sessionM
507 507
508 // -------- User wants to change his/her password. 508 // -------- User wants to change his/her password.
509 if ($targetPage == Router::$PAGE_CHANGEPASSWORD) { 509 if ($targetPage == Router::$PAGE_CHANGEPASSWORD) {
510 if ($conf->get('security.open_shaarli')) { 510 header('Location: ./password');
511 die(t('You are not supposed to change a password on an Open Shaarli.')); 511 exit;
512 }
513
514 if (!empty($_POST['setpassword']) && !empty($_POST['oldpassword'])) {
515 if (!$sessionManager->checkToken($_POST['token'])) {
516 die(t('Wrong token.')); // Go away!
517 }
518
519 // Make sure old password is correct.
520 $oldhash = sha1(
521 $_POST['oldpassword'].$conf->get('credentials.login').$conf->get('credentials.salt')
522 );
523 if ($oldhash != $conf->get('credentials.hash')) {
524 echo '<script>alert("'
525 . t('The old password is not correct.')
526 .'");document.location=\'./?do=changepasswd\';</script>';
527 exit;
528 }
529 // Save new password
530 // Salt renders rainbow-tables attacks useless.
531 $conf->set('credentials.salt', sha1(uniqid('', true) .'_'. mt_rand()));
532 $conf->set(
533 'credentials.hash',
534 sha1(
535 $_POST['setpassword']
536 . $conf->get('credentials.login')
537 . $conf->get('credentials.salt')
538 )
539 );
540 try {
541 $conf->write($loginManager->isLoggedIn());
542 } catch (Exception $e) {
543 error_log(
544 'ERROR while writing config file after changing password.' . PHP_EOL .
545 $e->getMessage()
546 );
547
548 // TODO: do not handle exceptions/errors in JS.
549 echo '<script>alert("'. $e->getMessage() .'");document.location=\'./tools\';</script>';
550 exit;
551 }
552 echo '<script>alert("'. t('Your password has been changed') .'");document.location=\'./tools\';</script>';
553 exit;
554 } else {
555 // show the change password form.
556 $PAGE->assign('pagetitle', t('Change password') .' - '. $conf->get('general.title', 'Shaarli'));
557 $PAGE->renderPage('changepassword');
558 exit;
559 }
560 } 512 }
561 513
562 // -------- User wants to change configuration 514 // -------- User wants to change configuration
@@ -1504,6 +1456,8 @@ $app->group('', function () {
1504 /* -- LOGGED IN -- */ 1456 /* -- LOGGED IN -- */
1505 $this->get('/logout', '\Shaarli\Front\Controller\Admin\LogoutController:index')->setName('logout'); 1457 $this->get('/logout', '\Shaarli\Front\Controller\Admin\LogoutController:index')->setName('logout');
1506 $this->get('/tools', '\Shaarli\Front\Controller\Admin\ToolsController:index')->setName('tools'); 1458 $this->get('/tools', '\Shaarli\Front\Controller\Admin\ToolsController:index')->setName('tools');
1459 $this->get('/password', '\Shaarli\Front\Controller\Admin\PasswordController:index')->setName('password');
1460 $this->post('/password', '\Shaarli\Front\Controller\Admin\PasswordController:change')->setName('changePassword');
1507 1461
1508 $this 1462 $this
1509 ->get('/links-per-page', '\Shaarli\Front\Controller\Admin\SessionFilterController:linksPerPage') 1463 ->get('/links-per-page', '\Shaarli\Front\Controller\Admin\SessionFilterController:linksPerPage')
diff --git a/tests/front/controller/admin/FrontAdminControllerMockHelper.php b/tests/front/controller/admin/FrontAdminControllerMockHelper.php
index 94581c09..bd40c0c7 100644
--- a/tests/front/controller/admin/FrontAdminControllerMockHelper.php
+++ b/tests/front/controller/admin/FrontAdminControllerMockHelper.php
@@ -6,7 +6,6 @@ namespace Shaarli\Front\Controller\Admin;
6 6
7use Shaarli\Container\ShaarliTestContainer; 7use Shaarli\Container\ShaarliTestContainer;
8use Shaarli\Front\Controller\Visitor\FrontControllerMockHelper; 8use Shaarli\Front\Controller\Visitor\FrontControllerMockHelper;
9use Shaarli\Security\LoginManager;
10 9
11/** 10/**
12 * Trait FrontControllerMockHelper 11 * Trait FrontControllerMockHelper
@@ -28,7 +27,7 @@ trait FrontAdminControllerMockHelper
28 { 27 {
29 $this->parentCreateContainer(); 28 $this->parentCreateContainer();
30 29
31 $this->container->loginManager = $this->createMock(LoginManager::class);
32 $this->container->loginManager->method('isLoggedIn')->willReturn(true); 30 $this->container->loginManager->method('isLoggedIn')->willReturn(true);
31 $this->container->sessionManager->method('checkToken')->willReturn(true);
33 } 32 }
34} 33}
diff --git a/tests/front/controller/admin/LogoutControllerTest.php b/tests/front/controller/admin/LogoutControllerTest.php
index ba681b16..78a0fe73 100644
--- a/tests/front/controller/admin/LogoutControllerTest.php
+++ b/tests/front/controller/admin/LogoutControllerTest.php
@@ -35,8 +35,6 @@ class LogoutControllerTest extends TestCase
35 35
36 public function testValidControllerInvoke(): void 36 public function testValidControllerInvoke(): void
37 { 37 {
38 $this->createValidContainerMockSet();
39
40 $request = $this->createMock(Request::class); 38 $request = $this->createMock(Request::class);
41 $response = new Response(); 39 $response = new Response();
42 40
diff --git a/tests/front/controller/admin/PasswordControllerTest.php b/tests/front/controller/admin/PasswordControllerTest.php
new file mode 100644
index 00000000..7262243e
--- /dev/null
+++ b/tests/front/controller/admin/PasswordControllerTest.php
@@ -0,0 +1,186 @@
1<?php
2
3declare(strict_types=1);
4
5namespace Shaarli\Front\Controller\Admin;
6
7use PHPUnit\Framework\TestCase;
8use Shaarli\Config\ConfigManager;
9use Shaarli\Front\Exception\WrongTokenException;
10use Shaarli\Security\SessionManager;
11use Slim\Http\Request;
12use Slim\Http\Response;
13
14class PasswordControllerTest extends TestCase
15{
16 use FrontAdminControllerMockHelper;
17
18 /** @var PasswordController */
19 protected $controller;
20
21 /** @var mixed[] Variables assigned to the template */
22 protected $assignedVariables = [];
23
24 public function setUp(): void
25 {
26 $this->createContainer();
27 $this->assignTemplateVars($this->assignedVariables);
28
29 $this->controller = new PasswordController($this->container);
30 }
31
32 /**
33 * Test displaying the change password page.
34 */
35 public function testGetPage(): void
36 {
37 $request = $this->createMock(Request::class);
38 $response = new Response();
39
40 $result = $this->controller->index($request, $response);
41
42 static::assertSame(200, $result->getStatusCode());
43 static::assertSame('changepassword', (string) $result->getBody());
44 static::assertSame('Change password - Shaarli', $this->assignedVariables['pagetitle']);
45 }
46
47 /**
48 * Change the password with valid parameters
49 */
50 public function testPostNewPasswordDefault(): void
51 {
52 $request = $this->createMock(Request::class);
53 $request->method('getParam')->willReturnCallback(function (string $key): string {
54 if ('oldpassword' === $key) {
55 return 'old';
56 }
57 if ('setpassword' === $key) {
58 return 'new';
59 }
60
61 return $key;
62 });
63 $response = new Response();
64
65 $this->container->conf = $this->createMock(ConfigManager::class);
66 $this->container->conf->method('get')->willReturnCallback(function (string $key, $default) {
67 if ('credentials.hash' === $key) {
68 return sha1('old' . 'credentials.login' . 'credentials.salt');
69 }
70
71 return strpos($key, 'credentials') !== false ? $key : $default;
72 });
73 $this->container->conf->expects(static::once())->method('write')->with(true);
74
75 $this->container->conf
76 ->method('set')
77 ->willReturnCallback(function (string $key, string $value) {
78 if ('credentials.hash' === $key) {
79 static::assertSame(sha1('new' . 'credentials.login' . 'credentials.salt'), $value);
80 }
81 })
82 ;
83
84 $result = $this->controller->change($request, $response);
85
86 static::assertSame(200, $result->getStatusCode());
87 static::assertSame('changepassword', (string) $result->getBody());
88 static::assertSame('Change password - Shaarli', $this->assignedVariables['pagetitle']);
89 }
90
91 /**
92 * Change the password with a wrong existing password
93 */
94 public function testPostNewPasswordWrongOldPassword(): void
95 {
96 $request = $this->createMock(Request::class);
97 $request->method('getParam')->willReturnCallback(function (string $key): string {
98 if ('oldpassword' === $key) {
99 return 'wrong';
100 }
101 if ('setpassword' === $key) {
102 return 'new';
103 }
104
105 return $key;
106 });
107 $response = new Response();
108
109 $this->container->conf = $this->createMock(ConfigManager::class);
110 $this->container->conf->method('get')->willReturnCallback(function (string $key, $default) {
111 if ('credentials.hash' === $key) {
112 return sha1('old' . 'credentials.login' . 'credentials.salt');
113 }
114
115 return strpos($key, 'credentials') !== false ? $key : $default;
116 });
117
118 $this->container->conf->expects(static::never())->method('set');
119 $this->container->conf->expects(static::never())->method('write');
120
121 $this->container->sessionManager
122 ->expects(static::once())
123 ->method('setSessionParameter')
124 ->with(SessionManager::KEY_ERROR_MESSAGES, ['The old password is not correct.'])
125 ;
126
127 $result = $this->controller->change($request, $response);
128
129 static::assertSame(400, $result->getStatusCode());
130 static::assertSame('changepassword', (string) $result->getBody());
131 static::assertSame('Change password - Shaarli', $this->assignedVariables['pagetitle']);
132 }
133
134 /**
135 * Change the password with a wrong existing password
136 */
137 public function testPostNewPasswordWrongToken(): void
138 {
139 $this->container->sessionManager = $this->createMock(SessionManager::class);
140 $this->container->sessionManager->method('checkToken')->willReturn(false);
141
142 $this->container->conf->expects(static::never())->method('set');
143 $this->container->conf->expects(static::never())->method('write');
144
145 $request = $this->createMock(Request::class);
146 $response = new Response();
147
148 $this->expectException(WrongTokenException::class);
149
150 $this->controller->change($request, $response);
151 }
152
153 /**
154 * Change the password with an empty new password
155 */
156 public function testPostNewEmptyPassword(): void
157 {
158 $this->container->sessionManager
159 ->expects(static::once())
160 ->method('setSessionParameter')
161 ->with(SessionManager::KEY_ERROR_MESSAGES, ['You must provide the current and new password to change it.'])
162 ;
163
164 $this->container->conf->expects(static::never())->method('set');
165 $this->container->conf->expects(static::never())->method('write');
166
167 $request = $this->createMock(Request::class);
168 $request->method('getParam')->willReturnCallback(function (string $key): string {
169 if ('oldpassword' === $key) {
170 return 'old';
171 }
172 if ('setpassword' === $key) {
173 return '';
174 }
175
176 return $key;
177 });
178 $response = new Response();
179
180 $result = $this->controller->change($request, $response);
181
182 static::assertSame(400, $result->getStatusCode());
183 static::assertSame('changepassword', (string) $result->getBody());
184 static::assertSame('Change password - Shaarli', $this->assignedVariables['pagetitle']);
185 }
186}
diff --git a/tests/front/controller/admin/SessionFilterControllerTest.php b/tests/front/controller/admin/SessionFilterControllerTest.php
index f50f2fc2..096963cf 100644
--- a/tests/front/controller/admin/SessionFilterControllerTest.php
+++ b/tests/front/controller/admin/SessionFilterControllerTest.php
@@ -30,8 +30,6 @@ class SessionFilterControllerTest extends TestCase
30 */ 30 */
31 public function testLinksPerPage(): void 31 public function testLinksPerPage(): void
32 { 32 {
33 $this->createValidContainerMockSet();
34
35 $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc']; 33 $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc'];
36 34
37 $request = $this->createMock(Request::class); 35 $request = $this->createMock(Request::class);
@@ -62,8 +60,6 @@ class SessionFilterControllerTest extends TestCase
62 */ 60 */
63 public function testLinksPerPageNotValid(): void 61 public function testLinksPerPageNotValid(): void
64 { 62 {
65 $this->createValidContainerMockSet();
66
67 $request = $this->createMock(Request::class); 63 $request = $this->createMock(Request::class);
68 $request->method('getUri')->willReturnCallback(function (): Uri { 64 $request->method('getUri')->willReturnCallback(function (): Uri {
69 $uri = $this->createMock(Uri::class); 65 $uri = $this->createMock(Uri::class);
@@ -92,8 +88,6 @@ class SessionFilterControllerTest extends TestCase
92 */ 88 */
93 public function testVisibility(): void 89 public function testVisibility(): void
94 { 90 {
95 $this->createValidContainerMockSet();
96
97 $arg = ['visibility' => 'private']; 91 $arg = ['visibility' => 'private'];
98 92
99 $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc']; 93 $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc'];
@@ -126,8 +120,6 @@ class SessionFilterControllerTest extends TestCase
126 */ 120 */
127 public function testVisibilityToggleOff(): void 121 public function testVisibilityToggleOff(): void
128 { 122 {
129 $this->createValidContainerMockSet();
130
131 $arg = ['visibility' => 'private']; 123 $arg = ['visibility' => 'private'];
132 124
133 $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc']; 125 $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc'];
@@ -169,8 +161,6 @@ class SessionFilterControllerTest extends TestCase
169 */ 161 */
170 public function testVisibilitySwitch(): void 162 public function testVisibilitySwitch(): void
171 { 163 {
172 $this->createValidContainerMockSet();
173
174 $arg = ['visibility' => 'private']; 164 $arg = ['visibility' => 'private'];
175 165
176 $this->container->loginManager->method('isLoggedIn')->willReturn(true); 166 $this->container->loginManager->method('isLoggedIn')->willReturn(true);
@@ -206,8 +196,6 @@ class SessionFilterControllerTest extends TestCase
206 */ 196 */
207 public function testVisibilityInvalidValue(): void 197 public function testVisibilityInvalidValue(): void
208 { 198 {
209 $this->createValidContainerMockSet();
210
211 $arg = ['visibility' => 'test']; 199 $arg = ['visibility' => 'test'];
212 200
213 $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc']; 201 $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc'];
@@ -244,8 +232,6 @@ class SessionFilterControllerTest extends TestCase
244 */ 232 */
245 public function testVisibilityLoggedOut(): void 233 public function testVisibilityLoggedOut(): void
246 { 234 {
247 $this->createValidContainerMockSet();
248
249 $arg = ['visibility' => 'test']; 235 $arg = ['visibility' => 'test'];
250 236
251 $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc']; 237 $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc'];
@@ -283,8 +269,6 @@ class SessionFilterControllerTest extends TestCase
283 */ 269 */
284 public function testUntaggedOnly(): void 270 public function testUntaggedOnly(): void
285 { 271 {
286 $this->createValidContainerMockSet();
287
288 $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc']; 272 $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc'];
289 273
290 $request = $this->createMock(Request::class); 274 $request = $this->createMock(Request::class);
@@ -314,8 +298,6 @@ class SessionFilterControllerTest extends TestCase
314 */ 298 */
315 public function testUntaggedOnlyToggleOff(): void 299 public function testUntaggedOnlyToggleOff(): void
316 { 300 {
317 $this->createValidContainerMockSet();
318
319 $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc']; 301 $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc'];
320 302
321 $request = $this->createMock(Request::class); 303 $request = $this->createMock(Request::class);
diff --git a/tests/front/controller/admin/ToolsControllerTest.php b/tests/front/controller/admin/ToolsControllerTest.php
index 47c5746e..fc756f0f 100644
--- a/tests/front/controller/admin/ToolsControllerTest.php
+++ b/tests/front/controller/admin/ToolsControllerTest.php
@@ -24,8 +24,6 @@ class ToolsControllerTestControllerTest extends TestCase
24 24
25 public function testDefaultInvokeWithHttps(): void 25 public function testDefaultInvokeWithHttps(): void
26 { 26 {
27 $this->createValidContainerMockSet();
28
29 $request = $this->createMock(Request::class); 27 $request = $this->createMock(Request::class);
30 $response = new Response(); 28 $response = new Response();
31 29
@@ -49,8 +47,6 @@ class ToolsControllerTestControllerTest extends TestCase
49 47
50 public function testDefaultInvokeWithoutHttps(): void 48 public function testDefaultInvokeWithoutHttps(): void
51 { 49 {
52 $this->createValidContainerMockSet();
53
54 $request = $this->createMock(Request::class); 50 $request = $this->createMock(Request::class);
55 $response = new Response(); 51 $response = new Response();
56 52
diff --git a/tests/front/controller/visitor/DailyControllerTest.php b/tests/front/controller/visitor/DailyControllerTest.php
index 6ff769fc..872420fd 100644
--- a/tests/front/controller/visitor/DailyControllerTest.php
+++ b/tests/front/controller/visitor/DailyControllerTest.php
@@ -27,8 +27,6 @@ class DailyControllerTest extends TestCase
27 27
28 public function testValidIndexControllerInvokeDefault(): void 28 public function testValidIndexControllerInvokeDefault(): void
29 { 29 {
30 $this->createValidContainerMockSet();
31
32 $currentDay = new \DateTimeImmutable('2020-05-13'); 30 $currentDay = new \DateTimeImmutable('2020-05-13');
33 31
34 $request = $this->createMock(Request::class); 32 $request = $this->createMock(Request::class);
@@ -169,8 +167,6 @@ class DailyControllerTest extends TestCase
169 */ 167 */
170 public function testValidIndexControllerInvokeNoFutureOrPast(): void 168 public function testValidIndexControllerInvokeNoFutureOrPast(): void
171 { 169 {
172 $this->createValidContainerMockSet();
173
174 $currentDay = new \DateTimeImmutable('2020-05-13'); 170 $currentDay = new \DateTimeImmutable('2020-05-13');
175 171
176 $request = $this->createMock(Request::class); 172 $request = $this->createMock(Request::class);
@@ -243,8 +239,6 @@ class DailyControllerTest extends TestCase
243 */ 239 */
244 public function testValidIndexControllerInvokeHeightAdjustment(): void 240 public function testValidIndexControllerInvokeHeightAdjustment(): void
245 { 241 {
246 $this->createValidContainerMockSet();
247
248 $currentDay = new \DateTimeImmutable('2020-05-13'); 242 $currentDay = new \DateTimeImmutable('2020-05-13');
249 243
250 $request = $this->createMock(Request::class); 244 $request = $this->createMock(Request::class);
@@ -314,8 +308,6 @@ class DailyControllerTest extends TestCase
314 */ 308 */
315 public function testValidIndexControllerInvokeNoBookmark(): void 309 public function testValidIndexControllerInvokeNoBookmark(): void
316 { 310 {
317 $this->createValidContainerMockSet();
318
319 $request = $this->createMock(Request::class); 311 $request = $this->createMock(Request::class);
320 $response = new Response(); 312 $response = new Response();
321 313
@@ -363,8 +355,6 @@ class DailyControllerTest extends TestCase
363 */ 355 */
364 public function testValidRssControllerInvokeDefault(): void 356 public function testValidRssControllerInvokeDefault(): void
365 { 357 {
366 $this->createValidContainerMockSet();
367
368 $dates = [ 358 $dates = [
369 new \DateTimeImmutable('2020-05-17'), 359 new \DateTimeImmutable('2020-05-17'),
370 new \DateTimeImmutable('2020-05-15'), 360 new \DateTimeImmutable('2020-05-15'),
@@ -439,8 +429,6 @@ class DailyControllerTest extends TestCase
439 */ 429 */
440 public function testValidRssControllerInvokeTriggerCache(): void 430 public function testValidRssControllerInvokeTriggerCache(): void
441 { 431 {
442 $this->createValidContainerMockSet();
443
444 $request = $this->createMock(Request::class); 432 $request = $this->createMock(Request::class);
445 $response = new Response(); 433 $response = new Response();
446 434
@@ -465,8 +453,6 @@ class DailyControllerTest extends TestCase
465 */ 453 */
466 public function testValidRssControllerInvokeNoBookmark(): void 454 public function testValidRssControllerInvokeNoBookmark(): void
467 { 455 {
468 $this->createValidContainerMockSet();
469
470 $request = $this->createMock(Request::class); 456 $request = $this->createMock(Request::class);
471 $response = new Response(); 457 $response = new Response();
472 458
diff --git a/tests/front/controller/visitor/FeedControllerTest.php b/tests/front/controller/visitor/FeedControllerTest.php
index fd4679ea..fb417e2a 100644
--- a/tests/front/controller/visitor/FeedControllerTest.php
+++ b/tests/front/controller/visitor/FeedControllerTest.php
@@ -30,8 +30,6 @@ class FeedControllerTest extends TestCase
30 */ 30 */
31 public function testDefaultRssController(): void 31 public function testDefaultRssController(): void
32 { 32 {
33 $this->createValidContainerMockSet();
34
35 $request = $this->createMock(Request::class); 33 $request = $this->createMock(Request::class);
36 $response = new Response(); 34 $response = new Response();
37 35
@@ -71,8 +69,6 @@ class FeedControllerTest extends TestCase
71 */ 69 */
72 public function testDefaultAtomController(): void 70 public function testDefaultAtomController(): void
73 { 71 {
74 $this->createValidContainerMockSet();
75
76 $request = $this->createMock(Request::class); 72 $request = $this->createMock(Request::class);
77 $response = new Response(); 73 $response = new Response();
78 74
@@ -112,8 +108,6 @@ class FeedControllerTest extends TestCase
112 */ 108 */
113 public function testAtomControllerWithParameters(): void 109 public function testAtomControllerWithParameters(): void
114 { 110 {
115 $this->createValidContainerMockSet();
116
117 $request = $this->createMock(Request::class); 111 $request = $this->createMock(Request::class);
118 $request->method('getParams')->willReturn(['parameter' => 'value']); 112 $request->method('getParams')->willReturn(['parameter' => 'value']);
119 $response = new Response(); 113 $response = new Response();
diff --git a/tests/front/controller/visitor/FrontControllerMockHelper.php b/tests/front/controller/visitor/FrontControllerMockHelper.php
index bc3266b5..d16b6949 100644
--- a/tests/front/controller/visitor/FrontControllerMockHelper.php
+++ b/tests/front/controller/visitor/FrontControllerMockHelper.php
@@ -31,18 +31,12 @@ trait FrontControllerMockHelper
31 protected $container; 31 protected $container;
32 32
33 /** 33 /**
34 * Mock the container instance 34 * Mock the container instance and initialize container's services used by tests
35 */ 35 */
36 protected function createContainer(): void 36 protected function createContainer(): void
37 { 37 {
38 $this->container = $this->createMock(ShaarliTestContainer::class); 38 $this->container = $this->createMock(ShaarliTestContainer::class);
39 }
40 39
41 /**
42 * Initialize container's services used by tests
43 */
44 protected function createValidContainerMockSet(): void
45 {
46 $this->container->loginManager = $this->createMock(LoginManager::class); 40 $this->container->loginManager = $this->createMock(LoginManager::class);
47 41
48 // Config 42 // Config
diff --git a/tests/front/controller/visitor/LoginControllerTest.php b/tests/front/controller/visitor/LoginControllerTest.php
index 9d223316..faa8ac71 100644
--- a/tests/front/controller/visitor/LoginControllerTest.php
+++ b/tests/front/controller/visitor/LoginControllerTest.php
@@ -26,8 +26,6 @@ class LoginControllerTest extends TestCase
26 26
27 public function testValidControllerInvoke(): void 27 public function testValidControllerInvoke(): void
28 { 28 {
29 $this->createValidContainerMockSet();
30
31 $request = $this->createMock(Request::class); 29 $request = $this->createMock(Request::class);
32 $request->expects(static::once())->method('getServerParam')->willReturn('> referer'); 30 $request->expects(static::once())->method('getServerParam')->willReturn('> referer');
33 $response = new Response(); 31 $response = new Response();
@@ -57,8 +55,6 @@ class LoginControllerTest extends TestCase
57 55
58 public function testValidControllerInvokeWithUserName(): void 56 public function testValidControllerInvokeWithUserName(): void
59 { 57 {
60 $this->createValidContainerMockSet();
61
62 $request = $this->createMock(Request::class); 58 $request = $this->createMock(Request::class);
63 $request->expects(static::once())->method('getServerParam')->willReturn('> referer'); 59 $request->expects(static::once())->method('getServerParam')->willReturn('> referer');
64 $request->expects(static::exactly(2))->method('getParam')->willReturn('myUser>'); 60 $request->expects(static::exactly(2))->method('getParam')->willReturn('myUser>');
@@ -90,8 +86,6 @@ class LoginControllerTest extends TestCase
90 86
91 public function testLoginControllerWhileLoggedIn(): void 87 public function testLoginControllerWhileLoggedIn(): void
92 { 88 {
93 $this->createValidContainerMockSet();
94
95 $request = $this->createMock(Request::class); 89 $request = $this->createMock(Request::class);
96 $response = new Response(); 90 $response = new Response();
97 91
@@ -106,8 +100,6 @@ class LoginControllerTest extends TestCase
106 100
107 public function testLoginControllerOpenShaarli(): void 101 public function testLoginControllerOpenShaarli(): void
108 { 102 {
109 $this->createValidContainerMockSet();
110
111 $request = $this->createMock(Request::class); 103 $request = $this->createMock(Request::class);
112 $response = new Response(); 104 $response = new Response();
113 105
@@ -129,8 +121,6 @@ class LoginControllerTest extends TestCase
129 121
130 public function testLoginControllerWhileBanned(): void 122 public function testLoginControllerWhileBanned(): void
131 { 123 {
132 $this->createValidContainerMockSet();
133
134 $request = $this->createMock(Request::class); 124 $request = $this->createMock(Request::class);
135 $response = new Response(); 125 $response = new Response();
136 126
diff --git a/tests/front/controller/visitor/OpenSearchControllerTest.php b/tests/front/controller/visitor/OpenSearchControllerTest.php
index 52475318..5f9f5b12 100644
--- a/tests/front/controller/visitor/OpenSearchControllerTest.php
+++ b/tests/front/controller/visitor/OpenSearchControllerTest.php
@@ -24,8 +24,6 @@ class OpenSearchControllerTest extends TestCase
24 24
25 public function testOpenSearchController(): void 25 public function testOpenSearchController(): void
26 { 26 {
27 $this->createValidContainerMockSet();
28
29 $request = $this->createMock(Request::class); 27 $request = $this->createMock(Request::class);
30 $response = new Response(); 28 $response = new Response();
31 29
diff --git a/tests/front/controller/visitor/PictureWallControllerTest.php b/tests/front/controller/visitor/PictureWallControllerTest.php
index 7ac842cb..3dc3f292 100644
--- a/tests/front/controller/visitor/PictureWallControllerTest.php
+++ b/tests/front/controller/visitor/PictureWallControllerTest.php
@@ -28,8 +28,6 @@ class PictureWallControllerTest extends TestCase
28 28
29 public function testValidControllerInvokeDefault(): void 29 public function testValidControllerInvokeDefault(): void
30 { 30 {
31 $this->createValidContainerMockSet();
32
33 $request = $this->createMock(Request::class); 31 $request = $this->createMock(Request::class);
34 $request->expects(static::once())->method('getQueryParams')->willReturn([]); 32 $request->expects(static::once())->method('getQueryParams')->willReturn([]);
35 $response = new Response(); 33 $response = new Response();
@@ -106,8 +104,6 @@ class PictureWallControllerTest extends TestCase
106 { 104 {
107 $this->expectException(ThumbnailsDisabledException::class); 105 $this->expectException(ThumbnailsDisabledException::class);
108 106
109 $this->createValidContainerMockSet();
110
111 $request = $this->createMock(Request::class); 107 $request = $this->createMock(Request::class);
112 $response = new Response(); 108 $response = new Response();
113 109
diff --git a/tests/front/controller/visitor/ShaarliPublicControllerTest.php b/tests/front/controller/visitor/ShaarliPublicControllerTest.php
index e2e88da3..1f7d57ad 100644
--- a/tests/front/controller/visitor/ShaarliPublicControllerTest.php
+++ b/tests/front/controller/visitor/ShaarliPublicControllerTest.php
@@ -67,8 +67,6 @@ class ShaarliControllerTest extends TestCase
67 67
68 public function testAssignView(): void 68 public function testAssignView(): void
69 { 69 {
70 $this->createValidContainerMockSet();
71
72 $this->assignTemplateVars($this->assignedValues); 70 $this->assignTemplateVars($this->assignedValues);
73 71
74 $self = $this->controller->assignView('variableName', 'variableValue'); 72 $self = $this->controller->assignView('variableName', 'variableValue');
@@ -79,8 +77,6 @@ class ShaarliControllerTest extends TestCase
79 77
80 public function testRender(): void 78 public function testRender(): void
81 { 79 {
82 $this->createValidContainerMockSet();
83
84 $this->assignTemplateVars($this->assignedValues); 80 $this->assignTemplateVars($this->assignedValues);
85 81
86 $this->container->bookmarkService 82 $this->container->bookmarkService
@@ -120,8 +116,6 @@ class ShaarliControllerTest extends TestCase
120 */ 116 */
121 public function testRedirectFromRefererDefault(): void 117 public function testRedirectFromRefererDefault(): void
122 { 118 {
123 $this->createValidContainerMockSet();
124
125 $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2'; 119 $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2';
126 120
127 $response = new Response(); 121 $response = new Response();
@@ -137,8 +131,6 @@ class ShaarliControllerTest extends TestCase
137 */ 131 */
138 public function testRedirectFromRefererWithUnmatchedLoopTerm(): void 132 public function testRedirectFromRefererWithUnmatchedLoopTerm(): void
139 { 133 {
140 $this->createValidContainerMockSet();
141
142 $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2'; 134 $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2';
143 135
144 $response = new Response(); 136 $response = new Response();
@@ -154,8 +146,6 @@ class ShaarliControllerTest extends TestCase
154 */ 146 */
155 public function testRedirectFromRefererWithMatchingLoopTermInPath(): void 147 public function testRedirectFromRefererWithMatchingLoopTermInPath(): void
156 { 148 {
157 $this->createValidContainerMockSet();
158
159 $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2'; 149 $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2';
160 150
161 $response = new Response(); 151 $response = new Response();
@@ -171,8 +161,6 @@ class ShaarliControllerTest extends TestCase
171 */ 161 */
172 public function testRedirectFromRefererWithMatchingLoopTermInQueryParam(): void 162 public function testRedirectFromRefererWithMatchingLoopTermInQueryParam(): void
173 { 163 {
174 $this->createValidContainerMockSet();
175
176 $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2'; 164 $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2';
177 165
178 $response = new Response(); 166 $response = new Response();
@@ -189,8 +177,6 @@ class ShaarliControllerTest extends TestCase
189 */ 177 */
190 public function testRedirectFromRefererWithMatchingLoopTermInQueryValue(): void 178 public function testRedirectFromRefererWithMatchingLoopTermInQueryValue(): void
191 { 179 {
192 $this->createValidContainerMockSet();
193
194 $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2'; 180 $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2';
195 181
196 $response = new Response(); 182 $response = new Response();
@@ -207,8 +193,6 @@ class ShaarliControllerTest extends TestCase
207 */ 193 */
208 public function testRedirectFromRefererWithLoopTermInDomain(): void 194 public function testRedirectFromRefererWithLoopTermInDomain(): void
209 { 195 {
210 $this->createValidContainerMockSet();
211
212 $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2'; 196 $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2';
213 197
214 $response = new Response(); 198 $response = new Response();
@@ -225,8 +209,6 @@ class ShaarliControllerTest extends TestCase
225 */ 209 */
226 public function testRedirectFromRefererWithMatchingClearedParam(): void 210 public function testRedirectFromRefererWithMatchingClearedParam(): void
227 { 211 {
228 $this->createValidContainerMockSet();
229
230 $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2'; 212 $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2';
231 213
232 $response = new Response(); 214 $response = new Response();
diff --git a/tests/front/controller/visitor/TagCloudControllerTest.php b/tests/front/controller/visitor/TagCloudControllerTest.php
index e636d496..9a6a4bc0 100644
--- a/tests/front/controller/visitor/TagCloudControllerTest.php
+++ b/tests/front/controller/visitor/TagCloudControllerTest.php
@@ -28,8 +28,6 @@ class TagCloudControllerTest extends TestCase
28 */ 28 */
29 public function testValidCloudControllerInvokeDefault(): void 29 public function testValidCloudControllerInvokeDefault(): void
30 { 30 {
31 $this->createValidContainerMockSet();
32
33 $allTags = [ 31 $allTags = [
34 'ghi' => 1, 32 'ghi' => 1,
35 'abc' => 3, 33 'abc' => 3,
@@ -94,8 +92,6 @@ class TagCloudControllerTest extends TestCase
94 */ 92 */
95 public function testValidCloudControllerInvokeWithParameters(): void 93 public function testValidCloudControllerInvokeWithParameters(): void
96 { 94 {
97 $this->createValidContainerMockSet();
98
99 $request = $this->createMock(Request::class); 95 $request = $this->createMock(Request::class);
100 $request 96 $request
101 ->method('getQueryParam') 97 ->method('getQueryParam')
@@ -161,8 +157,6 @@ class TagCloudControllerTest extends TestCase
161 */ 157 */
162 public function testEmptyCloud(): void 158 public function testEmptyCloud(): void
163 { 159 {
164 $this->createValidContainerMockSet();
165
166 $request = $this->createMock(Request::class); 160 $request = $this->createMock(Request::class);
167 $response = new Response(); 161 $response = new Response();
168 162
@@ -209,8 +203,6 @@ class TagCloudControllerTest extends TestCase
209 */ 203 */
210 public function testValidListControllerInvokeDefault(): void 204 public function testValidListControllerInvokeDefault(): void
211 { 205 {
212 $this->createValidContainerMockSet();
213
214 $allTags = [ 206 $allTags = [
215 'def' => 12, 207 'def' => 12,
216 'abc' => 3, 208 'abc' => 3,
@@ -271,8 +263,6 @@ class TagCloudControllerTest extends TestCase
271 */ 263 */
272 public function testValidListControllerInvokeWithParameters(): void 264 public function testValidListControllerInvokeWithParameters(): void
273 { 265 {
274 $this->createValidContainerMockSet();
275
276 $request = $this->createMock(Request::class); 266 $request = $this->createMock(Request::class);
277 $request 267 $request
278 ->method('getQueryParam') 268 ->method('getQueryParam')
@@ -336,8 +326,6 @@ class TagCloudControllerTest extends TestCase
336 */ 326 */
337 public function testEmptyList(): void 327 public function testEmptyList(): void
338 { 328 {
339 $this->createValidContainerMockSet();
340
341 $request = $this->createMock(Request::class); 329 $request = $this->createMock(Request::class);
342 $response = new Response(); 330 $response = new Response();
343 331
diff --git a/tests/front/controller/visitor/TagControllerTest.php b/tests/front/controller/visitor/TagControllerTest.php
index 9a2b1f71..1242a2e9 100644
--- a/tests/front/controller/visitor/TagControllerTest.php
+++ b/tests/front/controller/visitor/TagControllerTest.php
@@ -23,8 +23,6 @@ class TagControllerTest extends TestCase
23 23
24 public function testAddTagWithReferer(): void 24 public function testAddTagWithReferer(): void
25 { 25 {
26 $this->createValidContainerMockSet();
27
28 $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/']; 26 $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/'];
29 27
30 $request = $this->createMock(Request::class); 28 $request = $this->createMock(Request::class);
@@ -41,8 +39,6 @@ class TagControllerTest extends TestCase
41 39
42 public function testAddTagWithRefererAndExistingSearch(): void 40 public function testAddTagWithRefererAndExistingSearch(): void
43 { 41 {
44 $this->createValidContainerMockSet();
45
46 $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtags=def']; 42 $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtags=def'];
47 43
48 $request = $this->createMock(Request::class); 44 $request = $this->createMock(Request::class);
@@ -59,8 +55,6 @@ class TagControllerTest extends TestCase
59 55
60 public function testAddTagWithoutRefererAndExistingSearch(): void 56 public function testAddTagWithoutRefererAndExistingSearch(): void
61 { 57 {
62 $this->createValidContainerMockSet();
63
64 $request = $this->createMock(Request::class); 58 $request = $this->createMock(Request::class);
65 $response = new Response(); 59 $response = new Response();
66 60
@@ -75,8 +69,6 @@ class TagControllerTest extends TestCase
75 69
76 public function testAddTagRemoveLegacyQueryParam(): void 70 public function testAddTagRemoveLegacyQueryParam(): void
77 { 71 {
78 $this->createValidContainerMockSet();
79
80 $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtags=def&addtag=abc']; 72 $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtags=def&addtag=abc'];
81 73
82 $request = $this->createMock(Request::class); 74 $request = $this->createMock(Request::class);
@@ -93,8 +85,6 @@ class TagControllerTest extends TestCase
93 85
94 public function testAddTagResetPagination(): void 86 public function testAddTagResetPagination(): void
95 { 87 {
96 $this->createValidContainerMockSet();
97
98 $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtags=def&page=12']; 88 $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtags=def&page=12'];
99 89
100 $request = $this->createMock(Request::class); 90 $request = $this->createMock(Request::class);
@@ -111,8 +101,6 @@ class TagControllerTest extends TestCase
111 101
112 public function testAddTagWithRefererAndEmptySearch(): void 102 public function testAddTagWithRefererAndEmptySearch(): void
113 { 103 {
114 $this->createValidContainerMockSet();
115
116 $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtags=']; 104 $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtags='];
117 105
118 $request = $this->createMock(Request::class); 106 $request = $this->createMock(Request::class);
@@ -129,8 +117,6 @@ class TagControllerTest extends TestCase
129 117
130 public function testAddTagWithoutNewTagWithReferer(): void 118 public function testAddTagWithoutNewTagWithReferer(): void
131 { 119 {
132 $this->createValidContainerMockSet();
133
134 $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtags=def']; 120 $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtags=def'];
135 121
136 $request = $this->createMock(Request::class); 122 $request = $this->createMock(Request::class);
@@ -145,8 +131,6 @@ class TagControllerTest extends TestCase
145 131
146 public function testAddTagWithoutNewTagWithoutReferer(): void 132 public function testAddTagWithoutNewTagWithoutReferer(): void
147 { 133 {
148 $this->createValidContainerMockSet();
149
150 $request = $this->createMock(Request::class); 134 $request = $this->createMock(Request::class);
151 $response = new Response(); 135 $response = new Response();
152 136
@@ -159,8 +143,6 @@ class TagControllerTest extends TestCase
159 143
160 public function testRemoveTagWithoutMatchingTag(): void 144 public function testRemoveTagWithoutMatchingTag(): void
161 { 145 {
162 $this->createValidContainerMockSet();
163
164 $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtags=def']; 146 $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtags=def'];
165 147
166 $request = $this->createMock(Request::class); 148 $request = $this->createMock(Request::class);
@@ -177,8 +159,6 @@ class TagControllerTest extends TestCase
177 159
178 public function testRemoveTagWithoutTagsearch(): void 160 public function testRemoveTagWithoutTagsearch(): void
179 { 161 {
180 $this->createValidContainerMockSet();
181
182 $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/']; 162 $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/'];
183 163
184 $request = $this->createMock(Request::class); 164 $request = $this->createMock(Request::class);
@@ -195,8 +175,6 @@ class TagControllerTest extends TestCase
195 175
196 public function testRemoveTagWithoutReferer(): void 176 public function testRemoveTagWithoutReferer(): void
197 { 177 {
198 $this->createValidContainerMockSet();
199
200 $request = $this->createMock(Request::class); 178 $request = $this->createMock(Request::class);
201 $response = new Response(); 179 $response = new Response();
202 180
@@ -211,8 +189,6 @@ class TagControllerTest extends TestCase
211 189
212 public function testRemoveTagWithoutTag(): void 190 public function testRemoveTagWithoutTag(): void
213 { 191 {
214 $this->createValidContainerMockSet();
215
216 $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtag=abc']; 192 $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/controller/?searchtag=abc'];
217 193
218 $request = $this->createMock(Request::class); 194 $request = $this->createMock(Request::class);
@@ -227,8 +203,6 @@ class TagControllerTest extends TestCase
227 203
228 public function testRemoveTagWithoutTagWithoutReferer(): void 204 public function testRemoveTagWithoutTagWithoutReferer(): void
229 { 205 {
230 $this->createValidContainerMockSet();
231
232 $request = $this->createMock(Request::class); 206 $request = $this->createMock(Request::class);
233 $response = new Response(); 207 $response = new Response();
234 208
diff --git a/tpl/default/page.header.html b/tpl/default/page.header.html
index ca7dc1bc..4afcca73 100644
--- a/tpl/default/page.header.html
+++ b/tpl/default/page.header.html
@@ -184,6 +184,20 @@
184 </div> 184 </div>
185{/if} 185{/if}
186 186
187{if="!empty($global_errors) && $is_logged_in"}
188 <div class="pure-g new-version-message pure-alert pure-alert-error pure-alert-closable" id="shaarli-errors-alert">
189 <div class="pure-u-2-24"></div>
190 <div class="pure-u-20-24">
191 {loop="$global_errors"}
192 <p>{$value}</p>
193 {/loop}
194 </div>
195 <div class="pure-u-2-24">
196 <i class="fa fa-times pure-alert-close"></i>
197 </div>
198 </div>
199{/if}
200
187{if="!empty($global_warnings) && $is_logged_in"} 201{if="!empty($global_warnings) && $is_logged_in"}
188 <div class="pure-g pure-alert pure-alert-warning pure-alert-closable" id="shaarli-warnings-alert"> 202 <div class="pure-g pure-alert pure-alert-warning pure-alert-closable" id="shaarli-warnings-alert">
189 <div class="pure-u-2-24"></div> 203 <div class="pure-u-2-24"></div>
@@ -198,4 +212,18 @@
198 </div> 212 </div>
199{/if} 213{/if}
200 214
215{if="!empty($global_successes) && $is_logged_in"}
216 <div class="pure-g new-version-message pure-alert pure-alert-success pure-alert-closable" id="shaarli-success-alert">
217 <div class="pure-u-2-24"></div>
218 <div class="pure-u-20-24">
219 {loop="$global_successes"}
220 <p>{$value}</p>
221 {/loop}
222 </div>
223 <div class="pure-u-2-24">
224 <i class="fa fa-times pure-alert-close"></i>
225 </div>
226 </div>
227{/if}
228
201 <div class="clear"></div> 229 <div class="clear"></div>