From 7a6f27982549703b19cf4cf9fc6ecbcd30e4deda Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 13 Feb 2019 17:06:44 +0000 Subject: [PATCH 1/7] TextFormat: fixed clean() not being unicode-aware --- src/pocketmine/utils/TextFormat.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pocketmine/utils/TextFormat.php b/src/pocketmine/utils/TextFormat.php index 40d236347..3c3cc0ee8 100644 --- a/src/pocketmine/utils/TextFormat.php +++ b/src/pocketmine/utils/TextFormat.php @@ -86,9 +86,9 @@ abstract class TextFormat{ */ public static function clean(string $string, bool $removeFormat = true) : string{ if($removeFormat){ - return str_replace(TextFormat::ESCAPE, "", preg_replace(["/" . TextFormat::ESCAPE . "[0-9a-fk-or]/", "/\x1b[\\(\\][[0-9;\\[\\(]+[Bm]/"], "", $string)); + return str_replace(TextFormat::ESCAPE, "", preg_replace(["/" . TextFormat::ESCAPE . "[0-9a-fk-or]/u", "/\x1b[\\(\\][[0-9;\\[\\(]+[Bm]/"], "", $string)); } - return str_replace("\x1b", "", preg_replace("/\x1b[\\(\\][[0-9;\\[\\(]+[Bm]/", "", $string)); + return str_replace("\x1b", "", preg_replace("/\x1b[\\(\\][[0-9;\\[\\(]+[Bm]/u", "", $string)); } /** From 8fad5a6e30035c520d92216dbef5ff7cd1b71347 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 13 Feb 2019 20:01:36 +0000 Subject: [PATCH 2/7] TextFormat: use mb_scrub() in clean() this redacts invalid characters to prevent them appearing in places that might break the client. --- src/pocketmine/utils/TextFormat.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/pocketmine/utils/TextFormat.php b/src/pocketmine/utils/TextFormat.php index 3c3cc0ee8..7119030c7 100644 --- a/src/pocketmine/utils/TextFormat.php +++ b/src/pocketmine/utils/TextFormat.php @@ -25,6 +25,7 @@ namespace pocketmine\utils; use function is_array; use function json_encode; +use function mb_scrub; use function preg_quote; use function preg_replace; use function preg_split; @@ -77,14 +78,15 @@ abstract class TextFormat{ } /** - * Cleans the string from Minecraft codes and ANSI Escape Codes + * Cleans the string from Minecraft codes, ANSI Escape Codes and invalid UTF-8 characters * * @param string $string * @param bool $removeFormat * - * @return string + * @return string valid clean UTF-8 */ public static function clean(string $string, bool $removeFormat = true) : string{ + $string = mb_scrub($string, 'UTF-8'); if($removeFormat){ return str_replace(TextFormat::ESCAPE, "", preg_replace(["/" . TextFormat::ESCAPE . "[0-9a-fk-or]/u", "/\x1b[\\(\\][[0-9;\\[\\(]+[Bm]/"], "", $string)); } From c433fad0a7077c8402eed5a68f037ea110e20446 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 14 Feb 2019 13:50:56 +0000 Subject: [PATCH 3/7] another /u modifier --- src/pocketmine/utils/TextFormat.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pocketmine/utils/TextFormat.php b/src/pocketmine/utils/TextFormat.php index 7119030c7..7d5b028ac 100644 --- a/src/pocketmine/utils/TextFormat.php +++ b/src/pocketmine/utils/TextFormat.php @@ -88,7 +88,7 @@ abstract class TextFormat{ public static function clean(string $string, bool $removeFormat = true) : string{ $string = mb_scrub($string, 'UTF-8'); if($removeFormat){ - return str_replace(TextFormat::ESCAPE, "", preg_replace(["/" . TextFormat::ESCAPE . "[0-9a-fk-or]/u", "/\x1b[\\(\\][[0-9;\\[\\(]+[Bm]/"], "", $string)); + return str_replace(TextFormat::ESCAPE, "", preg_replace(["/" . TextFormat::ESCAPE . "[0-9a-fk-or]/u", "/\x1b[\\(\\][[0-9;\\[\\(]+[Bm]/u"], "", $string)); } return str_replace("\x1b", "", preg_replace("/\x1b[\\(\\][[0-9;\\[\\(]+[Bm]/u", "", $string)); } From c346c45d424a7f01d83703d376d85921e9ace8f4 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 14 Feb 2019 15:07:58 +0000 Subject: [PATCH 4/7] Use regex for command argument parsing, fixes #2266 moral of the story: don't abuse functions for things they weren't designed for... lol --- src/pocketmine/command/SimpleCommandMap.php | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/pocketmine/command/SimpleCommandMap.php b/src/pocketmine/command/SimpleCommandMap.php index 88d95a5ba..d7296f82f 100644 --- a/src/pocketmine/command/SimpleCommandMap.php +++ b/src/pocketmine/command/SimpleCommandMap.php @@ -66,13 +66,13 @@ use pocketmine\command\defaults\VersionCommand; use pocketmine\command\defaults\WhitelistCommand; use pocketmine\command\utils\InvalidCommandSyntaxException; use pocketmine\Server; -use function array_map; use function array_shift; use function count; use function explode; use function implode; use function min; -use function str_getcsv; +use function preg_match_all; +use function stripslashes; use function strpos; use function strtolower; use function trim; @@ -247,7 +247,16 @@ class SimpleCommandMap implements CommandMap{ } public function dispatch(CommandSender $sender, string $commandLine) : bool{ - $args = array_map("\stripslashes", str_getcsv($commandLine, " ")); + $args = []; + preg_match_all('/"((?:\\\\.|[^\\\\"])*)"|(\S+)/u', $commandLine, $matches); + foreach($matches[0] as $k => $_){ + for($i = 1; $i <= 2; ++$i){ + if($matches[$i][$k] !== ""){ + $args[$k] = stripslashes($matches[$i][$k]); + break; + } + } + } $sentCommandLabel = ""; $target = $this->matchCommand($sentCommandLabel, $args); From 65529ff2ced2e43715ee5d2cb3413fc6324c92ad Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 14 Feb 2019 15:09:41 +0000 Subject: [PATCH 5/7] Command: add @throws CommandException --- src/pocketmine/command/Command.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pocketmine/command/Command.php b/src/pocketmine/command/Command.php index 0e949f3f4..2f47e2029 100644 --- a/src/pocketmine/command/Command.php +++ b/src/pocketmine/command/Command.php @@ -26,6 +26,7 @@ declare(strict_types=1); */ namespace pocketmine\command; +use pocketmine\command\utils\CommandException; use pocketmine\lang\TextContainer; use pocketmine\lang\TranslationContainer; use pocketmine\permission\PermissionManager; @@ -92,6 +93,7 @@ abstract class Command{ * @param string[] $args * * @return mixed + * @throws CommandException */ abstract public function execute(CommandSender $sender, string $commandLabel, array $args); From 44697e784a262b739eb79329cd49c0489a9ce108 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 14 Feb 2019 15:16:51 +0000 Subject: [PATCH 6/7] Sign: add validity checks on text encoding, scrub invalid UTF-8 on load this works around a bug where corrupted text on preexisting signs can mess up the client. This also prevents corrupted text getting onto signs in the future by having them scrubbed and validated before applying them. --- src/pocketmine/tile/Sign.php | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/pocketmine/tile/Sign.php b/src/pocketmine/tile/Sign.php index ca577ad93..39b3b550b 100644 --- a/src/pocketmine/tile/Sign.php +++ b/src/pocketmine/tile/Sign.php @@ -33,6 +33,8 @@ use function array_pad; use function array_slice; use function explode; use function implode; +use function mb_check_encoding; +use function mb_scrub; use function sprintf; class Sign extends Spawnable{ @@ -57,6 +59,9 @@ class Sign extends Spawnable{ } } } + $this->text = array_map(function(string $line) : string{ + return mb_scrub($line, 'UTF-8'); + }, $this->text); } protected function writeSaveData(CompoundTag $nbt) : void{ @@ -79,16 +84,16 @@ class Sign extends Spawnable{ */ public function setText(?string $line1 = "", ?string $line2 = "", ?string $line3 = "", ?string $line4 = "") : void{ if($line1 !== null){ - $this->text[0] = $line1; + $this->setLine(0, $line1, false); } if($line2 !== null){ - $this->text[1] = $line2; + $this->setLine(1, $line2, false); } if($line3 !== null){ - $this->text[2] = $line3; + $this->setLine(2, $line3, false); } if($line4 !== null){ - $this->text[3] = $line4; + $this->setLine(3, $line4, false); } $this->onChanged(); @@ -103,6 +108,9 @@ class Sign extends Spawnable{ if($index < 0 or $index > 3){ throw new \InvalidArgumentException("Index must be in the range 0-3!"); } + if(!mb_check_encoding($line, 'UTF-8')){ + throw new \InvalidArgumentException("Text must be valid UTF-8"); + } $this->text[$index] = $line; if($update){ From e1bacb5c6d966a6c46348450182222be9091868e Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 14 Feb 2019 16:01:25 +0000 Subject: [PATCH 7/7] Human: fixed hunger underflow when value is a fraction, closes #2761 --- src/pocketmine/entity/Human.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pocketmine/entity/Human.php b/src/pocketmine/entity/Human.php index ee02412cb..d24b4f536 100644 --- a/src/pocketmine/entity/Human.php +++ b/src/pocketmine/entity/Human.php @@ -301,7 +301,7 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{ $food = $this->getFood(); if($food > 0){ $food--; - $this->setFood($food); + $this->setFood(max($food, 0)); } } }