From c5314dd86d6560865670940b59ac0fbb97225bb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Anne?= Date: Tue, 26 Feb 2019 13:46:06 +0100 Subject: [PATCH 01/10] Fix chevrons display in select2 rendering --- inc/html.class.php | 10 ++++++++++ js/common.js | 16 ++++++++++++---- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/inc/html.class.php b/inc/html.class.php index 760ffe164b..e5907c8d5b 100644 --- a/inc/html.class.php +++ b/inc/html.class.php @@ -4329,6 +4329,11 @@ static function jsAdaptDropdown($id, $params = []) { if (typeof data.text === 'string' && data.text.toUpperCase().indexOf(params.term.toUpperCase()) >= 0 ) { + if (data.text.indexOf('>') !== -1 || data.text.indexOf('<') !== -1) { + // escape text, if it contains chevrons (can already be escaped prior to this point :/) + data.text = jQuery.fn.select2.defaults.defaults.escapeMarkup(data.text); + } + return data; } return null; @@ -4341,6 +4346,11 @@ static function jsAdaptDropdown($id, $params = []) { if (child.text.toUpperCase().indexOf(params.term.toUpperCase()) != -1 || data.text.toUpperCase().indexOf(params.term.toUpperCase()) != -1 ) { + + if (child.text.indexOf('>') !== -1 || child.text.indexOf('<') !== -1) { + // escape text, if it contains chevrons (can already be escaped prior to this point :/) + child.text = jQuery.fn.select2.defaults.defaults.escapeMarkup(child.text); + } filteredChildren.push(child); } }); diff --git a/js/common.js b/js/common.js index c08623434c..15cf04b200 100644 --- a/js/common.js +++ b/js/common.js @@ -948,17 +948,25 @@ function markMatch (text, term) { * Function that renders select2 results. */ var templateResult = function(result) { - if (!result.id) { - return result.text; + if (!result.text) { + return null; } var _elt = $(''); _elt.attr('title', result.title); - var markup=[result.text]; + var text = result.text; + if (text.indexOf('>') !== -1 || text.indexOf('<') !== -1) { + // escape text, if it contains chevrons (can already be escaped prior to this point :/) + text = jQuery.fn.select2.defaults.defaults.escapeMarkup(result.text); + }; + + if (!result.id) { + return text; + } var _term = query.term || ''; - var markup = markMatch(result.text, _term); + var markup = markMatch(text, _term); if (result.level) { var a=''; From 2c5d9f80f64a1f5ef4c62af8be5d24b812b75ecc Mon Sep 17 00:00:00 2001 From: Johan Cwiklinski Date: Tue, 5 Mar 2019 12:49:05 +0100 Subject: [PATCH 02/10] Disallow all on attributes --- inc/html.class.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/inc/html.class.php b/inc/html.class.php index e5907c8d5b..f9aa6532dd 100644 --- a/inc/html.class.php +++ b/inc/html.class.php @@ -3550,6 +3550,9 @@ static function initEditorSystem($name, $rand = '', $display = true, $readonly = // init editor tinyMCE.init({ language: '$language', + invalid_elements: 'form,iframe,script,@[onclick|ondblclick|' + + 'onmousedown|onmouseup|onmouseover|onmousemove|onmouseout|onkeypress|' + + 'onkeydown|onkeyup]', browser_spellcheck: true, mode: 'exact', elements: '$name', From a330e5b49f46680cf9fb877fdac7a6e44eff9115 Mon Sep 17 00:00:00 2001 From: Johan Cwiklinski Date: Mon, 4 Mar 2019 16:15:04 +0100 Subject: [PATCH 03/10] Strict check --- inc/auth.class.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/inc/auth.class.php b/inc/auth.class.php index 323b3b94a2..707d7ab314 100644 --- a/inc/auth.class.php +++ b/inc/auth.class.php @@ -276,14 +276,14 @@ static function checkPassword($pass, $hash) { $ok = password_verify($pass, $hash); } else if (strlen($hash)==32) { - $ok = md5($pass) == $hash; + $ok = md5($pass) === $hash; } else if (strlen($hash)==40) { - $ok = sha1($pass) == $hash; + $ok = sha1($pass) === $hash; } else { $salt = substr($hash, 0, 8); - $ok = ($salt.sha1($salt.$pass) == $hash); + $ok = ($salt.sha1($salt.$pass) === $hash); } return $ok; From f8959e587db32361c3013898c9f223a4151ada33 Mon Sep 17 00:00:00 2001 From: Johan Cwiklinski Date: Tue, 12 Mar 2019 14:44:53 +0100 Subject: [PATCH 04/10] Use exif if present to check if file is image, or fallback with W on fileinfo --- inc/config.class.php | 3 +++ inc/document.class.php | 13 +++++++++++-- tests/functionnal/Document.php | 20 +++++++------------- tests/notanimage.jpg | 3 +++ 4 files changed, 24 insertions(+), 15 deletions(-) create mode 100644 tests/notanimage.jpg diff --git a/inc/config.class.php b/inc/config.class.php index b648d53181..8797b5bd4c 100644 --- a/inc/config.class.php +++ b/inc/config.class.php @@ -2456,6 +2456,9 @@ static function checkExtensions($list = null) { 'CAS' => [ 'required' => false, 'class' => 'phpCAS' + ], + 'exif' => [ + 'required' => false ] ]; } else { diff --git a/inc/document.class.php b/inc/document.class.php index 8072dac9f2..faca1a93ee 100644 --- a/inc/document.class.php +++ b/inc/document.class.php @@ -1497,8 +1497,17 @@ static function getImageTag($string) { * @return boolean */ public static function isImage($file) { - $ext = strtolower(pathinfo($file, PATHINFO_EXTENSION)); - return (in_array($ext, ['jpg', 'jpeg', 'png', 'bmp', 'gif'])); + if (extension_loaded('exif')) { + $etype = exif_imagetype($file); + return in_array($etype, [IMAGETYPE_JPEG, IMAGETYPE_GIF, IMAGETYPE_PNG, IMAGETYPE_BMP]); + } else { + Toolbox::logWarning('For security reasons, you should consider using exif PHP extension to properly check images.'); + $fileinfo = finfo_open(FILEINFO_MIME_TYPE); + return in_array( + finfo_file($fileinfo, $file), + ['image/jpeg', 'image/png','image/gif', 'image/bmp'] + ); + } } /** diff --git a/tests/functionnal/Document.php b/tests/functionnal/Document.php index a00ca4b57f..1757ebc8e6 100644 --- a/tests/functionnal/Document.php +++ b/tests/functionnal/Document.php @@ -215,25 +215,19 @@ public function testGetImageTag() { protected function isImageProvider() { return [ - ['PNG', true], - ['png', true], - ['JPG', true], - ['jpg', true], - ['jpeg', true], - ['JPEG', true], - ['bmp', true], - ['BMP', true], - ['gif', true], - ['GIF', true], - ['SVG', false] + [__FILE__, false], + [__DIR__ . "/../../pics/add_dropdown.png", true], + [__DIR__ . "/../../pics/corners.gif", true], + [__DIR__ . "/../../pics/PICS-AUTHORS.txt", false], + [__DIR__ . "/../notanimage.jpg", false] ]; } /** * @dataProvider isImageProvider */ - public function testIsImage($ext, $expected) { - $this->variable(\Document::isImage('myfile.' . $ext))->isIdenticalTo($expected); + public function testIsImage($file, $expected) { + $this->boolean(\Document::isImage($file))->isIdenticalTo($expected); } /** diff --git a/tests/notanimage.jpg b/tests/notanimage.jpg new file mode 100644 index 0000000000..d2dbc0fe33 --- /dev/null +++ b/tests/notanimage.jpg @@ -0,0 +1,3 @@ + Date: Tue, 12 Mar 2019 10:59:54 +0100 Subject: [PATCH 05/10] Password token date was not removed --- inc/user.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/user.class.php b/inc/user.class.php index e6ebb3a88d..fdc9d8b0ac 100644 --- a/inc/user.class.php +++ b/inc/user.class.php @@ -4355,7 +4355,7 @@ public function updateForgottenPassword(array $input) { } $input2 = [ 'password_forget_token' => '', - 'password_forget_token_date' => null, + 'password_forget_token_date' => 'NULL', 'id' => $this->fields['id'] ]; $this->update($input2); From 1ae67932a3de9349fbe5f0cd4d10d9a81a811f9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Anne?= Date: Thu, 14 Mar 2019 17:22:48 +0100 Subject: [PATCH 06/10] Fix ITIL image path --- inc/ticket.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/ticket.class.php b/inc/ticket.class.php index b414f85583..c9608c84e9 100644 --- a/inc/ticket.class.php +++ b/inc/ticket.class.php @@ -7249,7 +7249,7 @@ function showTimeline($rand) { echo "$filename"; - if (Document::isImage($filename)) { + if (Document::isImage(GLPI_DOC_DIR . '/' . $item_i['filepath'])) { echo "
"; echo ""; From cc1e2b02288635a4692bef5d2a7598862eafa4d1 Mon Sep 17 00:00:00 2001 From: Johan Cwiklinski Date: Mon, 18 Mar 2019 19:27:04 +0100 Subject: [PATCH 08/10] Update security-checker --- composer.json | 2 +- composer.lock | 21 +++++++++++---------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/composer.json b/composer.json index d1c3ee858b..66f6b52643 100644 --- a/composer.json +++ b/composer.json @@ -43,7 +43,7 @@ "patchwork/jsqueeze": "^2.0", "atoum/atoum": "^3.3", "atoum/telemetry-extension": "^1.0", - "sensiolabs/security-checker": "^4.1", + "sensiolabs/security-checker": "^5.0", "fzaninotto/Faker": "^1.7", "jakub-onderka/php-parallel-lint": "^1.0" }, diff --git a/composer.lock b/composer.lock index 467f8ce42d..4ce22d532d 100644 --- a/composer.lock +++ b/composer.lock @@ -1,10 +1,10 @@ { "_readme": [ "This file locks the dependencies of your project to a known state", - "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "4db9a468fea5706b030e4b631a08b28a", + "content-hash": "57b9b4901479f79936d11b74f56ff761", "packages": [ { "name": "container-interop/container-interop", @@ -2769,20 +2769,21 @@ }, { "name": "sensiolabs/security-checker", - "version": "v4.1.8", + "version": "v5.0.3", "source": { "type": "git", "url": "https://github.com/sensiolabs/security-checker.git", - "reference": "dc270d5fec418cc6ac983671dba5d80ffaffb142" + "reference": "46be3f58adac13084497961e10eed9a7fb4d44d1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sensiolabs/security-checker/zipball/dc270d5fec418cc6ac983671dba5d80ffaffb142", - "reference": "dc270d5fec418cc6ac983671dba5d80ffaffb142", + "url": "https://api.github.com/repos/sensiolabs/security-checker/zipball/46be3f58adac13084497961e10eed9a7fb4d44d1", + "reference": "46be3f58adac13084497961e10eed9a7fb4d44d1", "shasum": "" }, "require": { "composer/ca-bundle": "^1.0", + "php": ">=5.5.9", "symfony/console": "~2.7|~3.0|~4.0" }, "bin": [ @@ -2791,12 +2792,12 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.1-dev" + "dev-master": "5.0-dev" } }, "autoload": { - "psr-0": { - "SensioLabs\\Security": "" + "psr-4": { + "SensioLabs\\Security\\": "SensioLabs/Security" } }, "notification-url": "https://packagist.org/downloads/", @@ -2810,7 +2811,7 @@ } ], "description": "A security checker for your composer.lock", - "time": "2018-02-28T22:10:01+00:00" + "time": "2018-12-19T17:14:59+00:00" }, { "name": "squizlabs/php_codesniffer", From 150a94fc71230ca04fc00e2f2b6c40936cb3c060 Mon Sep 17 00:00:00 2001 From: Frederico Gendorf Date: Fri, 15 Mar 2019 11:50:29 -0300 Subject: [PATCH 09/10] Fix user image display and upload; fixes #5604 --- front/document.send.php | 2 +- inc/user.class.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/front/document.send.php b/front/document.send.php index d80ab14aad..87a7db6298 100644 --- a/front/document.send.php +++ b/front/document.send.php @@ -69,7 +69,7 @@ } if ($splitter[0] == "_pictures") { - if (Document::isImage($_GET['file'])) { + if (Document::isImage(GLPI_DOC_DIR."/".$_GET['file'])) { $send = true; } } diff --git a/inc/user.class.php b/inc/user.class.php index fdc9d8b0ac..67bfc71496 100644 --- a/inc/user.class.php +++ b/inc/user.class.php @@ -735,7 +735,7 @@ function prepareInputForUpdate($input) { $picture_path = GLPI_PICTURE_DIR . "/$sub/${filename}.$extension"; self::dropPictureFiles($filename.".".$extension); - if (Document::isImage($input["_picture"]) + if (Document::isImage($fullpath) && Document::renameForce($fullpath, $picture_path)) { Session::addMessageAfterRedirect(__('The file is valid. Upload is successful.')); // For display From 9ef29babf8ae57986b2f3c1480a07c4608599a64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Anne?= Date: Fri, 22 Mar 2019 11:05:24 +0100 Subject: [PATCH 10/10] Fix escaping of optgroups in dropdowns; fixes #5646 --- js/common.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/js/common.js b/js/common.js index 15cf04b200..e083b3970e 100644 --- a/js/common.js +++ b/js/common.js @@ -958,11 +958,13 @@ var templateResult = function(result) { var text = result.text; if (text.indexOf('>') !== -1 || text.indexOf('<') !== -1) { // escape text, if it contains chevrons (can already be escaped prior to this point :/) - text = jQuery.fn.select2.defaults.defaults.escapeMarkup(result.text); + text = jQuery.fn.select2.defaults.defaults.escapeMarkup(text); }; if (!result.id) { - return text; + // If result has no id, then it is used as an optgroup and is not used for matches + _elt.html(text); + return _elt; } var _term = query.term || '';