From: ArthurHoaro Date: Sat, 3 Oct 2020 10:59:16 +0000 (+0200) Subject: Merge pull request #1575 from ArthurHoaro/feature/php8 X-Git-Tag: v0.12.0-beta-2~7 X-Git-Url: https://git.immae.eu/?a=commitdiff_plain;h=7b18876361f2223672f3a2cac9fc0da16d12d69f;hp=d246e2c5129fe8d3f8e1429b4e8ff8e3e486c779;p=github%2Fshaarli%2FShaarli.git Merge pull request #1575 from ArthurHoaro/feature/php8 --- diff --git a/.github/mailmap b/.github/mailmap index 366946e8..15a25e43 100644 --- a/.github/mailmap +++ b/.github/mailmap @@ -3,6 +3,7 @@ ArthurHoaro Arthur Florian Eula feula Florian Eula Immánuel Fodor +Immánuel Fodor Immánuel! <21174107+immanuelfodor@users.noreply.github.com> kalvn kalvn Neros diff --git a/.htaccess b/.htaccess index af2dc5a7..25fcfb03 100644 --- a/.htaccess +++ b/.htaccess @@ -10,8 +10,12 @@ RewriteRule ^(.git|doxygen|vendor) - [F] # fixes JWT token not correctly forwarded on some Apache/FastCGI setups RewriteCond %{HTTP:Authorization} ^(.*) RewriteRule .* - [e=HTTP_AUTHORIZATION:%1] +# Alternative (if the 2 lines above don't work) +# SetEnvIf Authorization .+ HTTP_AUTHORIZATION=$0 # REST API +# Ionos Hosting needs RewriteBase / +# RewriteBase / RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^ index.php [QSA,L] diff --git a/AUTHORS b/AUTHORS index 9c5028eb..fe2aa882 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,22 +1,24 @@ - 903 ArthurHoaro + 973 ArthurHoaro 402 VirtualTam - 250 nodiscc + 291 nodiscc 56 Sébastien Sauvage 16 Luce Carević 15 Florian Eula 13 Emilien Klein 12 Nicolas Danelon + 9 Lucas Cimon 9 Willi Eggeling 8 Christophe HENRY - 7 Lucas Cimon 6 B. van Berkum + 6 Immánuel Fodor + 6 Keith Carangelo 6 kalvn 6 llune 5 Mark Schmitz 5 Sébastien NOBILI + 5 dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 4 Alexandre Alapetite 4 David Sferruzza - 4 Immánuel Fodor 3 Agurato 3 Teromene 2 Alexandre G.-Raymond @@ -30,7 +32,6 @@ 2 Qwerty 2 Stephen Muth 2 Timo Van Neerden - 2 dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> 2 flow.gunso 2 julienCXX 2 philipp-r @@ -75,4 +76,5 @@ 1 dimtion 1 durcheinandr 1 lapineige + 1 owen bell <66233223+xfnw@users.noreply.github.com> 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. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). -## [v0.12.0](https://github.com/shaarli/Shaarli/releases/tag/v0.12.0-beta) - UNRELEASED [beta 2020-08-27] +## [v0.12.0](https://github.com/shaarli/Shaarli/releases/tag/v0.12.0-beta) - UNRELEASED [beta 2020-08-27 - beta-1 2020-09-30] **Save you `data/` folder before updating!** @@ -16,6 +16,8 @@ Be aware that by using a beta version you might encounter bugs, and that 3rd par - Markdown rendering is now integrated into Shaarli core - Add autofocus on tag cloud filter input - Japanese translations +- Japanese translation: add language to admin configuration page +- Support for PHP 8.0 - Support for local anchor URL (startting with `#`) - LDAP authentication - Encapsulated PageCacheManager @@ -24,18 +26,22 @@ Be aware that by using a beta version you might encounter bugs, and that 3rd par - section about mkdocs - Ulauncher extension - CI: run against PHP 7.4 +- Added $links_per_page variable to template and display on default +- Inject BookmarkServiceInterface in plugins data +- Add manual configuration for root URL +- Added PATCH to the allowed Apache request methods. ### Changed - Introduce Bookmark object and Service layer - Save bookmark as objects in the datastore - Handle bookmark as objects across the whole codebase (except templates and plugins) - Process all Shaarli page through Slim controller, with proper URL rewriting (see #1516) +- Docs: the entire documentation has been reviewed, updated and improved, thanks to @nodiscc! - ATOM feed: use instance name as author name instead of URL - Updated French translation -- Docs: - - Troubleshooting page rewritten - - Updated unit tests page - - Updated Server security page +- Default colors plugin: generate CSS file during initialization +- Improve default bookmarks after install +- Upgrade all front end dependencies and webpack build ### Fixed - 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 - Division by zero in tag cloud - CI: deprecated linux distribution and sudo directive - Docker build: gcc is no longer included in python alpine image +- Default template: display pin button in mobile view +- Pinned bookmarks are not longer displayed first in ATOM/RSS feeds - Docs: - Outdated Docker documentation for stable branch - Outdated links @@ -63,6 +71,8 @@ Be aware that by using a beta version you might encounter bugs, and that 3rd par - Markdown plugin - Docs: - emojione & twemoji removed +- Makefile: remove static_analysis_summary from all: target +- doc/Makefile: remove references to composer update ## [v0.11.1](https://github.com/shaarli/Shaarli/releases/tag/v0.11.1) - 2019-08-03 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 @# --text doesn't work with phpunit 4.* (v5 requires PHP 5.6) @#$(BIN)/phpcov merge --text coverage/txt coverage +### download 3rd-party PHP libraries, including dev dependencies +composer_dependencies_dev: clean + composer install --prefer-dist + ## # Custom release archive generation # 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 */ protected function checkToken($request) { - if (! $request->hasHeader('Authorization')) { + if (!$request->hasHeader('Authorization') + && !isset($this->container->environment['REDIRECT_HTTP_AUTHORIZATION']) + ) { throw new ApiAuthorizationException('JWT token not provided'); } @@ -115,7 +117,11 @@ class ApiMiddleware throw new ApiAuthorizationException('Token secret must be set in Shaarli\'s administration'); } - $authorization = $request->getHeaderLine('Authorization'); + if (isset($this->container->environment['REDIRECT_HTTP_AUTHORIZATION'])) { + $authorization = $this->container->environment['REDIRECT_HTTP_AUTHORIZATION']; + } else { + $authorization = $request->getHeaderLine('Authorization'); + } if (! preg_match('/^Bearer (.*)/i', $authorization, $matches)) { 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) */ function header_extract_charset($header) { - preg_match('/charset="?([^; ]+)/i', $header, $match); + preg_match('/charset=["\']?([^; "\']+)/i', $header, $match); if (! empty($match[1])) { return strtolower(trim($match[1])); } 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 $retrieveDescription ) ); - if (! empty($title) && strtolower($charset) !== 'utf-8') { + if (! empty($title) && strtolower($charset) !== 'utf-8' && mb_check_encoding($charset)) { $title = mb_convert_encoding($title, 'utf-8', $charset); } } @@ -127,7 +127,7 @@ class ManageShaareController extends ShaarliAdminController $this->checkToken($request); // lf_id should only be present if the link exists. - $id = $request->getParam('lf_id') ? intval(escape($request->getParam('lf_id'))) : null; + $id = $request->getParam('lf_id') !== null ? intval(escape($request->getParam('lf_id'))) : null; if (null !== $id && true === $this->container->bookmarkService->exists($id)) { // Edit $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: - a local version, downloadable [here](https://getcomposer.org/download/). ```bash -# system-wide version -$ composer install -$ composer update - -# local version -$ php composer.phar self-update -$ php composer.phar install -$ php composer.phar update +# for Debian-based distros +sudo apt install composer ``` + ## Install Shaarli dev dependencies ```bash $ cd /path/to/shaarli -$ composer update +$ make composer_dependencies_dev ``` ## Install and enable Xdebug to generate PHPUnit coverage reports @@ -34,7 +29,7 @@ $ composer update ```bash # for Debian-based distros: -sudo aptitude install php5-xdebug +sudo apt install php-xdebug # for ArchLinux: pacman -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 @@ -66,6 +66,53 @@ class ApiMiddlewareTest extends \Shaarli\TestCase @unlink(self::$testDatastore); } + /** + * Invoke the middleware with a valid token + */ + public function testInvokeMiddlewareWithValidToken(): void + { + $next = function (Request $request, Response $response): Response { + return $response; + }; + $mw = new ApiMiddleware($this->container); + $env = Environment::mock([ + 'REQUEST_METHOD' => 'GET', + 'REQUEST_URI' => '/echo', + 'HTTP_AUTHORIZATION'=> 'Bearer ' . ApiUtilsTest::generateValidJwtToken('NapoleonWasALizard'), + ]); + $request = Request::createFromEnvironment($env); + $response = new Response(); + /** @var Response $response */ + $response = $mw($request, $response, $next); + + $this->assertEquals(200, $response->getStatusCode()); + } + + /** + * Invoke the middleware with a valid token + * Using specific Apache CGI redirected authorization. + */ + public function testInvokeMiddlewareWithValidTokenFromRedirectedHeader(): void + { + $next = function (Request $request, Response $response): Response { + return $response; + }; + + $token = 'Bearer ' . ApiUtilsTest::generateValidJwtToken('NapoleonWasALizard'); + $this->container->environment['REDIRECT_HTTP_AUTHORIZATION'] = $token; + $mw = new ApiMiddleware($this->container); + $env = Environment::mock([ + 'REQUEST_METHOD' => 'GET', + 'REQUEST_URI' => '/echo', + ]); + $request = Request::createFromEnvironment($env); + $response = new Response(); + /** @var Response $response */ + $response = $mw($request, $response, $next); + + $this->assertEquals(200, $response->getStatusCode()); + } + /** * Invoke the middleware with the API disabled: * should return a 401 error Unauthorized. 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 @@ -42,6 +42,19 @@ class LinkUtilsTest extends TestCase $this->assertEquals(strtolower($charset), header_extract_charset($headers)); } + /** + * Test headers_extract_charset() when the charset is found with odd quotes. + */ + public function testHeadersExtractExistentCharsetWithQuotes() + { + $charset = 'x-MacCroatian'; + $headers = 'text/html; charset="' . $charset . '"otherstuff="test"'; + $this->assertEquals(strtolower($charset), header_extract_charset($headers)); + + $headers = 'text/html; charset=\'' . $charset . '\'otherstuff="test"'; + $this->assertEquals(strtolower($charset), header_extract_charset($headers)); + } + /** * Test headers_extract_charset() when the charset is not found. */ 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 @@ -240,6 +240,30 @@ class SaveBookmarkTest extends TestCase static::assertSame(302, $result->getStatusCode()); } + /** + * Test save a bookmark - with ID #0 + */ + public function testSaveBookmarkWithIdZero(): void + { + $parameters = ['lf_id' => '0']; + + $request = $this->createMock(Request::class); + $request + ->method('getParam') + ->willReturnCallback(function (string $key) use ($parameters): ?string { + return $parameters[$key] ?? null; + }) + ; + $response = new Response(); + + $this->container->bookmarkService->expects(static::once())->method('exists')->with(0)->willReturn(true); + $this->container->bookmarkService->expects(static::once())->method('get')->with(0)->willReturn(new Bookmark()); + + $result = $this->controller->save($request, $response); + + static::assertSame(302, $result->getStatusCode()); + } + /** * Change the password with a wrong existing password */