Merge branch 'minor-next' into major-next

This commit is contained in:
Dylan K. Taylor 2023-07-14 13:28:07 +01:00
commit 280bf60830
No known key found for this signature in database
GPG Key ID: 8927471A91CAFD3D
19 changed files with 133 additions and 38 deletions

View File

@ -17,3 +17,10 @@ Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if
## Fixes
- Fixed Docker image build failure due to outdated `build/php` submodule.
# 4.23.1
Released 14th July 2023.
## Fixes
- Hardened validation of JWT signing keys in `LoginPacket`.
- Fixed server crash due to a bug in upstream dependency [`netresearch/jsonmapper`](https://github.com/cweiske/JsonMapper).

View File

@ -21,3 +21,13 @@ If you're upgrading directly from 5.1.x to 5.3.x, please also read the following
## Internals
- `BlockTypeNames`, `BlockStateNames`, `BlockStateStringValues` and `ItemTypeNames` in the `pocketmine\data\bedrock` package have BC-breaking changes to accommodate Bedrock 1.20.10.
# 5.3.1
Released 14th July 2023.
## Included releases
**This release includes changes from the following releases:**
- [4.23.1](https://github.com/pmmp/PocketMine-MP/blob/4.23.1/changelogs/4.23.md#4231) - Security fixes
## General
- Updated `build/php` submodule to pmmp/PHP-Binaries@e0c918d1379465964acefd562d9e48f87cfc2c9e.

View File

@ -33,7 +33,7 @@
"composer-runtime-api": "^2.0",
"adhocore/json-comment": "~1.2.0",
"fgrosse/phpasn1": "~2.5.0",
"pocketmine/netresearch-jsonmapper": "~v4.2.999",
"pocketmine/netresearch-jsonmapper": "~v4.2.1000",
"pocketmine/bedrock-block-upgrade-schema": "~3.1.0+bedrock-1.20.10",
"pocketmine/bedrock-data": "~2.4.0+bedrock-1.20.10",
"pocketmine/bedrock-item-upgrade-schema": "~1.4.0+bedrock-1.20.10",

14
composer.lock generated
View File

@ -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": "e0c0208b3fc3d1b20fef20d2fc43fc90",
"content-hash": "ee46ec27f8dfc8c767527b7776fe9992",
"packages": [
{
"name": "adhocore/json-comment",
@ -639,16 +639,16 @@
},
{
"name": "pocketmine/netresearch-jsonmapper",
"version": "v4.2.999",
"version": "v4.2.1000",
"source": {
"type": "git",
"url": "https://github.com/pmmp/netresearch-jsonmapper.git",
"reference": "f700806dec756ed825a8200dc2950ead98265956"
"reference": "078764e869e9b732f97206ec9363480a77c35532"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pmmp/netresearch-jsonmapper/zipball/f700806dec756ed825a8200dc2950ead98265956",
"reference": "f700806dec756ed825a8200dc2950ead98265956",
"url": "https://api.github.com/repos/pmmp/netresearch-jsonmapper/zipball/078764e869e9b732f97206ec9363480a77c35532",
"reference": "078764e869e9b732f97206ec9363480a77c35532",
"shasum": ""
},
"require": {
@ -687,9 +687,9 @@
"support": {
"email": "cweiske@cweiske.de",
"issues": "https://github.com/cweiske/jsonmapper/issues",
"source": "https://github.com/pmmp/netresearch-jsonmapper/tree/v4.2.999"
"source": "https://github.com/pmmp/netresearch-jsonmapper/tree/v4.2.1000"
},
"time": "2023-06-01T13:43:01+00:00"
"time": "2023-07-14T10:44:14+00:00"
},
{
"name": "pocketmine/raklib",

View File

@ -31,7 +31,7 @@ use function str_repeat;
final class VersionInfo{
public const NAME = "PocketMine-MP";
public const BASE_VERSION = "5.3.1";
public const BASE_VERSION = "5.3.2";
public const IS_DEVELOPMENT_BUILD = true;
public const BUILD_CHANNEL = "stable";

View File

@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\data\runtime\RuntimeDataDescriber;
use pocketmine\event\block\BlockGrowEvent;
use pocketmine\item\Item;
use pocketmine\math\Facing;
@ -30,11 +31,34 @@ use function array_rand;
use function mt_rand;
abstract class Stem extends Crops{
protected int $facing = Facing::UP;
protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{
parent::describeBlockOnlyState($w);
$w->facingExcept($this->facing, Facing::DOWN);
}
public function getFacing() : int{ return $this->facing; }
/** @return $this */
public function setFacing(int $facing) : self{
if($facing === Facing::DOWN){
throw new \InvalidArgumentException("DOWN is not a valid facing for this block");
}
$this->facing = $facing;
return $this;
}
abstract protected function getPlant() : Block;
public function onNearbyBlockChange() : void{
if($this->facing !== Facing::UP && !$this->getSide($this->facing)->hasSameTypeId($this->getPlant())){
$this->position->getWorld()->setBlock($this->position, $this->setFacing(Facing::UP));
}
}
public function onRandomTick() : void{
if(mt_rand(0, 2) === 1){
if($this->facing === Facing::UP && mt_rand(0, 2) === 1){
$world = $this->position->getWorld();
if($this->age < self::MAX_AGE){
$block = clone $this;
@ -52,11 +76,13 @@ abstract class Stem extends Crops{
}
}
$side = $this->getSide(Facing::HORIZONTAL[array_rand(Facing::HORIZONTAL)]);
$facing = Facing::HORIZONTAL[array_rand(Facing::HORIZONTAL)];
$side = $this->getSide($facing);
if($side->getTypeId() === BlockTypeIds::AIR && $side->getSide(Facing::DOWN)->hasTypeTag(BlockTypeTags::DIRT)){
$ev = new BlockGrowEvent($side, $grow);
$ev->call();
if(!$ev->isCancelled()){
$world->setBlock($this->position, $this->setFacing($facing));
$world->setBlock($side->position, $ev->getNewState());
}
}

View File

@ -84,6 +84,7 @@ final class PotionTypeIdMap{
$this->register(PotionTypeIds::STRONG_TURTLE_MASTER, PotionType::STRONG_TURTLE_MASTER());
$this->register(PotionTypeIds::SLOW_FALLING, PotionType::SLOW_FALLING());
$this->register(PotionTypeIds::LONG_SLOW_FALLING, PotionType::LONG_SLOW_FALLING());
$this->register(PotionTypeIds::STRONG_SLOWNESS, PotionType::STRONG_SLOWNESS());
}
private function register(int $id, PotionType $type) : void{

View File

@ -66,4 +66,5 @@ final class PotionTypeIds{
public const STRONG_TURTLE_MASTER = 39;
public const SLOW_FALLING = 40;
public const LONG_SLOW_FALLING = 41;
public const STRONG_SLOWNESS = 42;
}

View File

@ -236,9 +236,12 @@ final class BlockStateDeserializerHelper{
/** @throws BlockStateDeserializeException */
public static function decodeStem(Stem $block, BlockStateReader $in) : Stem{
//TODO: our stems don't support facings yet (facing_direction)
$in->todo(BlockStateNames::FACING_DIRECTION);
return self::decodeCrops($block, $in);
//In PM, we use Facing::UP to indicate that the stem is not attached to a pumpkin/melon, since this makes the
//most intuitive sense (the stem is pointing at the sky). However, Bedrock uses the DOWN state for this, which
//is absurd, and I refuse to make our API similarly absurd.
$facing = $in->readFacingWithoutUp();
return self::decodeCrops($block, $in)
->setFacing($facing === Facing::DOWN ? Facing::UP : $facing);
}
/** @throws BlockStateDeserializeException */

View File

@ -223,8 +223,12 @@ final class BlockStateSerializerHelper{
}
public static function encodeStem(Stem $block, BlockStateWriter $out) : BlockStateWriter{
//In PM, we use Facing::UP to indicate that the stem is not attached to a pumpkin/melon, since this makes the
//most intuitive sense (the stem is pointing at the sky). However, Bedrock uses the DOWN state for this, which
//is absurd, and I refuse to make our API similarly absurd.
$facing = $block->getFacing();
return self::encodeCrops($block, $out)
->writeHorizontalFacing(Facing::NORTH); //TODO: PM impl doesn't support this yet
->writeFacingWithoutUp($facing === Facing::UP ? Facing::DOWN : $facing);
}
public static function encodeStone(string $type) : BlockStateWriter{

View File

@ -190,16 +190,17 @@ trait RuntimeEnumDeserializerTrait{
29 => \pocketmine\item\PotionType::STRONG_LEAPING(),
30 => \pocketmine\item\PotionType::STRONG_POISON(),
31 => \pocketmine\item\PotionType::STRONG_REGENERATION(),
32 => \pocketmine\item\PotionType::STRONG_STRENGTH(),
33 => \pocketmine\item\PotionType::STRONG_SWIFTNESS(),
34 => \pocketmine\item\PotionType::STRONG_TURTLE_MASTER(),
35 => \pocketmine\item\PotionType::SWIFTNESS(),
36 => \pocketmine\item\PotionType::THICK(),
37 => \pocketmine\item\PotionType::TURTLE_MASTER(),
38 => \pocketmine\item\PotionType::WATER(),
39 => \pocketmine\item\PotionType::WATER_BREATHING(),
40 => \pocketmine\item\PotionType::WEAKNESS(),
41 => \pocketmine\item\PotionType::WITHER(),
32 => \pocketmine\item\PotionType::STRONG_SLOWNESS(),
33 => \pocketmine\item\PotionType::STRONG_STRENGTH(),
34 => \pocketmine\item\PotionType::STRONG_SWIFTNESS(),
35 => \pocketmine\item\PotionType::STRONG_TURTLE_MASTER(),
36 => \pocketmine\item\PotionType::SWIFTNESS(),
37 => \pocketmine\item\PotionType::THICK(),
38 => \pocketmine\item\PotionType::TURTLE_MASTER(),
39 => \pocketmine\item\PotionType::WATER(),
40 => \pocketmine\item\PotionType::WATER_BREATHING(),
41 => \pocketmine\item\PotionType::WEAKNESS(),
42 => \pocketmine\item\PotionType::WITHER(),
default => throw new InvalidSerializedRuntimeDataException("Invalid serialized value for PotionType")
};
}

View File

@ -190,16 +190,17 @@ trait RuntimeEnumSerializerTrait{
\pocketmine\item\PotionType::STRONG_LEAPING() => 29,
\pocketmine\item\PotionType::STRONG_POISON() => 30,
\pocketmine\item\PotionType::STRONG_REGENERATION() => 31,
\pocketmine\item\PotionType::STRONG_STRENGTH() => 32,
\pocketmine\item\PotionType::STRONG_SWIFTNESS() => 33,
\pocketmine\item\PotionType::STRONG_TURTLE_MASTER() => 34,
\pocketmine\item\PotionType::SWIFTNESS() => 35,
\pocketmine\item\PotionType::THICK() => 36,
\pocketmine\item\PotionType::TURTLE_MASTER() => 37,
\pocketmine\item\PotionType::WATER() => 38,
\pocketmine\item\PotionType::WATER_BREATHING() => 39,
\pocketmine\item\PotionType::WEAKNESS() => 40,
\pocketmine\item\PotionType::WITHER() => 41,
\pocketmine\item\PotionType::STRONG_SLOWNESS() => 32,
\pocketmine\item\PotionType::STRONG_STRENGTH() => 33,
\pocketmine\item\PotionType::STRONG_SWIFTNESS() => 34,
\pocketmine\item\PotionType::STRONG_TURTLE_MASTER() => 35,
\pocketmine\item\PotionType::SWIFTNESS() => 36,
\pocketmine\item\PotionType::THICK() => 37,
\pocketmine\item\PotionType::TURTLE_MASTER() => 38,
\pocketmine\item\PotionType::WATER() => 39,
\pocketmine\item\PotionType::WATER_BREATHING() => 40,
\pocketmine\item\PotionType::WEAKNESS() => 41,
\pocketmine\item\PotionType::WITHER() => 42,
default => throw new \pocketmine\utils\AssumptionFailedError("All PotionType cases should be covered")
});
}

View File

@ -217,6 +217,7 @@ abstract class Living extends Entity{
public function setSneaking(bool $value = true) : void{
$this->sneaking = $value;
$this->networkPropertiesDirty = true;
$this->recalculateSize();
}
public function isSprinting() : bool{
@ -258,6 +259,8 @@ abstract class Living extends Entity{
if($this->isSwimming() || $this->isGliding()){
$width = $size->getWidth();
$this->setSize((new EntitySizeInfo($width, $width, $width * 0.9))->scale($this->getScale()));
}elseif($this->isSneaking()){
$this->setSize((new EntitySizeInfo(3 / 4 * $size->getHeight(), $size->getWidth(), 3 / 4 * $size->getEyeHeight()))->scale($this->getScale()));
}else{
$this->setSize($size->scale($this->getScale()));
}

View File

@ -65,6 +65,7 @@ use pocketmine\utils\EnumTrait;
* @method static PotionType STRONG_LEAPING()
* @method static PotionType STRONG_POISON()
* @method static PotionType STRONG_REGENERATION()
* @method static PotionType STRONG_SLOWNESS()
* @method static PotionType STRONG_STRENGTH()
* @method static PotionType STRONG_SWIFTNESS()
* @method static PotionType STRONG_TURTLE_MASTER()
@ -201,6 +202,9 @@ final class PotionType{
]),
new self("long_slow_falling", "Long Slow Falling", fn() => [
//TODO
]),
new self("strong_slowness", "Strong Slowness", fn() => [
new EffectInstance(VanillaEffects::SLOWNESS(), 20 * 20, 3)
])
);
}

View File

@ -1506,6 +1506,8 @@ final class StringToItemParser extends StringToTParser{
$result->register("strong_poison_splash_potion", fn() => Items::SPLASH_POTION()->setType(PotionType::STRONG_POISON()));
$result->register("strong_regeneration_potion", fn() => Items::POTION()->setType(PotionType::STRONG_REGENERATION()));
$result->register("strong_regeneration_splash_potion", fn() => Items::SPLASH_POTION()->setType(PotionType::STRONG_REGENERATION()));
$result->register("strong_slowness_potion", fn() => Items::POTION()->setType(PotionType::STRONG_SLOWNESS()));
$result->register("strong_slowness_splash_potion", fn() => Items::SPLASH_POTION()->setType(PotionType::STRONG_SLOWNESS()));
$result->register("strong_strength_potion", fn() => Items::POTION()->setType(PotionType::STRONG_STRENGTH()));
$result->register("strong_strength_splash_potion", fn() => Items::SPLASH_POTION()->setType(PotionType::STRONG_STRENGTH()));
$result->register("strong_swiftness_potion", fn() => Items::POTION()->setType(PotionType::STRONG_SWIFTNESS()));

View File

@ -61,6 +61,7 @@ use const OPENSSL_ALGO_SHA384;
use const STR_PAD_LEFT;
final class JwtUtils{
public const BEDROCK_SIGNING_KEY_CURVE_NAME = "secp384r1";
/**
* @return string[]
@ -203,6 +204,17 @@ final class JwtUtils{
if($signingKeyOpenSSL === false){
throw new JwtException("OpenSSL failed to parse key: " . openssl_error_string());
}
$details = openssl_pkey_get_details($signingKeyOpenSSL);
if($details === false){
throw new JwtException("OpenSSL failed to get details from key: " . openssl_error_string());
}
if(!isset($details['ec']['curve_name'])){
throw new JwtException("Expected an EC key");
}
$curve = $details['ec']['curve_name'];
if($curve !== self::BEDROCK_SIGNING_KEY_CURVE_NAME){
throw new JwtException("Key must belong to curve " . self::BEDROCK_SIGNING_KEY_CURVE_NAME . ", got $curve");
}
return $signingKeyOpenSSL;
}
}

View File

@ -34,7 +34,6 @@ use pocketmine\thread\NonThreadSafeValue;
use function base64_decode;
use function igbinary_serialize;
use function igbinary_unserialize;
use function openssl_error_string;
use function time;
class ProcessLoginTask extends AsyncTask{
@ -164,7 +163,8 @@ class ProcessLoginTask extends AsyncTask{
try{
$signingKeyOpenSSL = JwtUtils::parseDerPublicKey($headerDerKey);
}catch(JwtException $e){
throw new VerifyLoginException("Invalid JWT public key: " . openssl_error_string());
//TODO: we shouldn't be showing this internal information to the client
throw new VerifyLoginException("Invalid JWT public key: " . $e->getMessage(), null, 0, $e);
}
try{
if(!JwtUtils::verify($jwt, $signingKeyOpenSSL)){
@ -204,6 +204,12 @@ class ProcessLoginTask extends AsyncTask{
if($identityPublicKey === false){
throw new VerifyLoginException("Invalid identityPublicKey: base64 error decoding");
}
try{
//verify key format and parameters
JwtUtils::parseDerPublicKey($identityPublicKey);
}catch(JwtException $e){
throw new VerifyLoginException("Invalid identityPublicKey: " . $e->getMessage(), null, 0, $e);
}
$currentPublicKey = $identityPublicKey; //if there are further links, the next link should be signed with this
}
}

View File

@ -33,6 +33,7 @@ use function hex2bin;
use function openssl_digest;
use function openssl_error_string;
use function openssl_pkey_derive;
use function openssl_pkey_get_details;
use function str_pad;
use const STR_PAD_LEFT;
@ -42,7 +43,20 @@ final class EncryptionUtils{
//NOOP
}
private static function validateKey(\OpenSSLAsymmetricKey $key) : void{
$keyDetails = Utils::assumeNotFalse(openssl_pkey_get_details($key));
if(!isset($keyDetails["ec"]["curve_name"])){
throw new \InvalidArgumentException("Key must be an EC key");
}
$curveName = $keyDetails["ec"]["curve_name"];
if($curveName !== JwtUtils::BEDROCK_SIGNING_KEY_CURVE_NAME){
throw new \InvalidArgumentException("Key must belong to the " . JwtUtils::BEDROCK_SIGNING_KEY_CURVE_NAME . " elliptic curve, got $curveName");
}
}
public static function generateSharedSecret(\OpenSSLAsymmetricKey $localPriv, \OpenSSLAsymmetricKey $remotePub) : \GMP{
self::validateKey($localPriv);
self::validateKey($remotePub);
$hexSecret = openssl_pkey_derive($remotePub, $localPriv, 48);
if($hexSecret === false){
throw new \InvalidArgumentException("Failed to derive shared secret: " . openssl_error_string());

File diff suppressed because one or more lines are too long