mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-05-17 03:08:58 +00:00
Merge branch 'minor-next' into major-next
This commit is contained in:
commit
280bf60830
@ -17,3 +17,10 @@ Consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if
|
|||||||
|
|
||||||
## Fixes
|
## Fixes
|
||||||
- Fixed Docker image build failure due to outdated `build/php` submodule.
|
- 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).
|
||||||
|
@ -21,3 +21,13 @@ If you're upgrading directly from 5.1.x to 5.3.x, please also read the following
|
|||||||
|
|
||||||
## Internals
|
## Internals
|
||||||
- `BlockTypeNames`, `BlockStateNames`, `BlockStateStringValues` and `ItemTypeNames` in the `pocketmine\data\bedrock` package have BC-breaking changes to accommodate Bedrock 1.20.10.
|
- `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.
|
||||||
|
@ -33,7 +33,7 @@
|
|||||||
"composer-runtime-api": "^2.0",
|
"composer-runtime-api": "^2.0",
|
||||||
"adhocore/json-comment": "~1.2.0",
|
"adhocore/json-comment": "~1.2.0",
|
||||||
"fgrosse/phpasn1": "~2.5.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-block-upgrade-schema": "~3.1.0+bedrock-1.20.10",
|
||||||
"pocketmine/bedrock-data": "~2.4.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",
|
"pocketmine/bedrock-item-upgrade-schema": "~1.4.0+bedrock-1.20.10",
|
||||||
|
14
composer.lock
generated
14
composer.lock
generated
@ -4,7 +4,7 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "e0c0208b3fc3d1b20fef20d2fc43fc90",
|
"content-hash": "ee46ec27f8dfc8c767527b7776fe9992",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "adhocore/json-comment",
|
"name": "adhocore/json-comment",
|
||||||
@ -639,16 +639,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "pocketmine/netresearch-jsonmapper",
|
"name": "pocketmine/netresearch-jsonmapper",
|
||||||
"version": "v4.2.999",
|
"version": "v4.2.1000",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/pmmp/netresearch-jsonmapper.git",
|
"url": "https://github.com/pmmp/netresearch-jsonmapper.git",
|
||||||
"reference": "f700806dec756ed825a8200dc2950ead98265956"
|
"reference": "078764e869e9b732f97206ec9363480a77c35532"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/pmmp/netresearch-jsonmapper/zipball/f700806dec756ed825a8200dc2950ead98265956",
|
"url": "https://api.github.com/repos/pmmp/netresearch-jsonmapper/zipball/078764e869e9b732f97206ec9363480a77c35532",
|
||||||
"reference": "f700806dec756ed825a8200dc2950ead98265956",
|
"reference": "078764e869e9b732f97206ec9363480a77c35532",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -687,9 +687,9 @@
|
|||||||
"support": {
|
"support": {
|
||||||
"email": "cweiske@cweiske.de",
|
"email": "cweiske@cweiske.de",
|
||||||
"issues": "https://github.com/cweiske/jsonmapper/issues",
|
"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",
|
"name": "pocketmine/raklib",
|
||||||
|
@ -31,7 +31,7 @@ use function str_repeat;
|
|||||||
|
|
||||||
final class VersionInfo{
|
final class VersionInfo{
|
||||||
public const NAME = "PocketMine-MP";
|
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 IS_DEVELOPMENT_BUILD = true;
|
||||||
public const BUILD_CHANNEL = "stable";
|
public const BUILD_CHANNEL = "stable";
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\block;
|
namespace pocketmine\block;
|
||||||
|
|
||||||
|
use pocketmine\data\runtime\RuntimeDataDescriber;
|
||||||
use pocketmine\event\block\BlockGrowEvent;
|
use pocketmine\event\block\BlockGrowEvent;
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\math\Facing;
|
use pocketmine\math\Facing;
|
||||||
@ -30,11 +31,34 @@ use function array_rand;
|
|||||||
use function mt_rand;
|
use function mt_rand;
|
||||||
|
|
||||||
abstract class Stem extends Crops{
|
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;
|
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{
|
public function onRandomTick() : void{
|
||||||
if(mt_rand(0, 2) === 1){
|
if($this->facing === Facing::UP && mt_rand(0, 2) === 1){
|
||||||
$world = $this->position->getWorld();
|
$world = $this->position->getWorld();
|
||||||
if($this->age < self::MAX_AGE){
|
if($this->age < self::MAX_AGE){
|
||||||
$block = clone $this;
|
$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)){
|
if($side->getTypeId() === BlockTypeIds::AIR && $side->getSide(Facing::DOWN)->hasTypeTag(BlockTypeTags::DIRT)){
|
||||||
$ev = new BlockGrowEvent($side, $grow);
|
$ev = new BlockGrowEvent($side, $grow);
|
||||||
$ev->call();
|
$ev->call();
|
||||||
if(!$ev->isCancelled()){
|
if(!$ev->isCancelled()){
|
||||||
|
$world->setBlock($this->position, $this->setFacing($facing));
|
||||||
$world->setBlock($side->position, $ev->getNewState());
|
$world->setBlock($side->position, $ev->getNewState());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,6 +84,7 @@ final class PotionTypeIdMap{
|
|||||||
$this->register(PotionTypeIds::STRONG_TURTLE_MASTER, PotionType::STRONG_TURTLE_MASTER());
|
$this->register(PotionTypeIds::STRONG_TURTLE_MASTER, PotionType::STRONG_TURTLE_MASTER());
|
||||||
$this->register(PotionTypeIds::SLOW_FALLING, PotionType::SLOW_FALLING());
|
$this->register(PotionTypeIds::SLOW_FALLING, PotionType::SLOW_FALLING());
|
||||||
$this->register(PotionTypeIds::LONG_SLOW_FALLING, PotionType::LONG_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{
|
private function register(int $id, PotionType $type) : void{
|
||||||
|
@ -66,4 +66,5 @@ final class PotionTypeIds{
|
|||||||
public const STRONG_TURTLE_MASTER = 39;
|
public const STRONG_TURTLE_MASTER = 39;
|
||||||
public const SLOW_FALLING = 40;
|
public const SLOW_FALLING = 40;
|
||||||
public const LONG_SLOW_FALLING = 41;
|
public const LONG_SLOW_FALLING = 41;
|
||||||
|
public const STRONG_SLOWNESS = 42;
|
||||||
}
|
}
|
||||||
|
@ -236,9 +236,12 @@ final class BlockStateDeserializerHelper{
|
|||||||
|
|
||||||
/** @throws BlockStateDeserializeException */
|
/** @throws BlockStateDeserializeException */
|
||||||
public static function decodeStem(Stem $block, BlockStateReader $in) : Stem{
|
public static function decodeStem(Stem $block, BlockStateReader $in) : Stem{
|
||||||
//TODO: our stems don't support facings yet (facing_direction)
|
//In PM, we use Facing::UP to indicate that the stem is not attached to a pumpkin/melon, since this makes the
|
||||||
$in->todo(BlockStateNames::FACING_DIRECTION);
|
//most intuitive sense (the stem is pointing at the sky). However, Bedrock uses the DOWN state for this, which
|
||||||
return self::decodeCrops($block, $in);
|
//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 */
|
/** @throws BlockStateDeserializeException */
|
||||||
|
@ -223,8 +223,12 @@ final class BlockStateSerializerHelper{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static function encodeStem(Stem $block, BlockStateWriter $out) : BlockStateWriter{
|
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)
|
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{
|
public static function encodeStone(string $type) : BlockStateWriter{
|
||||||
|
@ -190,16 +190,17 @@ trait RuntimeEnumDeserializerTrait{
|
|||||||
29 => \pocketmine\item\PotionType::STRONG_LEAPING(),
|
29 => \pocketmine\item\PotionType::STRONG_LEAPING(),
|
||||||
30 => \pocketmine\item\PotionType::STRONG_POISON(),
|
30 => \pocketmine\item\PotionType::STRONG_POISON(),
|
||||||
31 => \pocketmine\item\PotionType::STRONG_REGENERATION(),
|
31 => \pocketmine\item\PotionType::STRONG_REGENERATION(),
|
||||||
32 => \pocketmine\item\PotionType::STRONG_STRENGTH(),
|
32 => \pocketmine\item\PotionType::STRONG_SLOWNESS(),
|
||||||
33 => \pocketmine\item\PotionType::STRONG_SWIFTNESS(),
|
33 => \pocketmine\item\PotionType::STRONG_STRENGTH(),
|
||||||
34 => \pocketmine\item\PotionType::STRONG_TURTLE_MASTER(),
|
34 => \pocketmine\item\PotionType::STRONG_SWIFTNESS(),
|
||||||
35 => \pocketmine\item\PotionType::SWIFTNESS(),
|
35 => \pocketmine\item\PotionType::STRONG_TURTLE_MASTER(),
|
||||||
36 => \pocketmine\item\PotionType::THICK(),
|
36 => \pocketmine\item\PotionType::SWIFTNESS(),
|
||||||
37 => \pocketmine\item\PotionType::TURTLE_MASTER(),
|
37 => \pocketmine\item\PotionType::THICK(),
|
||||||
38 => \pocketmine\item\PotionType::WATER(),
|
38 => \pocketmine\item\PotionType::TURTLE_MASTER(),
|
||||||
39 => \pocketmine\item\PotionType::WATER_BREATHING(),
|
39 => \pocketmine\item\PotionType::WATER(),
|
||||||
40 => \pocketmine\item\PotionType::WEAKNESS(),
|
40 => \pocketmine\item\PotionType::WATER_BREATHING(),
|
||||||
41 => \pocketmine\item\PotionType::WITHER(),
|
41 => \pocketmine\item\PotionType::WEAKNESS(),
|
||||||
|
42 => \pocketmine\item\PotionType::WITHER(),
|
||||||
default => throw new InvalidSerializedRuntimeDataException("Invalid serialized value for PotionType")
|
default => throw new InvalidSerializedRuntimeDataException("Invalid serialized value for PotionType")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -190,16 +190,17 @@ trait RuntimeEnumSerializerTrait{
|
|||||||
\pocketmine\item\PotionType::STRONG_LEAPING() => 29,
|
\pocketmine\item\PotionType::STRONG_LEAPING() => 29,
|
||||||
\pocketmine\item\PotionType::STRONG_POISON() => 30,
|
\pocketmine\item\PotionType::STRONG_POISON() => 30,
|
||||||
\pocketmine\item\PotionType::STRONG_REGENERATION() => 31,
|
\pocketmine\item\PotionType::STRONG_REGENERATION() => 31,
|
||||||
\pocketmine\item\PotionType::STRONG_STRENGTH() => 32,
|
\pocketmine\item\PotionType::STRONG_SLOWNESS() => 32,
|
||||||
\pocketmine\item\PotionType::STRONG_SWIFTNESS() => 33,
|
\pocketmine\item\PotionType::STRONG_STRENGTH() => 33,
|
||||||
\pocketmine\item\PotionType::STRONG_TURTLE_MASTER() => 34,
|
\pocketmine\item\PotionType::STRONG_SWIFTNESS() => 34,
|
||||||
\pocketmine\item\PotionType::SWIFTNESS() => 35,
|
\pocketmine\item\PotionType::STRONG_TURTLE_MASTER() => 35,
|
||||||
\pocketmine\item\PotionType::THICK() => 36,
|
\pocketmine\item\PotionType::SWIFTNESS() => 36,
|
||||||
\pocketmine\item\PotionType::TURTLE_MASTER() => 37,
|
\pocketmine\item\PotionType::THICK() => 37,
|
||||||
\pocketmine\item\PotionType::WATER() => 38,
|
\pocketmine\item\PotionType::TURTLE_MASTER() => 38,
|
||||||
\pocketmine\item\PotionType::WATER_BREATHING() => 39,
|
\pocketmine\item\PotionType::WATER() => 39,
|
||||||
\pocketmine\item\PotionType::WEAKNESS() => 40,
|
\pocketmine\item\PotionType::WATER_BREATHING() => 40,
|
||||||
\pocketmine\item\PotionType::WITHER() => 41,
|
\pocketmine\item\PotionType::WEAKNESS() => 41,
|
||||||
|
\pocketmine\item\PotionType::WITHER() => 42,
|
||||||
default => throw new \pocketmine\utils\AssumptionFailedError("All PotionType cases should be covered")
|
default => throw new \pocketmine\utils\AssumptionFailedError("All PotionType cases should be covered")
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -217,6 +217,7 @@ abstract class Living extends Entity{
|
|||||||
public function setSneaking(bool $value = true) : void{
|
public function setSneaking(bool $value = true) : void{
|
||||||
$this->sneaking = $value;
|
$this->sneaking = $value;
|
||||||
$this->networkPropertiesDirty = true;
|
$this->networkPropertiesDirty = true;
|
||||||
|
$this->recalculateSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isSprinting() : bool{
|
public function isSprinting() : bool{
|
||||||
@ -258,6 +259,8 @@ abstract class Living extends Entity{
|
|||||||
if($this->isSwimming() || $this->isGliding()){
|
if($this->isSwimming() || $this->isGliding()){
|
||||||
$width = $size->getWidth();
|
$width = $size->getWidth();
|
||||||
$this->setSize((new EntitySizeInfo($width, $width, $width * 0.9))->scale($this->getScale()));
|
$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{
|
}else{
|
||||||
$this->setSize($size->scale($this->getScale()));
|
$this->setSize($size->scale($this->getScale()));
|
||||||
}
|
}
|
||||||
|
@ -65,6 +65,7 @@ use pocketmine\utils\EnumTrait;
|
|||||||
* @method static PotionType STRONG_LEAPING()
|
* @method static PotionType STRONG_LEAPING()
|
||||||
* @method static PotionType STRONG_POISON()
|
* @method static PotionType STRONG_POISON()
|
||||||
* @method static PotionType STRONG_REGENERATION()
|
* @method static PotionType STRONG_REGENERATION()
|
||||||
|
* @method static PotionType STRONG_SLOWNESS()
|
||||||
* @method static PotionType STRONG_STRENGTH()
|
* @method static PotionType STRONG_STRENGTH()
|
||||||
* @method static PotionType STRONG_SWIFTNESS()
|
* @method static PotionType STRONG_SWIFTNESS()
|
||||||
* @method static PotionType STRONG_TURTLE_MASTER()
|
* @method static PotionType STRONG_TURTLE_MASTER()
|
||||||
@ -201,6 +202,9 @@ final class PotionType{
|
|||||||
]),
|
]),
|
||||||
new self("long_slow_falling", "Long Slow Falling", fn() => [
|
new self("long_slow_falling", "Long Slow Falling", fn() => [
|
||||||
//TODO
|
//TODO
|
||||||
|
]),
|
||||||
|
new self("strong_slowness", "Strong Slowness", fn() => [
|
||||||
|
new EffectInstance(VanillaEffects::SLOWNESS(), 20 * 20, 3)
|
||||||
])
|
])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -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_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_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_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_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_strength_splash_potion", fn() => Items::SPLASH_POTION()->setType(PotionType::STRONG_STRENGTH()));
|
||||||
$result->register("strong_swiftness_potion", fn() => Items::POTION()->setType(PotionType::STRONG_SWIFTNESS()));
|
$result->register("strong_swiftness_potion", fn() => Items::POTION()->setType(PotionType::STRONG_SWIFTNESS()));
|
||||||
|
@ -61,6 +61,7 @@ use const OPENSSL_ALGO_SHA384;
|
|||||||
use const STR_PAD_LEFT;
|
use const STR_PAD_LEFT;
|
||||||
|
|
||||||
final class JwtUtils{
|
final class JwtUtils{
|
||||||
|
public const BEDROCK_SIGNING_KEY_CURVE_NAME = "secp384r1";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return string[]
|
* @return string[]
|
||||||
@ -203,6 +204,17 @@ final class JwtUtils{
|
|||||||
if($signingKeyOpenSSL === false){
|
if($signingKeyOpenSSL === false){
|
||||||
throw new JwtException("OpenSSL failed to parse key: " . openssl_error_string());
|
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;
|
return $signingKeyOpenSSL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,6 @@ use pocketmine\thread\NonThreadSafeValue;
|
|||||||
use function base64_decode;
|
use function base64_decode;
|
||||||
use function igbinary_serialize;
|
use function igbinary_serialize;
|
||||||
use function igbinary_unserialize;
|
use function igbinary_unserialize;
|
||||||
use function openssl_error_string;
|
|
||||||
use function time;
|
use function time;
|
||||||
|
|
||||||
class ProcessLoginTask extends AsyncTask{
|
class ProcessLoginTask extends AsyncTask{
|
||||||
@ -164,7 +163,8 @@ class ProcessLoginTask extends AsyncTask{
|
|||||||
try{
|
try{
|
||||||
$signingKeyOpenSSL = JwtUtils::parseDerPublicKey($headerDerKey);
|
$signingKeyOpenSSL = JwtUtils::parseDerPublicKey($headerDerKey);
|
||||||
}catch(JwtException $e){
|
}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{
|
try{
|
||||||
if(!JwtUtils::verify($jwt, $signingKeyOpenSSL)){
|
if(!JwtUtils::verify($jwt, $signingKeyOpenSSL)){
|
||||||
@ -204,6 +204,12 @@ class ProcessLoginTask extends AsyncTask{
|
|||||||
if($identityPublicKey === false){
|
if($identityPublicKey === false){
|
||||||
throw new VerifyLoginException("Invalid identityPublicKey: base64 error decoding");
|
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
|
$currentPublicKey = $identityPublicKey; //if there are further links, the next link should be signed with this
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,7 @@ use function hex2bin;
|
|||||||
use function openssl_digest;
|
use function openssl_digest;
|
||||||
use function openssl_error_string;
|
use function openssl_error_string;
|
||||||
use function openssl_pkey_derive;
|
use function openssl_pkey_derive;
|
||||||
|
use function openssl_pkey_get_details;
|
||||||
use function str_pad;
|
use function str_pad;
|
||||||
use const STR_PAD_LEFT;
|
use const STR_PAD_LEFT;
|
||||||
|
|
||||||
@ -42,7 +43,20 @@ final class EncryptionUtils{
|
|||||||
//NOOP
|
//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{
|
public static function generateSharedSecret(\OpenSSLAsymmetricKey $localPriv, \OpenSSLAsymmetricKey $remotePub) : \GMP{
|
||||||
|
self::validateKey($localPriv);
|
||||||
|
self::validateKey($remotePub);
|
||||||
$hexSecret = openssl_pkey_derive($remotePub, $localPriv, 48);
|
$hexSecret = openssl_pkey_derive($remotePub, $localPriv, 48);
|
||||||
if($hexSecret === false){
|
if($hexSecret === false){
|
||||||
throw new \InvalidArgumentException("Failed to derive shared secret: " . openssl_error_string());
|
throw new \InvalidArgumentException("Failed to derive shared secret: " . openssl_error_string());
|
||||||
|
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user