corrections de problèmes de liens inter articles et de display du about
This commit is contained in:
@@ -1300,6 +1300,17 @@ form:
|
||||
auto: Auto
|
||||
lazy: Lazy
|
||||
eager: Eager
|
||||
|
||||
images.defaults.decoding:
|
||||
type: select
|
||||
size: small
|
||||
label: PLUGIN_ADMIN.IMAGES_DECODING
|
||||
help: PLUGIN_ADMIN.IMAGES_DECODING_HELP
|
||||
highlight: auto
|
||||
options:
|
||||
auto: Auto
|
||||
sync: Sync
|
||||
async: Async
|
||||
|
||||
images.seofriendly:
|
||||
type: toggle
|
||||
|
@@ -168,6 +168,7 @@ images:
|
||||
retina_scale: 1 # scale to adjust auto-sizes for better handling of HiDPI resolutions
|
||||
defaults:
|
||||
loading: auto # Let browser pick [auto|lazy|eager]
|
||||
decoding: auto # Let browser pick [auto|sync|async]
|
||||
watermark:
|
||||
image: 'system://images/watermark.png' # Path to a watermark image
|
||||
position_y: 'center' # top|center|bottom
|
||||
|
@@ -9,7 +9,7 @@
|
||||
|
||||
// Some standard defines
|
||||
define('GRAV', true);
|
||||
define('GRAV_VERSION', '1.7.44');
|
||||
define('GRAV_VERSION', '1.7.46');
|
||||
define('GRAV_SCHEMA', '1.7.0_2020-11-20_1');
|
||||
define('GRAV_TESTING', false);
|
||||
|
||||
@@ -26,12 +26,12 @@ if (!defined('DS')) {
|
||||
// Absolute path to Grav root. This is where Grav is installed into.
|
||||
if (!defined('GRAV_ROOT')) {
|
||||
$path = rtrim(str_replace(DIRECTORY_SEPARATOR, DS, getenv('GRAV_ROOT') ?: getcwd()), DS);
|
||||
define('GRAV_ROOT', $path);
|
||||
define('GRAV_ROOT', $path ?: DS);
|
||||
}
|
||||
// Absolute path to Grav webroot. This is the path where your site is located in.
|
||||
if (!defined('GRAV_WEBROOT')) {
|
||||
$path = rtrim(getenv('GRAV_WEBROOT') ?: GRAV_ROOT, DS);
|
||||
define('GRAV_WEBROOT', $path);
|
||||
define('GRAV_WEBROOT', $path ?: DS);
|
||||
}
|
||||
// Relative path to user folder. This path needs to be located under GRAV_WEBROOT.
|
||||
if (!defined('GRAV_USER_PATH')) {
|
||||
|
@@ -104,6 +104,7 @@ GRAV:
|
||||
VALIDATION_FAIL: '<b>Провера неуспела:</b>'
|
||||
INVALID_INPUT: 'Неисправан унос у'
|
||||
MISSING_REQUIRED_FIELD: 'Недостаје обавезн поље:'
|
||||
XSS_ISSUES: "Потенцијална грешка у XSS-у детектована у пољу '%s' "
|
||||
MONTHS_OF_THE_YEAR:
|
||||
- 'Јануар'
|
||||
- 'Фебруар'
|
||||
@@ -125,6 +126,8 @@ GRAV:
|
||||
- 'Петак'
|
||||
- 'Субота'
|
||||
- 'Недеља'
|
||||
YES: "Да"
|
||||
NO: "Не"
|
||||
CRON:
|
||||
EVERY: сваки
|
||||
EVERY_HOUR: сваки сат
|
||||
|
@@ -218,7 +218,7 @@ class Backups
|
||||
if ($locator->isStream($backup_root)) {
|
||||
$backup_root = $locator->findResource($backup_root);
|
||||
} else {
|
||||
$backup_root = rtrim(GRAV_ROOT . $backup_root, '/');
|
||||
$backup_root = rtrim(GRAV_ROOT . $backup_root, DS) ?: DS;
|
||||
}
|
||||
|
||||
if (!$backup_root || !file_exists($backup_root)) {
|
||||
|
@@ -161,9 +161,15 @@ class Inflector
|
||||
*/
|
||||
public static function titleize($word, $uppercase = '')
|
||||
{
|
||||
$uppercase = $uppercase === 'first' ? 'ucfirst' : 'ucwords';
|
||||
$humanize_underscorize = static::humanize(static::underscorize($word));
|
||||
|
||||
if ($uppercase === 'first') {
|
||||
$firstLetter = mb_strtoupper(mb_substr($humanize_underscorize, 0, 1, "UTF-8"), "UTF-8");
|
||||
return $firstLetter . mb_substr($humanize_underscorize, 1, mb_strlen($humanize_underscorize, "UTF-8"), "UTF-8");
|
||||
} else {
|
||||
return mb_convert_case($humanize_underscorize, MB_CASE_TITLE, 'UTF-8');
|
||||
}
|
||||
|
||||
return $uppercase(static::humanize(static::underscorize($word)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -180,7 +186,7 @@ class Inflector
|
||||
*/
|
||||
public static function camelize($word)
|
||||
{
|
||||
return str_replace(' ', '', ucwords(preg_replace('/[^A-Z^a-z^0-9]+/', ' ', $word)));
|
||||
return str_replace(' ', '', ucwords(preg_replace('/[^\p{L}^0-9]+/', ' ', $word)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -198,7 +204,7 @@ class Inflector
|
||||
{
|
||||
$regex1 = preg_replace('/([A-Z]+)([A-Z][a-z])/', '\1_\2', $word);
|
||||
$regex2 = preg_replace('/([a-zd])([A-Z])/', '\1_\2', $regex1);
|
||||
$regex3 = preg_replace('/[^A-Z^a-z^0-9]+/', '_', $regex2);
|
||||
$regex3 = preg_replace('/[^\p{L}^0-9]+/u', '_', $regex2);
|
||||
|
||||
return strtolower($regex3);
|
||||
}
|
||||
@@ -219,7 +225,7 @@ class Inflector
|
||||
$regex1 = preg_replace('/([A-Z]+)([A-Z][a-z])/', '\1-\2', $word);
|
||||
$regex2 = preg_replace('/([a-z])([A-Z])/', '\1-\2', $regex1);
|
||||
$regex3 = preg_replace('/([0-9])([A-Z])/', '\1-\2', $regex2);
|
||||
$regex4 = preg_replace('/[^A-Z^a-z^0-9]+/', '-', $regex3);
|
||||
$regex4 = preg_replace('/[^\p{L}^0-9]+/', '-', $regex3);
|
||||
|
||||
$regex4 = trim($regex4, '-');
|
||||
|
||||
|
40
system/src/Grav/Common/Media/Traits/ImageDecodingTrait.php
Normal file
40
system/src/Grav/Common/Media/Traits/ImageDecodingTrait.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Grav\Common\Media
|
||||
* @author Pedro Moreno https://github.com/pmoreno-rodriguez
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Common\Media\Traits;
|
||||
|
||||
use Grav\Common\Grav;
|
||||
|
||||
/**
|
||||
* Trait ImageDecodingTrait
|
||||
* @package Grav\Common\Media\Traits
|
||||
*/
|
||||
|
||||
trait ImageDecodingTrait
|
||||
{
|
||||
/**
|
||||
* Allows to set the decoding attribute from Markdown or Twig
|
||||
*
|
||||
* @param string|null $value
|
||||
* @return $this
|
||||
*/
|
||||
public function decoding($value = null)
|
||||
{
|
||||
if (null === $value) {
|
||||
$value = Grav::instance()['config']->get('system.images.defaults.decoding', 'auto');
|
||||
}
|
||||
|
||||
// Validate the provided value (similar to loading)
|
||||
if ($value !== null && $value !== 'auto') {
|
||||
$this->attributes['decoding'] = $value;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
@@ -156,7 +156,7 @@ trait MediaUploadTrait
|
||||
$filepath = $folder . $filename;
|
||||
|
||||
// Check if the filename is allowed.
|
||||
if (!Utils::checkFilename($filename)) {
|
||||
if (!Utils::checkFilename($filepath)) {
|
||||
throw new RuntimeException(
|
||||
sprintf($this->translate('PLUGIN_ADMIN.FILEUPLOAD_UNABLE_TO_UPLOAD'), $filepath, $this->translate('PLUGIN_ADMIN.BAD_FILENAME'))
|
||||
);
|
||||
|
@@ -15,6 +15,7 @@ use Grav\Common\Media\Interfaces\ImageManipulateInterface;
|
||||
use Grav\Common\Media\Interfaces\ImageMediaInterface;
|
||||
use Grav\Common\Media\Interfaces\MediaLinkInterface;
|
||||
use Grav\Common\Media\Traits\ImageLoadingTrait;
|
||||
use Grav\Common\Media\Traits\ImageDecodingTrait;
|
||||
use Grav\Common\Media\Traits\ImageMediaTrait;
|
||||
use Grav\Common\Utils;
|
||||
use Gregwar\Image\Image;
|
||||
@@ -30,6 +31,7 @@ class ImageMedium extends Medium implements ImageMediaInterface, ImageManipulate
|
||||
{
|
||||
use ImageMediaTrait;
|
||||
use ImageLoadingTrait;
|
||||
use ImageDecodingTrait;
|
||||
|
||||
/**
|
||||
* @var mixed|string
|
||||
|
@@ -225,7 +225,7 @@ class Security
|
||||
// Set the patterns we'll test against
|
||||
$patterns = [
|
||||
// Match any attribute starting with "on" or xmlns
|
||||
'on_events' => '#(<[^>]+[[a-z\x00-\x20\"\'\/])([\s\/]on|\sxmlns)[a-z].*=>?#iUu',
|
||||
'on_events' => '#(<[^>]+[a-z\x00-\x20\"\'\/])(on[a-z]+|xmlns)\s*=[\s|\'\"].*[\s|\'\"]>#iUu',
|
||||
|
||||
// Match javascript:, livescript:, vbscript:, mocha:, feed: and data: protocols
|
||||
'invalid_protocols' => '#(' . implode('|', array_map('preg_quote', $invalid_protocols, ['#'])) . ')(:|\&\#58)\S.*?#iUu',
|
||||
@@ -263,4 +263,25 @@ class Security
|
||||
'invalid_protocols' => array_map('trim', $config->get('security.xss_invalid_protocols')),
|
||||
];
|
||||
}
|
||||
|
||||
public static function cleanDangerousTwig(string $string): string
|
||||
{
|
||||
if ($string === '') {
|
||||
return $string;
|
||||
}
|
||||
|
||||
$bad_twig = [
|
||||
'twig_array_map',
|
||||
'twig_array_filter',
|
||||
'call_user_func',
|
||||
'registerUndefinedFunctionCallback',
|
||||
'undefined_functions',
|
||||
'twig.getFunction',
|
||||
'core.setEscaper',
|
||||
'twig.safe_functions',
|
||||
'read_file',
|
||||
];
|
||||
$string = preg_replace('/(({{\s*|{%\s*)[^}]*?(' . implode('|', $bad_twig) . ')[^}]*?(\s*}}|\s*%}))/i', '{# $1 #}', $string);
|
||||
return $string;
|
||||
}
|
||||
}
|
||||
|
@@ -10,6 +10,7 @@
|
||||
namespace Grav\Common;
|
||||
|
||||
use Grav\Common\Config\Config;
|
||||
use Grav\Common\Language\Language;
|
||||
use Grav\Common\Page\Collection;
|
||||
use Grav\Common\Page\Interfaces\PageInterface;
|
||||
use function is_string;
|
||||
@@ -37,6 +38,8 @@ class Taxonomy
|
||||
protected $taxonomy_map;
|
||||
/** @var Grav */
|
||||
protected $grav;
|
||||
/** @var Language */
|
||||
protected $language;
|
||||
|
||||
/**
|
||||
* Constructor that resets the map
|
||||
@@ -45,8 +48,9 @@ class Taxonomy
|
||||
*/
|
||||
public function __construct(Grav $grav)
|
||||
{
|
||||
$this->taxonomy_map = [];
|
||||
$this->grav = $grav;
|
||||
$this->language = $grav['language'];
|
||||
$this->taxonomy_map[$this->language->getLanguage()] = [];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -107,7 +111,8 @@ class Taxonomy
|
||||
if (!empty($key)) {
|
||||
$taxonomy .= $key;
|
||||
}
|
||||
$this->taxonomy_map[$taxonomy][(string) $value][$page->path()] = ['slug' => $page->slug()];
|
||||
$active = $this->language->getLanguage();
|
||||
$this->taxonomy_map[$active][$taxonomy][(string) $value][$page->path()] = ['slug' => $page->slug()];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,14 +128,11 @@ class Taxonomy
|
||||
{
|
||||
$matches = [];
|
||||
$results = [];
|
||||
$active = $this->language->getLanguage();
|
||||
|
||||
foreach ((array)$taxonomies as $taxonomy => $items) {
|
||||
foreach ((array)$items as $item) {
|
||||
if (isset($this->taxonomy_map[$taxonomy][$item])) {
|
||||
$matches[] = $this->taxonomy_map[$taxonomy][$item];
|
||||
} else {
|
||||
$matches[] = [];
|
||||
}
|
||||
$matches[] = $this->taxonomy_map[$active][$taxonomy][$item] ?? [];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,11 +158,13 @@ class Taxonomy
|
||||
*/
|
||||
public function taxonomy($var = null)
|
||||
{
|
||||
$active = $this->language->getLanguage();
|
||||
|
||||
if ($var) {
|
||||
$this->taxonomy_map = $var;
|
||||
$this->taxonomy_map[$active] = $var;
|
||||
}
|
||||
|
||||
return $this->taxonomy_map;
|
||||
return $this->taxonomy_map[$active] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -171,6 +175,7 @@ class Taxonomy
|
||||
*/
|
||||
public function getTaxonomyItemKeys($taxonomy)
|
||||
{
|
||||
return isset($this->taxonomy_map[$taxonomy]) ? array_keys($this->taxonomy_map[$taxonomy]) : [];
|
||||
$active = $this->language->getLanguage();
|
||||
return isset($this->taxonomy_map[$active][$taxonomy]) ? array_keys($this->taxonomy_map[$active][$taxonomy]) : [];
|
||||
}
|
||||
}
|
||||
|
@@ -16,6 +16,7 @@ use Grav\Common\Language\Language;
|
||||
use Grav\Common\Language\LanguageCodes;
|
||||
use Grav\Common\Page\Interfaces\PageInterface;
|
||||
use Grav\Common\Page\Pages;
|
||||
use Grav\Common\Security;
|
||||
use Grav\Common\Twig\Exception\TwigException;
|
||||
use Grav\Common\Twig\Extension\FilesystemExtension;
|
||||
use Grav\Common\Twig\Extension\GravExtension;
|
||||
@@ -319,6 +320,7 @@ class Twig
|
||||
public function processPage(PageInterface $item, $content = null)
|
||||
{
|
||||
$content = $content ?? $item->content();
|
||||
$content = Security::cleanDangerousTwig($content);
|
||||
|
||||
// override the twig header vars for local resolution
|
||||
$this->grav->fireEvent('onTwigPageVariables', new Event(['page' => $item]));
|
||||
@@ -392,6 +394,8 @@ class Twig
|
||||
$this->grav->fireEvent('onTwigStringVariables');
|
||||
$vars += $this->twig_vars;
|
||||
|
||||
$string = Security::cleanDangerousTwig($string);
|
||||
|
||||
$name = '@Var:' . $string;
|
||||
$this->setTemplate($name, $string);
|
||||
|
||||
@@ -418,7 +422,7 @@ class Twig
|
||||
try {
|
||||
$grav = $this->grav;
|
||||
|
||||
// set the page now its been processed
|
||||
// set the page now it's been processed
|
||||
$grav->fireEvent('onTwigSiteVariables');
|
||||
|
||||
/** @var Pages $pages */
|
||||
@@ -427,13 +431,15 @@ class Twig
|
||||
/** @var PageInterface $page */
|
||||
$page = $grav['page'];
|
||||
|
||||
$content = Security::cleanDangerousTwig($page->content());
|
||||
|
||||
$twig_vars = $this->twig_vars;
|
||||
$twig_vars['theme'] = $grav['config']->get('theme');
|
||||
$twig_vars['pages'] = $pages->root();
|
||||
$twig_vars['page'] = $page;
|
||||
$twig_vars['header'] = $page->header();
|
||||
$twig_vars['media'] = $page->media();
|
||||
$twig_vars['content'] = $page->content();
|
||||
$twig_vars['content'] = $content;
|
||||
|
||||
// determine if params are set, if so disable twig cache
|
||||
$params = $grav['uri']->params(null, true);
|
||||
@@ -568,4 +574,5 @@ class Twig
|
||||
|
||||
$this->autoescape = (bool) $state;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -206,7 +206,7 @@ class Uri
|
||||
$uri = $language->setActiveFromUri($uri);
|
||||
|
||||
// split the URL and params (and make sure that the path isn't seen as domain)
|
||||
$bits = parse_url('http://domain.com' . $uri);
|
||||
$bits = static::parseUrl('http://domain.com' . $uri);
|
||||
|
||||
//process fragment
|
||||
if (isset($bits['fragment'])) {
|
||||
@@ -265,6 +265,7 @@ class Uri
|
||||
return $this->paths;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return route to the current URI. By default route doesn't include base path.
|
||||
*
|
||||
@@ -742,7 +743,7 @@ class Uri
|
||||
*/
|
||||
public static function isExternal($url)
|
||||
{
|
||||
return (0 === strpos($url, 'http://') || 0 === strpos($url, 'https://') || 0 === strpos($url, '//'));
|
||||
return (0 === strpos($url, 'http://') || 0 === strpos($url, 'https://') || 0 === strpos($url, '//') || 0 === strpos($url, 'mailto:') || 0 === strpos($url, 'tel:') || 0 === strpos($url, 'ftp://') || 0 === strpos($url, 'ftps://') || 0 === strpos($url, 'news:') || 0 === strpos($url, 'irc:') || 0 === strpos($url, 'gopher:') || 0 === strpos($url, 'nntp:') || 0 === strpos($url, 'feed:') || 0 === strpos($url, 'cvs:') || 0 === strpos($url, 'ssh:') || 0 === strpos($url, 'git:') || 0 === strpos($url, 'svn:') || 0 === strpos($url, 'hg:'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -954,9 +955,7 @@ class Uri
|
||||
$grav = Grav::instance();
|
||||
|
||||
// Remove extra slash from streams, parse_url() doesn't like it.
|
||||
if ($pos = strpos($url, ':///')) {
|
||||
$url = substr_replace($url, '://', $pos, 4);
|
||||
}
|
||||
$url = preg_replace('/([^:])(\/{2,})/', '$1/', $url);
|
||||
|
||||
$encodedUrl = preg_replace_callback(
|
||||
'%[^:/@?&=#]+%usD',
|
||||
|
@@ -989,6 +989,8 @@ abstract class Utils
|
||||
|| strtr($filename, "\t\v\n\r\0\\/", '_______') !== $filename
|
||||
// Filename should not start or end with dot or space.
|
||||
|| trim($filename, '. ') !== $filename
|
||||
// Filename should not contain path traversal
|
||||
|| str_replace('..', '', $filename) !== $filename
|
||||
// File extension should not be part of configured dangerous extensions
|
||||
|| in_array($extension, $dangerous_extensions)
|
||||
);
|
||||
@@ -1330,7 +1332,11 @@ abstract class Utils
|
||||
if ($dateformat) {
|
||||
$datetime = DateTime::createFromFormat($dateformat, $date);
|
||||
} else {
|
||||
$datetime = new DateTime($date);
|
||||
try {
|
||||
$datetime = new DateTime($date);
|
||||
} catch (Exception $e) {
|
||||
$datetime = false;
|
||||
}
|
||||
}
|
||||
|
||||
// fallback to strtotime() if DateTime approach failed
|
||||
|
0
system/src/Twig/DeferredExtension/DeferredBlockNode.php
Executable file → Normal file
0
system/src/Twig/DeferredExtension/DeferredBlockNode.php
Executable file → Normal file
0
system/src/Twig/DeferredExtension/DeferredNode.php
Executable file → Normal file
0
system/src/Twig/DeferredExtension/DeferredNode.php
Executable file → Normal file
Reference in New Issue
Block a user