aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--.github/mailmap1
-rw-r--r--.htaccess4
-rw-r--r--AUTHORS12
-rw-r--r--CHANGELOG.md20
-rw-r--r--Makefile4
-rw-r--r--application/api/ApiMiddleware.php10
-rw-r--r--application/bookmark/LinkUtils.php2
-rw-r--r--application/front/controller/admin/ManageShaareController.php4
-rw-r--r--doc/md/dev/Unit-tests.md15
-rw-r--r--tests/api/ApiMiddlewareTest.php47
-rw-r--r--tests/bookmark/LinkUtilsTest.php13
-rw-r--r--tests/front/controller/admin/ManageShaareControllerTest/SaveBookmarkTest.php24
12 files changed, 131 insertions, 25 deletions
diff --git a/.github/mailmap b/.github/mailmap
index 366946e8..15a25e43 100644
--- a/.github/mailmap
+++ b/.github/mailmap
@@ -3,6 +3,7 @@ ArthurHoaro <arthur@hoa.ro> Arthur
3Florian Eula <eula.florian@gmail.com> feula 3Florian Eula <eula.florian@gmail.com> feula
4Florian Eula <eula.florian@gmail.com> <mr.pikzen@gmail.com> 4Florian Eula <eula.florian@gmail.com> <mr.pikzen@gmail.com>
5Immánuel Fodor <immanuelfactor+github@gmail.com> 5Immánuel Fodor <immanuelfactor+github@gmail.com>
6Immánuel Fodor <immanuelfactor+github@gmail.com> Immánuel! <21174107+immanuelfodor@users.noreply.github.com>
6kalvn <kalvnthereal@gmail.com> <kalvn@users.noreply.github.com> 7kalvn <kalvnthereal@gmail.com> <kalvn@users.noreply.github.com>
7kalvn <kalvnthereal@gmail.com> <kalvn@pm.me> 8kalvn <kalvnthereal@gmail.com> <kalvn@pm.me>
8Neros <contact@neros.fr> <NerosTie@users.noreply.github.com> 9Neros <contact@neros.fr> <NerosTie@users.noreply.github.com>
diff --git a/.htaccess b/.htaccess
index af2dc5a7..25fcfb03 100644
--- a/.htaccess
+++ b/.htaccess
@@ -10,8 +10,12 @@ RewriteRule ^(.git|doxygen|vendor) - [F]
10# fixes JWT token not correctly forwarded on some Apache/FastCGI setups 10# fixes JWT token not correctly forwarded on some Apache/FastCGI setups
11RewriteCond %{HTTP:Authorization} ^(.*) 11RewriteCond %{HTTP:Authorization} ^(.*)
12RewriteRule .* - [e=HTTP_AUTHORIZATION:%1] 12RewriteRule .* - [e=HTTP_AUTHORIZATION:%1]
13# Alternative (if the 2 lines above don't work)
14# SetEnvIf Authorization .+ HTTP_AUTHORIZATION=$0
13 15
14# REST API 16# REST API
17# Ionos Hosting needs RewriteBase /
18# RewriteBase /
15RewriteCond %{REQUEST_FILENAME} !-f 19RewriteCond %{REQUEST_FILENAME} !-f
16RewriteCond %{REQUEST_FILENAME} !-d 20RewriteCond %{REQUEST_FILENAME} !-d
17RewriteRule ^ index.php [QSA,L] 21RewriteRule ^ index.php [QSA,L]
diff --git a/AUTHORS b/AUTHORS
index 9c5028eb..fe2aa882 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1,22 +1,24 @@
1 903 ArthurHoaro <arthur@hoa.ro> 1 973 ArthurHoaro <arthur@hoa.ro>
2 402 VirtualTam <virtualtam@flibidi.net> 2 402 VirtualTam <virtualtam@flibidi.net>
3 250 nodiscc <nodiscc@gmail.com> 3 291 nodiscc <nodiscc@gmail.com>
4 56 Sébastien Sauvage <sebsauvage@sebsauvage.net> 4 56 Sébastien Sauvage <sebsauvage@sebsauvage.net>
5 16 Luce Carević <lcarevic@access42.net> 5 16 Luce Carević <lcarevic@access42.net>
6 15 Florian Eula <eula.florian@gmail.com> 6 15 Florian Eula <eula.florian@gmail.com>
7 13 Emilien Klein <emilien@klein.st> 7 13 Emilien Klein <emilien@klein.st>
8 12 Nicolas Danelon <hi@nicolasmd.com.ar> 8 12 Nicolas Danelon <hi@nicolasmd.com.ar>
9 9 Lucas Cimon <lucas.cimon@gmail.com>
9 9 Willi Eggeling <thewilli@gmail.com> 10 9 Willi Eggeling <thewilli@gmail.com>
10 8 Christophe HENRY <christophe.henry@sbgodin.fr> 11 8 Christophe HENRY <christophe.henry@sbgodin.fr>
11 7 Lucas Cimon <lucas.cimon@gmail.com>
12 6 B. van Berkum <dev@dotmpe.com> 12 6 B. van Berkum <dev@dotmpe.com>
13 6 Immánuel Fodor <immanuelfactor+github@gmail.com>
14 6 Keith Carangelo <mail@kcaran.com>
13 6 kalvn <kalvnthereal@gmail.com> 15 6 kalvn <kalvnthereal@gmail.com>
14 6 llune <llune@users.noreply.github.com> 16 6 llune <llune@users.noreply.github.com>
15 5 Mark Schmitz <kramred@gmail.com> 17 5 Mark Schmitz <kramred@gmail.com>
16 5 Sébastien NOBILI <code@pipoprods.org> 18 5 Sébastien NOBILI <code@pipoprods.org>
19 5 dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
17 4 Alexandre Alapetite <alexandre@alapetite.fr> 20 4 Alexandre Alapetite <alexandre@alapetite.fr>
18 4 David Sferruzza <david.sferruzza@gmail.com> 21 4 David Sferruzza <david.sferruzza@gmail.com>
19 4 Immánuel Fodor <immanuelfactor+github@gmail.com>
20 3 Agurato <mail.vmonot@gmail.com> 22 3 Agurato <mail.vmonot@gmail.com>
21 3 Teromene <teromene@teromene.fr> 23 3 Teromene <teromene@teromene.fr>
22 2 Alexandre G.-Raymond <alex@ndre.gr> 24 2 Alexandre G.-Raymond <alex@ndre.gr>
@@ -30,7 +32,6 @@
30 2 Qwerty <champlywood@free.fr> 32 2 Qwerty <champlywood@free.fr>
31 2 Stephen Muth <smuth4@gmail.com> 33 2 Stephen Muth <smuth4@gmail.com>
32 2 Timo Van Neerden <fire@lehollandaisvolant.net> 34 2 Timo Van Neerden <fire@lehollandaisvolant.net>
33 2 dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
34 2 flow.gunso <flow.gunso@gmail.com> 35 2 flow.gunso <flow.gunso@gmail.com>
35 2 julienCXX <software@chmodplusx.eu> 36 2 julienCXX <software@chmodplusx.eu>
36 2 philipp-r <philipp-r@users.noreply.github.com> 37 2 philipp-r <philipp-r@users.noreply.github.com>
@@ -75,4 +76,5 @@
75 1 dimtion <zizou.xena@gmail.com> 76 1 dimtion <zizou.xena@gmail.com>
76 1 durcheinandr <jochen@durcheinandr.de> 77 1 durcheinandr <jochen@durcheinandr.de>
77 1 lapineige <lapineige@users.noreply.github.com> 78 1 lapineige <lapineige@users.noreply.github.com>
79 1 owen bell <66233223+xfnw@users.noreply.github.com>
78 1 rfolo9li <50079896+rfolo9li@users.noreply.github.com> 80 1 rfolo9li <50079896+rfolo9li@users.noreply.github.com>
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4bae5b48..e2fb480b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,7 +4,7 @@ All notable changes to this project will be documented in this file.
4The format is based on [Keep a Changelog](http://keepachangelog.com/) 4The format is based on [Keep a Changelog](http://keepachangelog.com/)
5and this project adheres to [Semantic Versioning](http://semver.org/). 5and this project adheres to [Semantic Versioning](http://semver.org/).
6 6
7## [v0.12.0](https://github.com/shaarli/Shaarli/releases/tag/v0.12.0-beta) - UNRELEASED [beta 2020-08-27] 7## [v0.12.0](https://github.com/shaarli/Shaarli/releases/tag/v0.12.0-beta) - UNRELEASED [beta 2020-08-27 - beta-1 2020-09-30]
8 8
9**Save you `data/` folder before updating!** 9**Save you `data/` folder before updating!**
10 10
@@ -16,6 +16,8 @@ Be aware that by using a beta version you might encounter bugs, and that 3rd par
16- Markdown rendering is now integrated into Shaarli core 16- Markdown rendering is now integrated into Shaarli core
17- Add autofocus on tag cloud filter input 17- Add autofocus on tag cloud filter input
18- Japanese translations 18- Japanese translations
19- Japanese translation: add language to admin configuration page
20- Support for PHP 8.0
19- Support for local anchor URL (startting with `#`) 21- Support for local anchor URL (startting with `#`)
20- LDAP authentication 22- LDAP authentication
21- Encapsulated PageCacheManager 23- Encapsulated PageCacheManager
@@ -24,18 +26,22 @@ Be aware that by using a beta version you might encounter bugs, and that 3rd par
24 - section about mkdocs 26 - section about mkdocs
25 - Ulauncher extension 27 - Ulauncher extension
26- CI: run against PHP 7.4 28- CI: run against PHP 7.4
29- Added $links_per_page variable to template and display on default
30- Inject BookmarkServiceInterface in plugins data
31- Add manual configuration for root URL
32- Added PATCH to the allowed Apache request methods.
27 33
28### Changed 34### Changed
29- Introduce Bookmark object and Service layer 35- Introduce Bookmark object and Service layer
30 - Save bookmark as objects in the datastore 36 - Save bookmark as objects in the datastore
31 - Handle bookmark as objects across the whole codebase (except templates and plugins) 37 - Handle bookmark as objects across the whole codebase (except templates and plugins)
32- Process all Shaarli page through Slim controller, with proper URL rewriting (see #1516) 38- Process all Shaarli page through Slim controller, with proper URL rewriting (see #1516)
39- Docs: the entire documentation has been reviewed, updated and improved, thanks to @nodiscc!
33- ATOM feed: use instance name as author name instead of URL 40- ATOM feed: use instance name as author name instead of URL
34- Updated French translation 41- Updated French translation
35- Docs: 42- Default colors plugin: generate CSS file during initialization
36 - Troubleshooting page rewritten 43- Improve default bookmarks after install
37 - Updated unit tests page 44- Upgrade all front end dependencies and webpack build
38 - Updated Server security page
39 45
40### Fixed 46### Fixed
41- Undefined index: thumbnail in daily page 47- Undefined index: thumbnail in daily page
@@ -54,6 +60,8 @@ Be aware that by using a beta version you might encounter bugs, and that 3rd par
54- Division by zero in tag cloud 60- Division by zero in tag cloud
55- CI: deprecated linux distribution and sudo directive 61- CI: deprecated linux distribution and sudo directive
56- Docker build: gcc is no longer included in python alpine image 62- Docker build: gcc is no longer included in python alpine image
63- Default template: display pin button in mobile view
64- Pinned bookmarks are not longer displayed first in ATOM/RSS feeds
57- Docs: 65- Docs:
58 - Outdated Docker documentation for stable branch 66 - Outdated Docker documentation for stable branch
59 - Outdated links 67 - Outdated links
@@ -63,6 +71,8 @@ Be aware that by using a beta version you might encounter bugs, and that 3rd par
63- Markdown plugin 71- Markdown plugin
64- Docs: 72- Docs:
65 - emojione & twemoji removed 73 - emojione & twemoji removed
74- Makefile: remove static_analysis_summary from all: target
75- doc/Makefile: remove references to composer update
66 76
67## [v0.11.1](https://github.com/shaarli/Shaarli/releases/tag/v0.11.1) - 2019-08-03 77## [v0.11.1](https://github.com/shaarli/Shaarli/releases/tag/v0.11.1) - 2019-08-03
68 78
diff --git a/Makefile b/Makefile
index 4c9a9c83..0ff6bd3f 100644
--- a/Makefile
+++ b/Makefile
@@ -85,6 +85,10 @@ all_tests: test locale_test_de_DE locale_test_en_US locale_test_fr_FR
85 @# --text doesn't work with phpunit 4.* (v5 requires PHP 5.6) 85 @# --text doesn't work with phpunit 4.* (v5 requires PHP 5.6)
86 @#$(BIN)/phpcov merge --text coverage/txt coverage 86 @#$(BIN)/phpcov merge --text coverage/txt coverage
87 87
88### download 3rd-party PHP libraries, including dev dependencies
89composer_dependencies_dev: clean
90 composer install --prefer-dist
91
88## 92##
89# Custom release archive generation 93# Custom release archive generation
90# 94#
diff --git a/application/api/ApiMiddleware.php b/application/api/ApiMiddleware.php
index 09ce6445..f5b53b01 100644
--- a/application/api/ApiMiddleware.php
+++ b/application/api/ApiMiddleware.php
@@ -107,7 +107,9 @@ class ApiMiddleware
107 */ 107 */
108 protected function checkToken($request) 108 protected function checkToken($request)
109 { 109 {
110 if (! $request->hasHeader('Authorization')) { 110 if (!$request->hasHeader('Authorization')
111 && !isset($this->container->environment['REDIRECT_HTTP_AUTHORIZATION'])
112 ) {
111 throw new ApiAuthorizationException('JWT token not provided'); 113 throw new ApiAuthorizationException('JWT token not provided');
112 } 114 }
113 115
@@ -115,7 +117,11 @@ class ApiMiddleware
115 throw new ApiAuthorizationException('Token secret must be set in Shaarli\'s administration'); 117 throw new ApiAuthorizationException('Token secret must be set in Shaarli\'s administration');
116 } 118 }
117 119
118 $authorization = $request->getHeaderLine('Authorization'); 120 if (isset($this->container->environment['REDIRECT_HTTP_AUTHORIZATION'])) {
121 $authorization = $this->container->environment['REDIRECT_HTTP_AUTHORIZATION'];
122 } else {
123 $authorization = $request->getHeaderLine('Authorization');
124 }
119 125
120 if (! preg_match('/^Bearer (.*)/i', $authorization, $matches)) { 126 if (! preg_match('/^Bearer (.*)/i', $authorization, $matches)) {
121 throw new ApiAuthorizationException('Invalid JWT header'); 127 throw new ApiAuthorizationException('Invalid JWT header');
diff --git a/application/bookmark/LinkUtils.php b/application/bookmark/LinkUtils.php
index 68914fca..e7af4d55 100644
--- a/application/bookmark/LinkUtils.php
+++ b/application/bookmark/LinkUtils.php
@@ -26,7 +26,7 @@ function html_extract_title($html)
26 */ 26 */
27function header_extract_charset($header) 27function header_extract_charset($header)
28{ 28{
29 preg_match('/charset="?([^; ]+)/i', $header, $match); 29 preg_match('/charset=["\']?([^; "\']+)/i', $header, $match);
30 if (! empty($match[1])) { 30 if (! empty($match[1])) {
31 return strtolower(trim($match[1])); 31 return strtolower(trim($match[1]));
32 } 32 }
diff --git a/application/front/controller/admin/ManageShaareController.php b/application/front/controller/admin/ManageShaareController.php
index ca2da9b5..59ba2de9 100644
--- a/application/front/controller/admin/ManageShaareController.php
+++ b/application/front/controller/admin/ManageShaareController.php
@@ -69,7 +69,7 @@ class ManageShaareController extends ShaarliAdminController
69 $retrieveDescription 69 $retrieveDescription
70 ) 70 )
71 ); 71 );
72 if (! empty($title) && strtolower($charset) !== 'utf-8') { 72 if (! empty($title) && strtolower($charset) !== 'utf-8' && mb_check_encoding($charset)) {
73 $title = mb_convert_encoding($title, 'utf-8', $charset); 73 $title = mb_convert_encoding($title, 'utf-8', $charset);
74 } 74 }
75 } 75 }
@@ -127,7 +127,7 @@ class ManageShaareController extends ShaarliAdminController
127 $this->checkToken($request); 127 $this->checkToken($request);
128 128
129 // lf_id should only be present if the link exists. 129 // lf_id should only be present if the link exists.
130 $id = $request->getParam('lf_id') ? intval(escape($request->getParam('lf_id'))) : null; 130 $id = $request->getParam('lf_id') !== null ? intval(escape($request->getParam('lf_id'))) : null;
131 if (null !== $id && true === $this->container->bookmarkService->exists($id)) { 131 if (null !== $id && true === $this->container->bookmarkService->exists($id)) {
132 // Edit 132 // Edit
133 $bookmark = $this->container->bookmarkService->get($id); 133 $bookmark = $this->container->bookmarkService->get($id);
diff --git a/doc/md/dev/Unit-tests.md b/doc/md/dev/Unit-tests.md
index 25af82d7..fd286bf0 100644
--- a/doc/md/dev/Unit-tests.md
+++ b/doc/md/dev/Unit-tests.md
@@ -10,21 +10,16 @@ You can either use:
10- a local version, downloadable [here](https://getcomposer.org/download/). 10- a local version, downloadable [here](https://getcomposer.org/download/).
11 11
12```bash 12```bash
13# system-wide version 13# for Debian-based distros
14$ composer install 14sudo apt install composer
15$ composer update
16
17# local version
18$ php composer.phar self-update
19$ php composer.phar install
20$ php composer.phar update
21``` 15```
22 16
17
23## Install Shaarli dev dependencies 18## Install Shaarli dev dependencies
24 19
25```bash 20```bash
26$ cd /path/to/shaarli 21$ cd /path/to/shaarli
27$ composer update 22$ make composer_dependencies_dev
28``` 23```
29 24
30## Install and enable Xdebug to generate PHPUnit coverage reports 25## Install and enable Xdebug to generate PHPUnit coverage reports
@@ -34,7 +29,7 @@ $ composer update
34 29
35```bash 30```bash
36# for Debian-based distros: 31# for Debian-based distros:
37sudo aptitude install php5-xdebug 32sudo apt install php-xdebug
38 33
39# for ArchLinux: 34# for ArchLinux:
40pacman -S xdebug 35pacman -S xdebug
diff --git a/tests/api/ApiMiddlewareTest.php b/tests/api/ApiMiddlewareTest.php
index 7386e435..86700840 100644
--- a/tests/api/ApiMiddlewareTest.php
+++ b/tests/api/ApiMiddlewareTest.php
@@ -67,6 +67,53 @@ class ApiMiddlewareTest extends \Shaarli\TestCase
67 } 67 }
68 68
69 /** 69 /**
70 * Invoke the middleware with a valid token
71 */
72 public function testInvokeMiddlewareWithValidToken(): void
73 {
74 $next = function (Request $request, Response $response): Response {
75 return $response;
76 };
77 $mw = new ApiMiddleware($this->container);
78 $env = Environment::mock([
79 'REQUEST_METHOD' => 'GET',
80 'REQUEST_URI' => '/echo',
81 'HTTP_AUTHORIZATION'=> 'Bearer ' . ApiUtilsTest::generateValidJwtToken('NapoleonWasALizard'),
82 ]);
83 $request = Request::createFromEnvironment($env);
84 $response = new Response();
85 /** @var Response $response */
86 $response = $mw($request, $response, $next);
87
88 $this->assertEquals(200, $response->getStatusCode());
89 }
90
91 /**
92 * Invoke the middleware with a valid token
93 * Using specific Apache CGI redirected authorization.
94 */
95 public function testInvokeMiddlewareWithValidTokenFromRedirectedHeader(): void
96 {
97 $next = function (Request $request, Response $response): Response {
98 return $response;
99 };
100
101 $token = 'Bearer ' . ApiUtilsTest::generateValidJwtToken('NapoleonWasALizard');
102 $this->container->environment['REDIRECT_HTTP_AUTHORIZATION'] = $token;
103 $mw = new ApiMiddleware($this->container);
104 $env = Environment::mock([
105 'REQUEST_METHOD' => 'GET',
106 'REQUEST_URI' => '/echo',
107 ]);
108 $request = Request::createFromEnvironment($env);
109 $response = new Response();
110 /** @var Response $response */
111 $response = $mw($request, $response, $next);
112
113 $this->assertEquals(200, $response->getStatusCode());
114 }
115
116 /**
70 * Invoke the middleware with the API disabled: 117 * Invoke the middleware with the API disabled:
71 * should return a 401 error Unauthorized. 118 * should return a 401 error Unauthorized.
72 */ 119 */
diff --git a/tests/bookmark/LinkUtilsTest.php b/tests/bookmark/LinkUtilsTest.php
index a7087953..ef00b92f 100644
--- a/tests/bookmark/LinkUtilsTest.php
+++ b/tests/bookmark/LinkUtilsTest.php
@@ -43,6 +43,19 @@ class LinkUtilsTest extends TestCase
43 } 43 }
44 44
45 /** 45 /**
46 * Test headers_extract_charset() when the charset is found with odd quotes.
47 */
48 public function testHeadersExtractExistentCharsetWithQuotes()
49 {
50 $charset = 'x-MacCroatian';
51 $headers = 'text/html; charset="' . $charset . '"otherstuff="test"';
52 $this->assertEquals(strtolower($charset), header_extract_charset($headers));
53
54 $headers = 'text/html; charset=\'' . $charset . '\'otherstuff="test"';
55 $this->assertEquals(strtolower($charset), header_extract_charset($headers));
56 }
57
58 /**
46 * Test headers_extract_charset() when the charset is not found. 59 * Test headers_extract_charset() when the charset is not found.
47 */ 60 */
48 public function testHeadersExtractNonExistentCharset() 61 public function testHeadersExtractNonExistentCharset()
diff --git a/tests/front/controller/admin/ManageShaareControllerTest/SaveBookmarkTest.php b/tests/front/controller/admin/ManageShaareControllerTest/SaveBookmarkTest.php
index 3999b44e..f7a68226 100644
--- a/tests/front/controller/admin/ManageShaareControllerTest/SaveBookmarkTest.php
+++ b/tests/front/controller/admin/ManageShaareControllerTest/SaveBookmarkTest.php
@@ -241,6 +241,30 @@ class SaveBookmarkTest extends TestCase
241 } 241 }
242 242
243 /** 243 /**
244 * Test save a bookmark - with ID #0
245 */
246 public function testSaveBookmarkWithIdZero(): void
247 {
248 $parameters = ['lf_id' => '0'];
249
250 $request = $this->createMock(Request::class);
251 $request
252 ->method('getParam')
253 ->willReturnCallback(function (string $key) use ($parameters): ?string {
254 return $parameters[$key] ?? null;
255 })
256 ;
257 $response = new Response();
258
259 $this->container->bookmarkService->expects(static::once())->method('exists')->with(0)->willReturn(true);
260 $this->container->bookmarkService->expects(static::once())->method('get')->with(0)->willReturn(new Bookmark());
261
262 $result = $this->controller->save($request, $response);
263
264 static::assertSame(302, $result->getStatusCode());
265 }
266
267 /**
244 * Change the password with a wrong existing password 268 * Change the password with a wrong existing password
245 */ 269 */
246 public function testSaveBookmarkFromBookmarklet(): void 270 public function testSaveBookmarkFromBookmarklet(): void