ouidade il y a 2 ans
Parent
commit
87668f1c0b
33 fichiers modifiés avec 536 ajouts et 257 suppressions
  1. 18 0
      CHANGELOG.md
  2. 0 0
      README.md
  3. 2 6
      bin/gpm
  4. 2 6
      bin/grav
  5. 2 6
      bin/plugin
  6. 4 3
      composer.json
  7. 200 155
      composer.lock
  8. 9 19
      index.php
  9. 42 24
      system/blueprints/config/system.yaml
  10. 12 1
      system/blueprints/user/account.yaml
  11. 1 0
      system/config/system.yaml
  12. 1 1
      system/defines.php
  13. 22 4
      system/src/Grav/Common/Assets.php
  14. 1 1
      system/src/Grav/Common/Assets/BlockAssets.php
  15. 1 1
      system/src/Grav/Common/Backup/Backups.php
  16. 5 1
      system/src/Grav/Common/Flex/Types/Pages/PageIndex.php
  17. 8 1
      system/src/Grav/Common/Flex/Types/Pages/PageObject.php
  18. 1 1
      system/src/Grav/Common/Flex/Types/Users/UserObject.php
  19. 6 2
      system/src/Grav/Common/Grav.php
  20. 2 0
      system/src/Grav/Common/Media/Interfaces/MediaObjectInterface.php
  21. 5 5
      system/src/Grav/Common/Media/Traits/MediaPlayerTrait.php
  22. 4 0
      system/src/Grav/Common/Media/Traits/MediaUploadTrait.php
  23. 1 1
      system/src/Grav/Common/Media/Traits/VideoMediaTrait.php
  24. 2 1
      system/src/Grav/Common/Page/Medium/MediumFactory.php
  25. 68 0
      system/src/Grav/Common/Page/Medium/VectorImageMedium.php
  26. 15 4
      system/src/Grav/Common/Page/Pages.php
  27. 17 1
      system/src/Grav/Common/Security.php
  28. 8 2
      system/src/Grav/Common/Twig/TwigEnvironment.php
  29. 1 1
      system/src/Grav/Common/User/DataUser/User.php
  30. 48 2
      system/src/Grav/Common/User/Traits/UserTrait.php
  31. 6 7
      system/src/Grav/Common/Utils.php
  32. 17 0
      system/src/Grav/Framework/Form/FormFlashFile.php
  33. 5 1
      system/src/Grav/Framework/Form/Traits/FormTrait.php

+ 18 - 0
CHANGELOG.md

@@ -1,3 +1,21 @@
+# v1.7.31
+## 03/14/2022
+
+1. [](#new)
+   * Added new local Multiavatar (local generation). **This will be default in Grav 1.8**
+   * Added support to get image size for SVG vector images [#3533](https://github.com/getgrav/grav/pull/3533)
+   * Added XSS check for uploaded SVG files before they get stored
+   * Fixed phpstan issues (All level 2, Framework level 5)
+2. [](#improved)
+   * Moved Accounts out of Experimental section of System configuration to new "Accounts" tab
+3. [](#bugfix)
+   * Fixed `'mbstring' extension is not loaded` error, use Polyfill instead [#3504](https://github.com/getgrav/grav/pull/3504)
+   * Fixed new `Utils::pathinfo()` and `Utils::basename()` being too strict for legacy use [#3542](https://github.com/getgrav/grav/issues/3542)
+   * Fixed non-standard video html atributes generated by `{{ media.html() }}` [#3540](https://github.com/getgrav/grav/issues/3540)
+   * Fixed entity sanitization for XSS detection
+   * Fixed avatar save location when `account://` stream points to custom directory
+   * Fixed bug in `Utils::url()` when path contains part of root
+
 # v1.7.30
 ## 02/07/2022
 

Fichier diff supprimé car celui-ci est trop grand
+ 0 - 0
README.md


+ 2 - 6
bin/gpm

@@ -25,14 +25,10 @@ if (!file_exists(__DIR__ . '/../vendor/autoload.php')){
 
 $autoload = require __DIR__ . '/../vendor/autoload.php';
 
-if (!ini_get('date.timezone')) {
-    date_default_timezone_set('UTC');
-}
+// Set timezone to default, falls back to system if php.ini not set
+date_default_timezone_set(@date_default_timezone_get());
 
 // Set internal encoding.
-if (!\extension_loaded('mbstring')) {
-    die("'mbstring' extension is not loaded.  This is required for Grav to run correctly");
-}
 @ini_set('default_charset', 'UTF-8');
 mb_internal_encoding('UTF-8');
 

+ 2 - 6
bin/grav

@@ -25,14 +25,10 @@ if (!file_exists(__DIR__ . '/../vendor/autoload.php')){
 
 $autoload = require __DIR__ . '/../vendor/autoload.php';
 
-if (!ini_get('date.timezone')) {
-    date_default_timezone_set('UTC');
-}
+// Set timezone to default, falls back to system if php.ini not set
+date_default_timezone_set(@date_default_timezone_get());
 
 // Set internal encoding.
-if (!\extension_loaded('mbstring')) {
-    die("'mbstring' extension is not loaded.  This is required for Grav to run correctly");
-}
 @ini_set('default_charset', 'UTF-8');
 mb_internal_encoding('UTF-8');
 

+ 2 - 6
bin/plugin

@@ -25,14 +25,10 @@ if (!file_exists(__DIR__ . '/../vendor/autoload.php')){
 
 $autoload = require __DIR__ . '/../vendor/autoload.php';
 
-if (!ini_get('date.timezone')) {
-    date_default_timezone_set('UTC');
-}
+// Set timezone to default, falls back to system if php.ini not set
+date_default_timezone_set(@date_default_timezone_get());
 
 // Set internal encoding.
-if (!\extension_loaded('mbstring')) {
-    die("'mbstring' extension is not loaded.  This is required for Grav to run correctly");
-}
 @ini_set('default_charset', 'UTF-8');
 mb_internal_encoding('UTF-8');
 

+ 4 - 3
composer.json

@@ -59,7 +59,8 @@
         "itsgoingd/clockwork": "^5.0",
         "symfony/http-client": "^4.4",
         "composer/semver": "^1.4",
-        "rhukster/dom-sanitizer": "^1.0"
+        "rhukster/dom-sanitizer": "^1.0",
+        "multiavatar/multiavatar-php": "^1.0"
     },
     "require-dev": {
         "codeception/codeception": "^4.1",
@@ -115,8 +116,8 @@
     "scripts": {
         "api-17": "vendor/bin/phpdoc-md generate system/src > user/pages/14.api/default.17.md",
         "post-create-project-cmd": "bin/grav install",
-        "phpstan": "vendor/bin/phpstan analyse -l 1 -c ./tests/phpstan/phpstan.neon --memory-limit=720M system/src",
-        "phpstan-framework": "vendor/bin/phpstan analyse -l 4 -c ./tests/phpstan/phpstan.neon --memory-limit=480M system/src/Grav/Framework system/src/Grav/Events system/src/Grav/Installer",
+        "phpstan": "vendor/bin/phpstan analyse -l 2 -c ./tests/phpstan/phpstan.neon --memory-limit=720M system/src",
+        "phpstan-framework": "vendor/bin/phpstan analyse -l 5 -c ./tests/phpstan/phpstan.neon --memory-limit=480M system/src/Grav/Framework system/src/Grav/Events system/src/Grav/Installer",
         "phpstan-plugins": "vendor/bin/phpstan analyse -l 1 -c ./tests/phpstan/plugins.neon --memory-limit=400M user/plugins",
         "test": "vendor/bin/codecept run unit",
         "test-windows": "vendor\\bin\\codecept run unit"

+ 200 - 155
composer.lock

@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "1067938388862c52927c6450e8a36df0",
+    "content-hash": "f0530b0fd3e574fef0852376653da5a0",
     "packages": [
         {
             "name": "composer/ca-bundle",
@@ -840,22 +840,21 @@
         },
         {
             "name": "itsgoingd/clockwork",
-            "version": "v5.1.4",
+            "version": "v5.1.5",
             "source": {
                 "type": "git",
                 "url": "https://github.com/itsgoingd/clockwork.git",
-                "reference": "7252aa771b77ac8678b44290fd7ec7577435cce6"
+                "reference": "6a7b3942224fa53cf3704d9adba636e1f3dfeb9a"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/itsgoingd/clockwork/zipball/7252aa771b77ac8678b44290fd7ec7577435cce6",
-                "reference": "7252aa771b77ac8678b44290fd7ec7577435cce6",
+                "url": "https://api.github.com/repos/itsgoingd/clockwork/zipball/6a7b3942224fa53cf3704d9adba636e1f3dfeb9a",
+                "reference": "6a7b3942224fa53cf3704d9adba636e1f3dfeb9a",
                 "shasum": ""
             },
             "require": {
                 "ext-json": "*",
-                "php": ">=5.6",
-                "psr/log": "1.* || ^2.0"
+                "php": ">=5.6"
             },
             "type": "library",
             "extra": {
@@ -897,7 +896,7 @@
             ],
             "support": {
                 "issues": "https://github.com/itsgoingd/clockwork/issues",
-                "source": "https://github.com/itsgoingd/clockwork/tree/v5.1.4"
+                "source": "https://github.com/itsgoingd/clockwork/tree/v5.1.5"
             },
             "funding": [
                 {
@@ -905,7 +904,7 @@
                     "type": "github"
                 }
             ],
-            "time": "2022-01-30T12:36:18+00:00"
+            "time": "2022-02-13T22:57:42+00:00"
         },
         {
             "name": "league/climate",
@@ -1105,25 +1104,26 @@
         },
         {
             "name": "maximebf/debugbar",
-            "version": "v1.17.3",
+            "version": "v1.18.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/maximebf/php-debugbar.git",
-                "reference": "e8ac3499af0ea5b440908e06cc0abe5898008b3c"
+                "reference": "0d44b75f3b5d6d41ae83b79c7a4bceae7fbc78b6"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/maximebf/php-debugbar/zipball/e8ac3499af0ea5b440908e06cc0abe5898008b3c",
-                "reference": "e8ac3499af0ea5b440908e06cc0abe5898008b3c",
+                "url": "https://api.github.com/repos/maximebf/php-debugbar/zipball/0d44b75f3b5d6d41ae83b79c7a4bceae7fbc78b6",
+                "reference": "0d44b75f3b5d6d41ae83b79c7a4bceae7fbc78b6",
                 "shasum": ""
             },
             "require": {
                 "php": "^7.1|^8",
                 "psr/log": "^1|^2|^3",
-                "symfony/var-dumper": "^2.6|^3|^4|^5"
+                "symfony/var-dumper": "^2.6|^3|^4|^5|^6"
             },
             "require-dev": {
-                "phpunit/phpunit": "^7.5.20 || ^9.4.2"
+                "phpunit/phpunit": "^7.5.20 || ^9.4.2",
+                "twig/twig": "^1.38|^2.7|^3.0"
             },
             "suggest": {
                 "kriswallsmith/assetic": "The best way to manage assets",
@@ -1164,9 +1164,9 @@
             ],
             "support": {
                 "issues": "https://github.com/maximebf/php-debugbar/issues",
-                "source": "https://github.com/maximebf/php-debugbar/tree/v1.17.3"
+                "source": "https://github.com/maximebf/php-debugbar/tree/v1.18.0"
             },
-            "time": "2021-10-19T12:33:27+00:00"
+            "time": "2021-12-27T18:49:48+00:00"
         },
         {
             "name": "miljar/php-exif",
@@ -1314,6 +1314,53 @@
             ],
             "time": "2021-05-28T08:32:12+00:00"
         },
+        {
+            "name": "multiavatar/multiavatar-php",
+            "version": "v1.0.5",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/multiavatar/multiavatar-php.git",
+                "reference": "13a62a656b1c2ca1c62dee57b4c1d8a3b04e6574"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/multiavatar/multiavatar-php/zipball/13a62a656b1c2ca1c62dee57b4c1d8a3b04e6574",
+                "reference": "13a62a656b1c2ca1c62dee57b4c1d8a3b04e6574",
+                "shasum": ""
+            },
+            "type": "library",
+            "autoload": {
+                "classmap": [
+                    "Multiavatar.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "proprietary"
+            ],
+            "authors": [
+                {
+                    "name": "Gie Katon",
+                    "homepage": "https://giekaton.com"
+                }
+            ],
+            "description": "Multicultural Avatar Generator",
+            "homepage": "https://multiavatar.com",
+            "keywords": [
+                "avatar",
+                "creator",
+                "generator",
+                "image",
+                "maker",
+                "picture",
+                "profile"
+            ],
+            "support": {
+                "issues": "https://github.com/multiavatar/multiavatar-php/issues",
+                "source": "https://github.com/multiavatar/multiavatar-php/tree/v1.0.5"
+            },
+            "time": "2021-03-02T07:33:46+00:00"
+        },
         {
             "name": "nyholm/psr7",
             "version": "1.5.0",
@@ -2075,44 +2122,37 @@
         },
         {
             "name": "rockettheme/toolbox",
-            "version": "1.6.0",
+            "version": "1.6.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/rockettheme/toolbox.git",
-                "reference": "a0eb328b9c416e526c8264b48ccbc1a7519e8618"
+                "reference": "fdf0195ced25b83525d3b084c3e81f05de96ac8c"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/rockettheme/toolbox/zipball/a0eb328b9c416e526c8264b48ccbc1a7519e8618",
-                "reference": "a0eb328b9c416e526c8264b48ccbc1a7519e8618",
+                "url": "https://api.github.com/repos/rockettheme/toolbox/zipball/fdf0195ced25b83525d3b084c3e81f05de96ac8c",
+                "reference": "fdf0195ced25b83525d3b084c3e81f05de96ac8c",
                 "shasum": ""
             },
             "require": {
                 "ext-json": "*",
                 "php": ">=5.6.0",
-                "pimple/pimple": "~3.0",
-                "symfony/event-dispatcher": "^3.4|^4.0",
-                "symfony/polyfill-php80": "^1.23",
-                "symfony/polyfill-php81": "^1.23",
-                "symfony/yaml": "^3.4|^4.0"
-            },
-            "require-dev": {
-                "phpstan/phpstan": "^1.2",
-                "phpstan/phpstan-deprecation-rules": "^1.0",
-                "phpunit/phpunit": "^8.0"
+                "pimple/pimple": "^3.0",
+                "symfony/event-dispatcher": "^3.4|^4.0|^5.0",
+                "symfony/yaml": "^3.4|^4.0|^5.0"
             },
             "type": "library",
             "autoload": {
                 "psr-4": {
-                    "RocketTheme\\Toolbox\\ArrayTraits\\": "ArrayTraits/src",
-                    "RocketTheme\\Toolbox\\Blueprints\\": "Blueprints/src",
-                    "RocketTheme\\Toolbox\\Compat\\": "Compat/src",
                     "RocketTheme\\Toolbox\\DI\\": "DI/src",
-                    "RocketTheme\\Toolbox\\Event\\": "Event/src",
                     "RocketTheme\\Toolbox\\File\\": "File/src",
-                    "RocketTheme\\Toolbox\\ResourceLocator\\": "ResourceLocator/src",
+                    "RocketTheme\\Toolbox\\Event\\": "Event/src",
+                    "RocketTheme\\Toolbox\\Compat\\": "Compat/src",
                     "RocketTheme\\Toolbox\\Session\\": "Session/src",
-                    "RocketTheme\\Toolbox\\StreamWrapper\\": "StreamWrapper/src"
+                    "RocketTheme\\Toolbox\\Blueprints\\": "Blueprints/src",
+                    "RocketTheme\\Toolbox\\ArrayTraits\\": "ArrayTraits/src",
+                    "RocketTheme\\Toolbox\\StreamWrapper\\": "StreamWrapper/src",
+                    "RocketTheme\\Toolbox\\ResourceLocator\\": "ResourceLocator/src"
                 },
                 "exclude-from-classmap": [
                     "**/tests/"
@@ -2130,9 +2170,9 @@
             ],
             "support": {
                 "issues": "https://github.com/rockettheme/toolbox/issues",
-                "source": "https://github.com/rockettheme/toolbox/tree/1.6.0"
+                "source": "https://github.com/rockettheme/toolbox/tree/1.6.1"
             },
-            "time": "2021-12-15T19:20:00+00:00"
+            "time": "2022-02-08T08:36:03+00:00"
         },
         {
             "name": "seld/cli-prompt",
@@ -2191,16 +2231,16 @@
         },
         {
             "name": "symfony/console",
-            "version": "v4.4.37",
+            "version": "v4.4.38",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/console.git",
-                "reference": "0259f01dbf9d77badddbbf4c2abb681f24c9cac6"
+                "reference": "5a50085bf5460f0c0d60a50b58388c1249826b8a"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/console/zipball/0259f01dbf9d77badddbbf4c2abb681f24c9cac6",
-                "reference": "0259f01dbf9d77badddbbf4c2abb681f24c9cac6",
+                "url": "https://api.github.com/repos/symfony/console/zipball/5a50085bf5460f0c0d60a50b58388c1249826b8a",
+                "reference": "5a50085bf5460f0c0d60a50b58388c1249826b8a",
                 "shasum": ""
             },
             "require": {
@@ -2261,7 +2301,7 @@
             "description": "Eases the creation of beautiful and testable command line interfaces",
             "homepage": "https://symfony.com",
             "support": {
-                "source": "https://github.com/symfony/console/tree/v4.4.37"
+                "source": "https://github.com/symfony/console/tree/v4.4.38"
             },
             "funding": [
                 {
@@ -2277,7 +2317,7 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2022-01-26T16:15:26+00:00"
+            "time": "2022-01-30T21:23:57+00:00"
         },
         {
             "name": "symfony/contracts",
@@ -2459,16 +2499,16 @@
         },
         {
             "name": "symfony/http-client",
-            "version": "v4.4.37",
+            "version": "v4.4.39",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/http-client.git",
-                "reference": "8129ccd6233338e1d495b7734c003053766cb262"
+                "reference": "40342406a975385c5b21e929df46e3fc0278853d"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/http-client/zipball/8129ccd6233338e1d495b7734c003053766cb262",
-                "reference": "8129ccd6233338e1d495b7734c003053766cb262",
+                "url": "https://api.github.com/repos/symfony/http-client/zipball/40342406a975385c5b21e929df46e3fc0278853d",
+                "reference": "40342406a975385c5b21e929df46e3fc0278853d",
                 "shasum": ""
             },
             "require": {
@@ -2520,7 +2560,7 @@
             "description": "Provides powerful methods to fetch HTTP resources synchronously or asynchronously",
             "homepage": "https://symfony.com",
             "support": {
-                "source": "https://github.com/symfony/http-client/tree/v4.4.37"
+                "source": "https://github.com/symfony/http-client/tree/v4.4.39"
             },
             "funding": [
                 {
@@ -2536,11 +2576,11 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2022-01-19T13:29:07+00:00"
+            "time": "2022-02-28T13:17:32+00:00"
         },
         {
             "name": "symfony/polyfill-ctype",
-            "version": "v1.24.0",
+            "version": "v1.25.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/polyfill-ctype.git",
@@ -2572,12 +2612,12 @@
                 }
             },
             "autoload": {
-                "psr-4": {
-                    "Symfony\\Polyfill\\Ctype\\": ""
-                },
                 "files": [
                     "bootstrap.php"
-                ]
+                ],
+                "psr-4": {
+                    "Symfony\\Polyfill\\Ctype\\": ""
+                }
             },
             "notification-url": "https://packagist.org/downloads/",
             "license": [
@@ -2602,7 +2642,7 @@
                 "portable"
             ],
             "support": {
-                "source": "https://github.com/symfony/polyfill-ctype/tree/v1.24.0"
+                "source": "https://github.com/symfony/polyfill-ctype/tree/v1.25.0"
             },
             "funding": [
                 {
@@ -2622,7 +2662,7 @@
         },
         {
             "name": "symfony/polyfill-iconv",
-            "version": "v1.24.0",
+            "version": "v1.25.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/polyfill-iconv.git",
@@ -2685,7 +2725,7 @@
                 "shim"
             ],
             "support": {
-                "source": "https://github.com/symfony/polyfill-iconv/tree/v1.24.0"
+                "source": "https://github.com/symfony/polyfill-iconv/tree/v1.25.0"
             },
             "funding": [
                 {
@@ -2705,7 +2745,7 @@
         },
         {
             "name": "symfony/polyfill-mbstring",
-            "version": "v1.24.0",
+            "version": "v1.25.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/polyfill-mbstring.git",
@@ -2737,12 +2777,12 @@
                 }
             },
             "autoload": {
-                "psr-4": {
-                    "Symfony\\Polyfill\\Mbstring\\": ""
-                },
                 "files": [
                     "bootstrap.php"
-                ]
+                ],
+                "psr-4": {
+                    "Symfony\\Polyfill\\Mbstring\\": ""
+                }
             },
             "notification-url": "https://packagist.org/downloads/",
             "license": [
@@ -2768,7 +2808,7 @@
                 "shim"
             ],
             "support": {
-                "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.24.0"
+                "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.25.0"
             },
             "funding": [
                 {
@@ -2788,7 +2828,7 @@
         },
         {
             "name": "symfony/polyfill-php74",
-            "version": "v1.24.0",
+            "version": "v1.25.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/polyfill-php74.git",
@@ -2848,7 +2888,7 @@
                 "shim"
             ],
             "support": {
-                "source": "https://github.com/symfony/polyfill-php74/tree/v1.24.0"
+                "source": "https://github.com/symfony/polyfill-php74/tree/v1.25.0"
             },
             "funding": [
                 {
@@ -2868,16 +2908,16 @@
         },
         {
             "name": "symfony/polyfill-php80",
-            "version": "v1.24.0",
+            "version": "v1.25.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/polyfill-php80.git",
-                "reference": "57b712b08eddb97c762a8caa32c84e037892d2e9"
+                "reference": "4407588e0d3f1f52efb65fbe92babe41f37fe50c"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/57b712b08eddb97c762a8caa32c84e037892d2e9",
-                "reference": "57b712b08eddb97c762a8caa32c84e037892d2e9",
+                "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/4407588e0d3f1f52efb65fbe92babe41f37fe50c",
+                "reference": "4407588e0d3f1f52efb65fbe92babe41f37fe50c",
                 "shasum": ""
             },
             "require": {
@@ -2931,7 +2971,7 @@
                 "shim"
             ],
             "support": {
-                "source": "https://github.com/symfony/polyfill-php80/tree/v1.24.0"
+                "source": "https://github.com/symfony/polyfill-php80/tree/v1.25.0"
             },
             "funding": [
                 {
@@ -2947,11 +2987,11 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2021-09-13T13:58:33+00:00"
+            "time": "2022-03-04T08:16:47+00:00"
         },
         {
             "name": "symfony/polyfill-php81",
-            "version": "v1.24.0",
+            "version": "v1.25.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/polyfill-php81.git",
@@ -3010,7 +3050,7 @@
                 "shim"
             ],
             "support": {
-                "source": "https://github.com/symfony/polyfill-php81/tree/v1.24.0"
+                "source": "https://github.com/symfony/polyfill-php81/tree/v1.25.0"
             },
             "funding": [
                 {
@@ -3092,16 +3132,16 @@
         },
         {
             "name": "symfony/var-dumper",
-            "version": "v4.4.37",
+            "version": "v4.4.39",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/var-dumper.git",
-                "reference": "e74eee4ec02de71db3d60151aa5b203c990556df"
+                "reference": "35237c5e5dcb6593a46a860ba5b29c1d4683d80e"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/var-dumper/zipball/e74eee4ec02de71db3d60151aa5b203c990556df",
-                "reference": "e74eee4ec02de71db3d60151aa5b203c990556df",
+                "url": "https://api.github.com/repos/symfony/var-dumper/zipball/35237c5e5dcb6593a46a860ba5b29c1d4683d80e",
+                "reference": "35237c5e5dcb6593a46a860ba5b29c1d4683d80e",
                 "shasum": ""
             },
             "require": {
@@ -3161,7 +3201,7 @@
                 "dump"
             ],
             "support": {
-                "source": "https://github.com/symfony/var-dumper/tree/v4.4.37"
+                "source": "https://github.com/symfony/var-dumper/tree/v4.4.39"
             },
             "funding": [
                 {
@@ -3177,7 +3217,7 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2022-01-02T09:41:36+00:00"
+            "time": "2022-02-25T10:38:15+00:00"
         },
         {
             "name": "symfony/yaml",
@@ -3451,16 +3491,16 @@
         },
         {
             "name": "codeception/codeception",
-            "version": "4.1.29",
+            "version": "4.1.30",
             "source": {
                 "type": "git",
                 "url": "https://github.com/Codeception/Codeception.git",
-                "reference": "f8dec8f2bf5347cc596aaf141753f4fb2504c17c"
+                "reference": "a035d77d070fa57fad438e07a65447aeca248c45"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/Codeception/Codeception/zipball/f8dec8f2bf5347cc596aaf141753f4fb2504c17c",
-                "reference": "f8dec8f2bf5347cc596aaf141753f4fb2504c17c",
+                "url": "https://api.github.com/repos/Codeception/Codeception/zipball/a035d77d070fa57fad438e07a65447aeca248c45",
+                "reference": "a035d77d070fa57fad438e07a65447aeca248c45",
                 "shasum": ""
             },
             "require": {
@@ -3537,7 +3577,7 @@
             ],
             "support": {
                 "issues": "https://github.com/Codeception/Codeception/issues",
-                "source": "https://github.com/Codeception/Codeception/tree/4.1.29"
+                "source": "https://github.com/Codeception/Codeception/tree/4.1.30"
             },
             "funding": [
                 {
@@ -3545,7 +3585,7 @@
                     "type": "open_collective"
                 }
             ],
-            "time": "2022-01-29T16:56:03+00:00"
+            "time": "2022-03-05T18:12:30+00:00"
         },
         {
             "name": "codeception/lib-asserts",
@@ -3863,29 +3903,30 @@
         },
         {
             "name": "doctrine/instantiator",
-            "version": "1.4.0",
+            "version": "1.4.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/doctrine/instantiator.git",
-                "reference": "d56bf6102915de5702778fe20f2de3b2fe570b5b"
+                "reference": "10dcfce151b967d20fde1b34ae6640712c3891bc"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/doctrine/instantiator/zipball/d56bf6102915de5702778fe20f2de3b2fe570b5b",
-                "reference": "d56bf6102915de5702778fe20f2de3b2fe570b5b",
+                "url": "https://api.github.com/repos/doctrine/instantiator/zipball/10dcfce151b967d20fde1b34ae6640712c3891bc",
+                "reference": "10dcfce151b967d20fde1b34ae6640712c3891bc",
                 "shasum": ""
             },
             "require": {
                 "php": "^7.1 || ^8.0"
             },
             "require-dev": {
-                "doctrine/coding-standard": "^8.0",
+                "doctrine/coding-standard": "^9",
                 "ext-pdo": "*",
                 "ext-phar": "*",
-                "phpbench/phpbench": "^0.13 || 1.0.0-alpha2",
-                "phpstan/phpstan": "^0.12",
-                "phpstan/phpstan-phpunit": "^0.12",
-                "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0"
+                "phpbench/phpbench": "^0.16 || ^1",
+                "phpstan/phpstan": "^1.4",
+                "phpstan/phpstan-phpunit": "^1",
+                "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
+                "vimeo/psalm": "^4.22"
             },
             "type": "library",
             "autoload": {
@@ -3912,7 +3953,7 @@
             ],
             "support": {
                 "issues": "https://github.com/doctrine/instantiator/issues",
-                "source": "https://github.com/doctrine/instantiator/tree/1.4.0"
+                "source": "https://github.com/doctrine/instantiator/tree/1.4.1"
             },
             "funding": [
                 {
@@ -3928,7 +3969,7 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2020-11-10T18:47:58+00:00"
+            "time": "2022-03-03T08:28:38+00:00"
         },
         {
             "name": "getgrav/markdowndocs",
@@ -4026,12 +4067,12 @@
                 }
             },
             "autoload": {
-                "psr-4": {
-                    "GuzzleHttp\\": "src/"
-                },
                 "files": [
                     "src/functions_include.php"
-                ]
+                ],
+                "psr-4": {
+                    "GuzzleHttp\\": "src/"
+                }
             },
             "notification-url": "https://packagist.org/downloads/",
             "license": [
@@ -4133,12 +4174,12 @@
                 }
             },
             "autoload": {
-                "psr-4": {
-                    "GuzzleHttp\\Promise\\": "src/"
-                },
                 "files": [
                     "src/functions_include.php"
-                ]
+                ],
+                "psr-4": {
+                    "GuzzleHttp\\Promise\\": "src/"
+                }
             },
             "notification-url": "https://packagist.org/downloads/",
             "license": [
@@ -4192,25 +4233,29 @@
         },
         {
             "name": "myclabs/deep-copy",
-            "version": "1.10.2",
+            "version": "1.11.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/myclabs/DeepCopy.git",
-                "reference": "776f831124e9c62e1a2c601ecc52e776d8bb7220"
+                "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/776f831124e9c62e1a2c601ecc52e776d8bb7220",
-                "reference": "776f831124e9c62e1a2c601ecc52e776d8bb7220",
+                "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/14daed4296fae74d9e3201d2c4925d1acb7aa614",
+                "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614",
                 "shasum": ""
             },
             "require": {
                 "php": "^7.1 || ^8.0"
             },
+            "conflict": {
+                "doctrine/collections": "<1.6.8",
+                "doctrine/common": "<2.13.3 || >=3,<3.2.2"
+            },
             "require-dev": {
-                "doctrine/collections": "^1.0",
-                "doctrine/common": "^2.6",
-                "phpunit/phpunit": "^7.1"
+                "doctrine/collections": "^1.6.8",
+                "doctrine/common": "^2.13.3 || ^3.2.2",
+                "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13"
             },
             "type": "library",
             "autoload": {
@@ -4235,7 +4280,7 @@
             ],
             "support": {
                 "issues": "https://github.com/myclabs/DeepCopy/issues",
-                "source": "https://github.com/myclabs/DeepCopy/tree/1.10.2"
+                "source": "https://github.com/myclabs/DeepCopy/tree/1.11.0"
             },
             "funding": [
                 {
@@ -4243,7 +4288,7 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2020-11-13T09:40:50+00:00"
+            "time": "2022-03-03T13:19:32+00:00"
         },
         {
             "name": "nikic/php-parser",
@@ -4363,16 +4408,16 @@
         },
         {
             "name": "phar-io/version",
-            "version": "3.1.0",
+            "version": "3.2.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/phar-io/version.git",
-                "reference": "bae7c545bef187884426f042434e561ab1ddb182"
+                "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/phar-io/version/zipball/bae7c545bef187884426f042434e561ab1ddb182",
-                "reference": "bae7c545bef187884426f042434e561ab1ddb182",
+                "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74",
+                "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74",
                 "shasum": ""
             },
             "require": {
@@ -4408,9 +4453,9 @@
             "description": "Library for handling version information and constraints",
             "support": {
                 "issues": "https://github.com/phar-io/version/issues",
-                "source": "https://github.com/phar-io/version/tree/3.1.0"
+                "source": "https://github.com/phar-io/version/tree/3.2.1"
             },
-            "time": "2021-02-23T14:00:09+00:00"
+            "time": "2022-02-21T01:04:05+00:00"
         },
         {
             "name": "phpdocumentor/reflection-common",
@@ -4641,16 +4686,16 @@
         },
         {
             "name": "phpstan/phpstan",
-            "version": "1.4.6",
+            "version": "1.4.8",
             "source": {
                 "type": "git",
                 "url": "https://github.com/phpstan/phpstan.git",
-                "reference": "8a7761f1c520e0dad6e04d862fdc697445457cfe"
+                "reference": "2a6d6704b17c4db6190cc3104056c0aad740cb15"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/phpstan/phpstan/zipball/8a7761f1c520e0dad6e04d862fdc697445457cfe",
-                "reference": "8a7761f1c520e0dad6e04d862fdc697445457cfe",
+                "url": "https://api.github.com/repos/phpstan/phpstan/zipball/2a6d6704b17c4db6190cc3104056c0aad740cb15",
+                "reference": "2a6d6704b17c4db6190cc3104056c0aad740cb15",
                 "shasum": ""
             },
             "require": {
@@ -4681,7 +4726,7 @@
             "description": "PHPStan - PHP Static Analysis Tool",
             "support": {
                 "issues": "https://github.com/phpstan/phpstan/issues",
-                "source": "https://github.com/phpstan/phpstan/tree/1.4.6"
+                "source": "https://github.com/phpstan/phpstan/tree/1.4.8"
             },
             "funding": [
                 {
@@ -4701,7 +4746,7 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2022-02-06T12:56:13+00:00"
+            "time": "2022-03-04T13:03:56+00:00"
         },
         {
             "name": "phpstan/phpstan-deprecation-rules",
@@ -4755,16 +4800,16 @@
         },
         {
             "name": "phpunit/php-code-coverage",
-            "version": "9.2.10",
+            "version": "9.2.15",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
-                "reference": "d5850aaf931743067f4bfc1ae4cbd06468400687"
+                "reference": "2e9da11878c4202f97915c1cb4bb1ca318a63f5f"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/d5850aaf931743067f4bfc1ae4cbd06468400687",
-                "reference": "d5850aaf931743067f4bfc1ae4cbd06468400687",
+                "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/2e9da11878c4202f97915c1cb4bb1ca318a63f5f",
+                "reference": "2e9da11878c4202f97915c1cb4bb1ca318a63f5f",
                 "shasum": ""
             },
             "require": {
@@ -4820,7 +4865,7 @@
             ],
             "support": {
                 "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
-                "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.10"
+                "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.15"
             },
             "funding": [
                 {
@@ -4828,7 +4873,7 @@
                     "type": "github"
                 }
             ],
-            "time": "2021-12-05T09:12:13+00:00"
+            "time": "2022-03-07T09:28:20+00:00"
         },
         {
             "name": "phpunit/php-file-iterator",
@@ -5073,16 +5118,16 @@
         },
         {
             "name": "phpunit/phpunit",
-            "version": "9.5.13",
+            "version": "9.5.18",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/phpunit.git",
-                "reference": "597cb647654ede35e43b137926dfdfef0fb11743"
+                "reference": "1b5856028273bfd855e60a887278857d872ec67a"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/597cb647654ede35e43b137926dfdfef0fb11743",
-                "reference": "597cb647654ede35e43b137926dfdfef0fb11743",
+                "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/1b5856028273bfd855e60a887278857d872ec67a",
+                "reference": "1b5856028273bfd855e60a887278857d872ec67a",
                 "shasum": ""
             },
             "require": {
@@ -5098,7 +5143,7 @@
                 "phar-io/version": "^3.0.2",
                 "php": ">=7.3",
                 "phpspec/prophecy": "^1.12.1",
-                "phpunit/php-code-coverage": "^9.2.7",
+                "phpunit/php-code-coverage": "^9.2.13",
                 "phpunit/php-file-iterator": "^3.0.5",
                 "phpunit/php-invoker": "^3.1.1",
                 "phpunit/php-text-template": "^2.0.3",
@@ -5133,11 +5178,11 @@
                 }
             },
             "autoload": {
-                "classmap": [
-                    "src/"
-                ],
                 "files": [
                     "src/Framework/Assert/Functions.php"
+                ],
+                "classmap": [
+                    "src/"
                 ]
             },
             "notification-url": "https://packagist.org/downloads/",
@@ -5160,7 +5205,7 @@
             ],
             "support": {
                 "issues": "https://github.com/sebastianbergmann/phpunit/issues",
-                "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.13"
+                "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.18"
             },
             "funding": [
                 {
@@ -5172,7 +5217,7 @@
                     "type": "github"
                 }
             ],
-            "time": "2022-01-24T07:33:35+00:00"
+            "time": "2022-03-08T06:52:28+00:00"
         },
         {
             "name": "psr/http-client",
@@ -5732,16 +5777,16 @@
         },
         {
             "name": "sebastian/global-state",
-            "version": "5.0.3",
+            "version": "5.0.5",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/global-state.git",
-                "reference": "23bd5951f7ff26f12d4e3242864df3e08dec4e49"
+                "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/23bd5951f7ff26f12d4e3242864df3e08dec4e49",
-                "reference": "23bd5951f7ff26f12d4e3242864df3e08dec4e49",
+                "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/0ca8db5a5fc9c8646244e629625ac486fa286bf2",
+                "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2",
                 "shasum": ""
             },
             "require": {
@@ -5784,7 +5829,7 @@
             ],
             "support": {
                 "issues": "https://github.com/sebastianbergmann/global-state/issues",
-                "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.3"
+                "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.5"
             },
             "funding": [
                 {
@@ -5792,7 +5837,7 @@
                     "type": "github"
                 }
             ],
-            "time": "2021-06-11T13:31:12+00:00"
+            "time": "2022-02-14T08:28:10+00:00"
         },
         {
             "name": "sebastian/lines-of-code",
@@ -6397,16 +6442,16 @@
         },
         {
             "name": "symfony/dom-crawler",
-            "version": "v5.4.3",
+            "version": "v5.4.6",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/dom-crawler.git",
-                "reference": "2634381fdf27a2a0a8ac8eb404025eb656c65d0c"
+                "reference": "c0bda97480d96337bd3866026159a8b358665457"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/2634381fdf27a2a0a8ac8eb404025eb656c65d0c",
-                "reference": "2634381fdf27a2a0a8ac8eb404025eb656c65d0c",
+                "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/c0bda97480d96337bd3866026159a8b358665457",
+                "reference": "c0bda97480d96337bd3866026159a8b358665457",
                 "shasum": ""
             },
             "require": {
@@ -6452,7 +6497,7 @@
             "description": "Eases DOM navigation for HTML and XML documents",
             "homepage": "https://symfony.com",
             "support": {
-                "source": "https://github.com/symfony/dom-crawler/tree/v5.4.3"
+                "source": "https://github.com/symfony/dom-crawler/tree/v5.4.6"
             },
             "funding": [
                 {
@@ -6468,7 +6513,7 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2022-01-02T09:53:40+00:00"
+            "time": "2022-03-02T12:42:23+00:00"
         },
         {
             "name": "symfony/finder",

+ 9 - 19
index.php

@@ -20,16 +20,6 @@ if (PHP_SAPI === 'cli-server') {
     }
 }
 
-// Set timezone to default, falls back to system if php.ini not set
-date_default_timezone_set(@date_default_timezone_get());
-
-// Set internal encoding.
-if (!\extension_loaded('mbstring')) {
-    die("'mbstring' extension is not loaded.  This is required for Grav to run correctly");
-}
-@ini_set('default_charset', 'UTF-8');
-mb_internal_encoding('UTF-8');
-
 // Ensure vendor libraries exist
 $autoload = __DIR__ . '/vendor/autoload.php';
 if (!is_file($autoload)) {
@@ -39,23 +29,23 @@ if (!is_file($autoload)) {
 // Register the auto-loader.
 $loader = require $autoload;
 
+// Set timezone to default, falls back to system if php.ini not set
+date_default_timezone_set(@date_default_timezone_get());
+
+// Set internal encoding.
+@ini_set('default_charset', 'UTF-8');
+mb_internal_encoding('UTF-8');
+
 use Grav\Common\Grav;
 use RocketTheme\Toolbox\Event\Event;
 
 // Get the Grav instance
-$grav = Grav::instance(
-    array(
-        'loader' => $loader
-    )
-);
+$grav = Grav::instance(array('loader' => $loader));
 
 // Process the page
 try {
     $grav->process();
-} catch (\Error $e) {
-    $grav->fireEvent('onFatalException', new Event(array('exception' => $e)));
-    throw $e;
-} catch (\Exception $e) {
+} catch (\Error|\Exception $e) {
     $grav->fireEvent('onFatalException', new Event(array('exception' => $e)));
     throw $e;
 }

+ 42 - 24
system/blueprints/config/system.yaml

@@ -1786,35 +1786,15 @@ form:
               validate:
                 type: bool
 
-        experimental:
+
+        accounts:
           type: tab
-          title: PLUGIN_ADMIN.EXPERIMENTAL
+          title: PLUGIN_ADMIN.ACCOUNTS
 
           fields:
-            experimental_section:
-              type: section
-              title: PLUGIN_ADMIN.EXPERIMENTAL
-              underline: true
-
-#            flex_pages:
-#              type: section
-#              title: Flex Pages
-#
-#            pages.type:
-#              type: select
-#              label: PLUGIN_ADMIN.PAGES_TYPE
-#              highlight: regular
-#              help: PLUGIN_ADMIN.PAGES_TYPE_HELP
-#              options:
-#                regular: PLUGIN_ADMIN.REGULAR
-#                flex: PLUGIN_ADMIN.FLEX
-
-            pages.type:
-              type: hidden
-
             flex_accounts:
               type: section
-              title: Flex Accounts
+              title: User Accounts
 
             accounts.type:
               type: select
@@ -1833,3 +1813,41 @@ form:
               options:
                 file: PLUGIN_ADMIN.FILE
                 folder: PLUGIN_ADMIN.FOLDER
+
+            accounts.avatar:
+              type: select
+              label: PLUGIN_ADMIN.AVATAR
+              default: gravatar
+              help: PLUGIN_ADMIN.AVATAR_HELP
+              options:
+                multiavatar: Multiavatar [local]
+                gravatar: Gravatar [external]
+
+#        experimental:
+#          type: tab
+#          title: PLUGIN_ADMIN.EXPERIMENTAL
+#
+#          fields:
+#            experimental_section:
+#              type: section
+#              title: PLUGIN_ADMIN.EXPERIMENTAL
+#              underline: true
+#
+#            flex_pages:
+#              type: section
+#              title: Flex Pages
+#
+#            pages.type:
+#              type: select
+#              label: PLUGIN_ADMIN.PAGES_TYPE
+#              highlight: regular
+#              help: PLUGIN_ADMIN.PAGES_TYPE_HELP
+#              options:
+#                regular: PLUGIN_ADMIN.REGULAR
+#                flex: PLUGIN_ADMIN.FLEX
+#
+#            pages.type:
+#              type: hidden
+
+
+

+ 12 - 1
system/blueprints/user/account.yaml

@@ -11,10 +11,21 @@ form:
         avatar:
             type: file
             size: large
-            destination: 'user://accounts/avatars'
+            destination: 'account://avatars'
             multiple: false
             random_name: true
 
+        multiavatar_only:
+          type: conditional
+          condition: config.system.accounts.avatar == 'multiavatar'
+          fields:
+            avatar_hash:
+                type: text
+                label: ''
+                placeholder: 'e.g. dceaadcfda491f4e45'
+                description: PLUGIN_ADMIN.AVATAR_HASH
+                size: large
+
         content:
             type: section
             title: PLUGIN_ADMIN.ACCOUNT

+ 1 - 0
system/config/system.yaml

@@ -208,6 +208,7 @@ http:
 accounts:
   type: regular                                  # EXPERIMENTAL: Account type: regular or flex
   storage: file                                  # EXPERIMENTAL: Flex storage type: file or folder
+  avatar: gravatar                               # Avatar generator [multiavatar|gravatar]
 
 flex:
   cache:

+ 1 - 1
system/defines.php

@@ -9,7 +9,7 @@
 
 // Some standard defines
 define('GRAV', true);
-define('GRAV_VERSION', '1.7.30');
+define('GRAV_VERSION', '1.7.31');
 define('GRAV_SCHEMA', '1.7.0_2020-11-20_1');
 define('GRAV_TESTING', false);
 

+ 22 - 4
system/src/Grav/Common/Assets.php

@@ -16,8 +16,8 @@ use Grav\Common\Assets\Traits\TestingAssetsTrait;
 use Grav\Common\Config\Config;
 use Grav\Framework\Object\PropertyObject;
 use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
+use function array_slice;
 use function call_user_func_array;
-use function count;
 use function func_get_args;
 use function is_array;
 
@@ -174,6 +174,10 @@ class Assets extends PropertyObject
      */
     public function add($asset)
     {
+        if (!$asset) {
+            return $this;
+        }
+
         $args = func_get_args();
 
         // More than one asset
@@ -198,7 +202,8 @@ class Assets extends PropertyObject
             call_user_func_array([$this, 'add'], $args);
         } else {
             // Get extension
-            $extension = Utils::pathinfo(parse_url($asset, PHP_URL_PATH), PATHINFO_EXTENSION);
+            $path = parse_url($asset, PHP_URL_PATH);
+            $extension = $path ? Utils::pathinfo($path, PATHINFO_EXTENSION) : '';
 
             // JavaScript or CSS
             if ($extension !== '') {
@@ -525,8 +530,8 @@ class Assets extends PropertyObject
     /**
      * Build the Javascript Modules tags
      *
-     * @param $group
-     * @param $attributes
+     * @param string $group
+     * @param array $attributes
      * @return string
      */
     public function jsModule($group = 'head', $attributes = [])
@@ -534,6 +539,11 @@ class Assets extends PropertyObject
         return $this->render(self::JS_MODULE, $group, $attributes);
     }
 
+    /**
+     * @param string $group
+     * @param array $attributes
+     * @return string
+     */
     public function all($group = 'head', $attributes = [])
     {
         $output = $this->css($group, $attributes, false);
@@ -543,11 +553,19 @@ class Assets extends PropertyObject
         return $output;
     }
 
+    /**
+     * @param class-string $type
+     * @return bool
+     */
     protected function isValidType($type)
     {
         return in_array($type, [self::CSS_TYPE, self::JS_TYPE, self::JS_MODULE_TYPE]);
     }
 
+    /**
+     * @param class-string $type
+     * @return string
+     */
     protected function getBaseType($type)
     {
         switch ($type) {

+ 1 - 1
system/src/Grav/Common/Assets/BlockAssets.php

@@ -55,7 +55,7 @@ class BlockAssets
 
     /**
      * @param Assets $assets
-     * @param array $groups
+     * @param array $list
      * @return void
      */
     protected static function registerFrameworks(Assets $assets, array $list): void

+ 1 - 1
system/src/Grav/Common/Backup/Backups.php

@@ -104,7 +104,7 @@ class Backups
      */
     public function getBackupDownloadUrl($backup, $base_url)
     {
-        $param_sep = $param_sep = Grav::instance()['config']->get('system.param_sep', ':');
+        $param_sep = Grav::instance()['config']->get('system.param_sep', ':');
         $download = urlencode(base64_encode(Utils::basename($backup)));
         $url      = rtrim(Grav::instance()['uri']->rootUrl(true), '/') . '/' . trim(
             $base_url,

+ 5 - 1
system/src/Grav/Common/Flex/Types/Pages/PageIndex.php

@@ -606,8 +606,10 @@ class PageIndex extends FlexPageIndex implements PageCollectionInterface
                 }
             }
 
+            /** @var PageCollection|PageIndex $children */
+            $children = $page->children();
             /** @var PageIndex $children */
-            $children = $page->children()->getIndex();
+            $children = $children->getIndex();
             $selectedChildren = $children->filterBy($filters, true);
 
             /** @var Header $header */
@@ -686,6 +688,8 @@ class PageIndex extends FlexPageIndex implements PageCollectionInterface
                     $extras = array_filter($extras, static function ($v) {
                         return $v !== null;
                     });
+
+                    /** @var PageIndex $tmp */
                     $tmp = $child->children()->getIndex();
                     $child_count = $tmp->count();
                     $count = $filters ? $tmp->filterBy($filters, true)->count() : null;

+ 8 - 1
system/src/Grav/Common/Flex/Types/Pages/PageObject.php

@@ -625,7 +625,14 @@ class PageObject extends FlexPageObject
 
             // If current filter does not match, we still may have match as a parent.
             if ($matches === false) {
-                return $recursive && $this->children()->getIndex()->filterBy($filters, true)->count() > 0;
+                if (!$recursive) {
+                    return false;
+                }
+
+                /** @var PageIndex $index */
+                $index = $this->children()->getIndex();
+
+                return $index->filterBy($filters, true)->count() > 0;
             }
         }
 

+ 1 - 1
system/src/Grav/Common/Flex/Types/Users/UserObject.php

@@ -666,7 +666,7 @@ class UserObject extends FlexObject implements UserInterface, Countable
         // Check for shared media
         if (!$folder && !$this->getFlexDirectory()->getMediaFolder()) {
             $this->_loadMedia = false;
-            $folder = $this->getBlueprint()->fields()['avatar']['destination'] ?? 'user://accounts/avatars';
+            $folder = $this->getBlueprint()->fields()['avatar']['destination'] ?? 'account://avatars';
         }
 
         return $folder;

+ 6 - 2
system/src/Grav/Common/Grav.php

@@ -62,6 +62,7 @@ use function call_user_func_array;
 use function function_exists;
 use function get_class;
 use function in_array;
+use function is_array;
 use function is_callable;
 use function is_int;
 use function is_string;
@@ -729,14 +730,17 @@ class Grav extends Container
      */
     public function fallbackUrl($path)
     {
+        $path_parts = Utils::pathinfo($path);
+        if (!is_array($path_parts)) {
+            return false;
+        }
+
         /** @var Uri $uri */
         $uri = $this['uri'];
 
         /** @var Config $config */
         $config = $this['config'];
 
-        $path_parts = Utils::pathinfo($path);
-
         /** @var Pages $pages */
         $pages = $this['pages'];
         $page = $pages->find($path_parts['dirname'], true);

+ 2 - 0
system/src/Grav/Common/Media/Interfaces/MediaObjectInterface.php

@@ -16,6 +16,8 @@ use Grav\Common\Data\Data;
  * Class implements media object interface.
  *
  * @property string $type
+ * @property string $filename
+ * @property string $filepath
  */
 interface MediaObjectInterface extends \Grav\Framework\Media\Interfaces\MediaObjectInterface, ArrayAccess
 {

+ 5 - 5
system/src/Grav/Common/Media/Traits/MediaPlayerTrait.php

@@ -25,7 +25,7 @@ trait MediaPlayerTrait
     public function controls($status = true)
     {
         if ($status) {
-            $this->attributes['controls'] = true;
+            $this->attributes['controls'] = 'controls';
         } else {
             unset($this->attributes['controls']);
         }
@@ -42,7 +42,7 @@ trait MediaPlayerTrait
     public function loop($status = false)
     {
         if ($status) {
-            $this->attributes['loop'] = true;
+            $this->attributes['loop'] = 'loop';
         } else {
             unset($this->attributes['loop']);
         }
@@ -59,7 +59,7 @@ trait MediaPlayerTrait
     public function autoplay($status = false)
     {
         if ($status) {
-            $this->attributes['autoplay'] = true;
+            $this->attributes['autoplay'] = 'autoplay';
         } else {
             unset($this->attributes['autoplay']);
         }
@@ -76,7 +76,7 @@ trait MediaPlayerTrait
     public function muted($status = false)
     {
         if ($status) {
-            $this->attributes['muted'] = true;
+            $this->attributes['muted'] = 'muted';
         } else {
             unset($this->attributes['muted']);
         }
@@ -108,6 +108,6 @@ trait MediaPlayerTrait
      */
     public function resetPlayer()
     {
-        $this->attributes['controls'] = true;
+        $this->attributes['controls'] = 'controls';
     }
 }

+ 4 - 0
system/src/Grav/Common/Media/Traits/MediaUploadTrait.php

@@ -100,6 +100,10 @@ trait MediaUploadTrait
             'size' => $uploadedFile->getSize(),
         ];
 
+        if ($uploadedFile instanceof FormFlashFile) {
+            $uploadedFile->checkXss();
+        }
+
         return $this->checkFileMetadata($metadata, $filename, $settings);
     }
 

+ 1 - 1
system/src/Grav/Common/Media/Traits/VideoMediaTrait.php

@@ -40,7 +40,7 @@ trait VideoMediaTrait
     public function playsinline($status = false)
     {
         if ($status) {
-            $this->attributes['playsinline'] = true;
+            $this->attributes['playsinline'] = 'playsinline';
         } else {
             unset($this->attributes['playsinline']);
         }

+ 2 - 1
system/src/Grav/Common/Page/Medium/MediumFactory.php

@@ -159,8 +159,9 @@ class MediumFactory
                 return new ImageMedium($items, $blueprint);
             case 'thumbnail':
                 return new ThumbnailImageMedium($items, $blueprint);
-            case 'animated':
             case 'vector':
+                return new VectorImageMedium($items, $blueprint);
+            case 'animated':
                 return new StaticImageMedium($items, $blueprint);
             case 'video':
                 return new VideoMedium($items, $blueprint);

+ 68 - 0
system/src/Grav/Common/Page/Medium/VectorImageMedium.php

@@ -0,0 +1,68 @@
+<?php
+
+/**
+ * @package    Grav\Common\Page
+ *
+ * @copyright  Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved.
+ * @license    MIT License; see LICENSE file for details.
+ */
+
+namespace Grav\Common\Page\Medium;
+
+use Grav\Common\Data\Blueprint;
+
+
+/**
+ * Class StaticImageMedium
+ * @package Grav\Common\Page\Medium
+ */
+class VectorImageMedium extends StaticImageMedium
+{
+    /**
+     * Construct.
+     *
+     * @param array $items
+     * @param Blueprint|null $blueprint
+     */
+    public function __construct($items = [], Blueprint $blueprint = null)
+    {
+        parent::__construct($items, $blueprint);
+
+        // If we already have the image size, we do not need to do anything else.
+        $width = $this->get('width');
+        $height = $this->get('height');
+        if ($width && $height) {
+            return;
+        }
+
+        // Make sure that getting image size is supported.
+        if ($this->mime !== 'image/svg+xml' || !\extension_loaded('simplexml')) {
+            return;
+        }
+
+        // Make sure that the image exists.
+        $path = $this->get('filepath');
+        if (!$path || !file_exists($path) || !filesize($path)) {
+            return;
+        }
+
+        $xml = simplexml_load_string(file_get_contents($path));
+        $attr = $xml ? $xml->attributes() : null;
+        if (!$attr instanceof \SimpleXMLElement) {
+            return;
+        }
+
+        // Get the size from svg image.
+        if ($attr->width && $attr->height) {
+            $width = (string)$attr->width;
+            $height = (string)$attr->height;
+        } elseif ($attr->viewBox && \count($size = explode(' ', (string)$attr->viewBox)) === 4) {
+            [,$width,$height,] = $size;
+        }
+
+        if ($width && $height) {
+            $this->def('width', (int)$width);
+            $this->def('height', (int)$height);
+        }
+    }
+}

+ 15 - 4
system/src/Grav/Common/Page/Pages.php

@@ -736,7 +736,13 @@ class Pages
                 break;
             case 'siblings':
                 $parent = $page->parent();
-                $collection = $parent ? $parent->children()->remove($page->path()) : new Collection();
+                if ($parent) {
+                    /** @var Collection $collection */
+                    $collection = $parent->children();
+                    $collection = $collection->remove($page->path());
+                } else {
+                    $collection = new Collection();
+                }
                 break;
             case 'descendants':
                 $collection = $this->all($page)->remove($page->path())->pages();
@@ -1041,9 +1047,14 @@ class Pages
                     $this->grav->redirectLangSafe($page->redirect());
                 }
 
-                if (!$routable && ($child = $page->children()->visible()->routable()->published()->first()) !== null) {
-                    // Redirect to the first visible child as current page isn't routable.
-                    $this->grav->redirectLangSafe($child->route());
+                if (!$routable) {
+                    /** @var Collection $children */
+                    $children = $page->children()->visible()->routable()->published();
+                    $child = $children->first();
+                    if ($child !== null) {
+                        // Redirect to the first visible child as current page isn't routable.
+                        $this->grav->redirectLangSafe($child->route());
+                    }
                 }
             }
 

+ 17 - 1
system/src/Grav/Common/Security.php

@@ -25,6 +25,22 @@ use function is_string;
  */
 class Security
 {
+    /**
+     * @param string $filepath
+     * @param array|null $options
+     * @return string|null
+     */
+    public static function detectXssFromSvgFile(string $filepath, array $options = null): ?string
+    {
+        if (file_exists($filepath) && Grav::instance()['config']->get('security.sanitize_svg')) {
+            $content = file_get_contents($filepath);
+
+            return static::detectXss($content, $options);
+        }
+
+        return null;
+    }
+
     /**
      * Sanitize SVG string for XSS code
      *
@@ -200,7 +216,7 @@ class Security
         }, $string);
 
         // Clean up entities
-        $string = preg_replace('!(&#0+[0-9]+)!u', '$1;', $string);
+        $string = preg_replace('!(&#[0-9]+);?!u', '$1;', $string);
 
         // Decode entities
         $string = html_entity_decode($string, ENT_NOQUOTES | ENT_HTML5, 'UTF-8');

+ 8 - 2
system/src/Grav/Common/Twig/TwigEnvironment.php

@@ -11,6 +11,8 @@ namespace Grav\Common\Twig;
 
 use Twig\Environment;
 use Twig\Error\LoaderError;
+use Twig\Loader\ExistsLoaderInterface;
+use Twig\Loader\LoaderInterface;
 use Twig\Template;
 use Twig\TemplateWrapper;
 
@@ -41,8 +43,12 @@ class TwigEnvironment extends Environment
             }
 
             // Optimization: Avoid throwing an exception when it would be ignored anyway.
-            if (1 !== $count && !$this->getLoader()->exists($name)) {
-                continue;
+            if (1 !== $count) {
+                /** @var LoaderInterface|ExistsLoaderInterface $loader */
+                $loader = $this->getLoader();
+                if (!$loader->exists($name)) {
+                    continue;
+                }
             }
 
             // Throws LoaderError: Unable to find template "%s".

+ 1 - 1
system/src/Grav/Common/User/DataUser/User.php

@@ -193,7 +193,7 @@ class User extends Data implements UserInterface
      */
     public function getMediaFolder()
     {
-        return $this->blueprints()->fields()['avatar']['destination'] ?? 'user://accounts/avatars';
+        return $this->blueprints()->fields()['avatar']['destination'] ?? 'account://avatars';
     }
 
     /**

+ 48 - 2
system/src/Grav/Common/User/Traits/UserTrait.php

@@ -9,12 +9,15 @@
 
 namespace Grav\Common\User\Traits;
 
+use Grav\Common\Filesystem\Folder;
 use Grav\Common\Grav;
 use Grav\Common\Page\Medium\ImageMedium;
 use Grav\Common\Page\Medium\Medium;
 use Grav\Common\Page\Medium\StaticImageMedium;
 use Grav\Common\User\Authentication;
 use Grav\Common\Utils;
+use Multiavatar;
+use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
 use function is_array;
 use function is_string;
 
@@ -175,9 +178,52 @@ trait UserTrait
         }
 
         $email = $this->get('email');
+        $avatar_generator = Grav::instance()['config']->get('system.accounts.avatar', 'multiavatar');
+        if ($avatar_generator === 'gravatar') {
+            if (!$email) {
+                return '';
+            }
+
+            $hash = md5(strtolower(trim($email)));
+
+            return 'https://www.gravatar.com/avatar/' . $hash;
+        }
+
+        $hash = $this->get('avatar_hash');
+        if (!$hash) {
+            $username = $this->get('username');
+            $hash = md5(strtolower(trim($email ?? $username)));
+        }
+
+        return $this->generateMultiavatar($hash);
+    }
+
+    /**
+     * @param string $hash
+     * @return string
+     */
+    protected function generateMultiavatar(string $hash): string
+    {
+        /** @var UniformResourceLocator $locator */
+        $locator = Grav::instance()['locator'];
+
+        $storage = $locator->findResource('image://multiavatar', true, true);
+        $avatar_file = "{$storage}/{$hash}.svg";
+
+        if (!file_exists($storage)) {
+            Folder::create($storage);
+        }
+
+        if (!file_exists($avatar_file)) {
+            $mavatar = new Multiavatar();
+
+            file_put_contents($avatar_file, $mavatar->generate($hash, null, null));
+        }
+
+        $avatar_url = $locator->findResource("image://multiavatar/{$hash}.svg", false, true);
+
+        return Utils::url($avatar_url);
 
-        // By default fall back to gravatar image.
-        return $email ? 'https://www.gravatar.com/avatar/' . md5(strtolower(trim($email))) : '';
     }
 
     abstract public function get($name, $default = null, $separator = null);

+ 6 - 7
system/src/Grav/Common/Utils.php

@@ -134,14 +134,13 @@ abstract class Utils
                 $resource = $locator->findResource($input, false);
             }
         } else {
-            $root = $uri->rootUrl();
-
-            if (static::startsWith($input, $root)) {
-                $input = static::replaceFirstOccurrence($root, '', $input);
+            $root = preg_quote($uri->rootUrl(), '#');
+            $pattern = '#(' . $root . '$|' . $root . '/)#';
+            if (!empty($root) && preg_match($pattern, $input, $matches)) {
+                $input = static::replaceFirstOccurrence($matches[0], '', $input);
             }
 
             $input = ltrim($input, '/');
-
             $resource = $input;
         }
 
@@ -994,7 +993,7 @@ abstract class Utils
      * @param int|null $flags
      * @return array|string
      */
-    public static function pathinfo(string $path, int $flags = null)
+    public static function pathinfo($path, int $flags = null)
     {
         $path = str_replace(['%2F', '%5C'], ['/', '\\'], rawurlencode($path));
 
@@ -1020,7 +1019,7 @@ abstract class Utils
      * @param string $suffix
      * @return string
      */
-    public static function basename(string $path, string $suffix = ''): string
+    public static function basename($path, string $suffix = ''): string
     {
         return rawurldecode(basename(str_replace(['%2F', '%5C'], '/', rawurlencode($path)), $suffix));
     }

+ 17 - 0
system/src/Grav/Framework/Form/FormFlashFile.php

@@ -9,6 +9,8 @@
 
 namespace Grav\Framework\Form;
 
+use Grav\Common\Security;
+use Grav\Common\Utils;
 use Grav\Framework\Psr7\Stream;
 use InvalidArgumentException;
 use JsonSerializable;
@@ -182,6 +184,21 @@ class FormFlashFile implements UploadedFileInterface, JsonSerializable
         return $this->upload;
     }
 
+    /**
+     * @return void
+     */
+    public function checkXss(): void
+    {
+        $tmpFile = $this->getTmpFile();
+        $mime = $this->getClientMediaType();
+        if (Utils::contains($mime, 'svg', false)) {
+            $response = Security::detectXssFromSvgFile($tmpFile);
+            if ($response) {
+                throw new RuntimeException(sprintf('SVG file XSS check failed on %s', $response));
+            }
+        }
+    }
+
     /**
      * @return string|null
      */

+ 5 - 1
system/src/Grav/Framework/Form/Traits/FormTrait.php

@@ -23,6 +23,7 @@ use Grav\Common\User\Interfaces\UserInterface;
 use Grav\Common\Utils;
 use Grav\Framework\Compat\Serializable;
 use Grav\Framework\ContentBlock\HtmlBlock;
+use Grav\Framework\Form\FormFlashFile;
 use Grav\Framework\Form\Interfaces\FormFlashInterface;
 use Grav\Framework\Form\Interfaces\FormInterface;
 use Grav\Framework\Session\SessionInterface;
@@ -775,13 +776,16 @@ trait FormTrait
     {
         // Handle bad filenames.
         $filename = $file->getClientFilename();
-
         if ($filename && !Utils::checkFilename($filename)) {
             $grav = Grav::instance();
             throw new RuntimeException(
                 sprintf($grav['language']->translate('PLUGIN_FORM.FILEUPLOAD_UNABLE_TO_UPLOAD', null, true), $filename, 'Bad filename')
             );
         }
+
+        if ($file instanceof FormFlashFile) {
+            $file->checkXss();
+        }
     }
 
     /**

Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff