From 7001c2a92d05390c8358d713af4fa71421841f0d Mon Sep 17 00:00:00 2001 From: Shoghi Cervantes Date: Thu, 26 Jun 2014 01:05:09 +0200 Subject: [PATCH] Working skins and online authentication --- resources/config.yml | 3 +- src/phpseclib/Crypt/Base.php | 93 ++++++++++--------- src/shoghicp/BigBrother/BigBrother.php | 7 +- src/shoghicp/BigBrother/DesktopPlayer.php | 71 ++++++++++++-- .../BigBrother/network/ServerThread.php | 1 - src/shoghicp/BigBrother/network/Session.php | 7 +- .../network/protocol/EntityTeleportPacket.php | 8 +- .../network/protocol/SpawnPlayerPacket.php | 4 +- .../network/translation/Translator_16.php | 40 ++++++-- .../BigBrother/tasks/AuthenticateOnline.php | 6 +- 10 files changed, 159 insertions(+), 81 deletions(-) diff --git a/resources/config.yml b/resources/config.yml index 8e921dd3..336a6a46 100644 --- a/resources/config.yml +++ b/resources/config.yml @@ -15,4 +15,5 @@ online-mode-simpleauth: false #kickpc: kicks the PC player #kickold: kicks the player that was on the server #kicknew: kicks the player that is connecting -action-on-conflict: kickpe \ No newline at end of file +#none: do nothing, leave it up to PocketMine-MP and other plugins +action-on-conflict: none \ No newline at end of file diff --git a/src/phpseclib/Crypt/Base.php b/src/phpseclib/Crypt/Base.php index 908c9f3b..34cd67a7 100644 --- a/src/phpseclib/Crypt/Base.php +++ b/src/phpseclib/Crypt/Base.php @@ -457,6 +457,7 @@ function __construct($mode = CRYPT_MODE_CBC) $const_crypt_mode = 'CRYPT_' . $this->const_namespace . '_MODE'; // Determining the availibility of mcrypt support for the cipher + if (!defined($const_crypt_mode)) { switch (true) { case extension_loaded('mcrypt') && in_array($this->cipher_name_mcrypt, mcrypt_list_algorithms()): @@ -639,6 +640,7 @@ function encrypt($plaintext) $this->changed = false; } if ($this->enchanged) { + mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV); $this->enchanged = false; } @@ -646,7 +648,7 @@ function encrypt($plaintext) // re: {@link http://phpseclib.sourceforge.net/cfb-demo.phps} // using mcrypt's default handing of CFB the above would output two different things. using phpseclib's // rewritten CFB implementation the above outputs the same thing twice. - if ($this->mode == CRYPT_MODE_CFB && $this->continuousBuffer) { + if (false && $this->continuousBuffer) { $block_size = $this->block_size; $iv = &$this->encryptIV; $pos = &$this->enbuffer['pos']; @@ -770,47 +772,48 @@ function encrypt($plaintext) } } break; + case CRYPT_MODE_CFB: - // cfb loosely routines inspired by openssl's: - // {@link http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1} - if ($this->continuousBuffer) { - $iv = &$this->encryptIV; - $pos = &$buffer['pos']; - } else { - $iv = $this->encryptIV; - $pos = 0; - } - $len = strlen($plaintext); - $i = 0; - if ($pos) { - $orig_pos = $pos; - $max = $block_size - $pos; - if ($len >= $max) { - $i = $max; - $len-= $max; - $pos = 0; - } else { - $i = $len; - $pos+= $len; - $len = 0; - } - // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize - $ciphertext = substr($iv, $orig_pos) ^ $plaintext; - $iv = substr_replace($iv, $ciphertext, $orig_pos, $i); - } - while ($len >= $block_size) { - $iv = $this->_encryptBlock($iv) ^ substr($plaintext, $i, $block_size); - $ciphertext.= $iv; - $len-= $block_size; - $i+= $block_size; - } - if ($len) { - $iv = $this->_encryptBlock($iv); - $block = $iv ^ substr($plaintext, $i); - $iv = substr_replace($iv, $block, 0, $len); - $ciphertext.= $block; - $pos = $len; - } + // cfb loosely routines inspired by openssl's: + // {@link http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1} + if ($this->continuousBuffer) { + $iv = &$this->encryptIV; + $pos = &$buffer['pos']; + } else { + $iv = $this->encryptIV; + $pos = 0; + } + $len = strlen($plaintext); + $i = 0; + if ($pos) { + $orig_pos = $pos; + $max = $block_size - $pos; + if ($len >= $max) { + $i = $max; + $len-= $max; + $pos = 0; + } else { + $i = $len; + $pos+= $len; + $len = 0; + } + // ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize + $ciphertext = substr($iv, $orig_pos) ^ $plaintext; + $iv = substr_replace($iv, $ciphertext, $orig_pos, $i); + } + while ($len >= $block_size) { + $iv = $this->_encryptBlock($iv) ^ substr($plaintext, $i, $block_size); + $ciphertext.= $iv; + $len-= $block_size; + $i+= $block_size; + } + if ($len) { + $iv = $this->_encryptBlock($iv); + $block = $iv ^ substr($plaintext, $i); + $iv = substr_replace($iv, $block, 0, $len); + $ciphertext.= $block; + $pos = $len; + } break; case CRYPT_MODE_OFB: $xor = $this->encryptIV; @@ -872,7 +875,7 @@ function decrypt($ciphertext) $this->dechanged = false; } - if ($this->mode == CRYPT_MODE_CFB && $this->continuousBuffer) { + if (false && $this->continuousBuffer) { $iv = &$this->decryptIV; $pos = &$this->debuffer['pos']; $len = strlen($ciphertext); @@ -1274,7 +1277,7 @@ function _setupMcrypt() CRYPT_MODE_CTR => 'ctr', CRYPT_MODE_ECB => MCRYPT_MODE_ECB, CRYPT_MODE_CBC => MCRYPT_MODE_CBC, - CRYPT_MODE_CFB => 'ncfb', + CRYPT_MODE_CFB => 'cfb', CRYPT_MODE_OFB => MCRYPT_MODE_NOFB, CRYPT_MODE_STREAM => MCRYPT_MODE_STREAM, ); @@ -1285,13 +1288,13 @@ function _setupMcrypt() // we need the $ecb mcrypt resource (only) in MODE_CFB with enableContinuousBuffer() // to workaround mcrypt's broken ncfb implementation in buffered mode // see: {@link http://phpseclib.sourceforge.net/cfb-demo.phps} - if ($this->mode == CRYPT_MODE_CFB) { + if (false) { $this->ecb = mcrypt_module_open($this->cipher_name_mcrypt, '', MCRYPT_MODE_ECB, ''); } } // else should mcrypt_generic_deinit be called? - if ($this->mode == CRYPT_MODE_CFB) { + if (false) { mcrypt_generic_init($this->ecb, $this->key, str_repeat("\0", $this->block_size)); } } diff --git a/src/shoghicp/BigBrother/BigBrother.php b/src/shoghicp/BigBrother/BigBrother.php index e8256ba7..3a54b2ab 100644 --- a/src/shoghicp/BigBrother/BigBrother.php +++ b/src/shoghicp/BigBrother/BigBrother.php @@ -65,6 +65,10 @@ class_exists("phpseclib\\Crypt\\AES", true); //TODO: work on online mode $this->onlineMode = (bool) $this->getConfig()->get("online-mode"); + if($this->onlineMode and !function_exists("mcrypt_generic_init")){ + $this->onlineMode = false; + $this->getLogger()->notice("no mcrypt detected, online-mode has been disabled"); + } if(Info::CURRENT_PROTOCOL === 16){ $this->translator = new Translator_16(); @@ -76,11 +80,10 @@ class_exists("phpseclib\\Crypt\\AES", true); $this->rsa = new RSA(); - - $this->getServer()->getPluginManager()->registerEvents($this, $this); if($this->onlineMode){ + $this->getLogger()->info("Server is being started in the background"); $task = new GeneratePrivateKey($this->getServer()->getLogger(), $this->getServer()->getLoader()); $this->getServer()->getScheduler()->scheduleAsyncTask($task); }else{ diff --git a/src/shoghicp/BigBrother/DesktopPlayer.php b/src/shoghicp/BigBrother/DesktopPlayer.php index 980b2fd7..752d0da3 100644 --- a/src/shoghicp/BigBrother/DesktopPlayer.php +++ b/src/shoghicp/BigBrother/DesktopPlayer.php @@ -24,21 +24,25 @@ use pocketmine\level\Position; use pocketmine\network\protocol\Info; use pocketmine\network\protocol\LoginPacket; +use pocketmine\network\protocol\SetEntityMotionPacket; use pocketmine\network\protocol\SetTimePacket; use pocketmine\network\SourceInterface; use pocketmine\Player; use pocketmine\scheduler\CallbackTask; use pocketmine\Server; use pocketmine\tile\Spawnable; +use pocketmine\utils\TextFormat; use pocketmine\utils\Utils; use shoghicp\BigBrother\network\protocol\ChunkDataPacket; use shoghicp\BigBrother\network\protocol\EncryptionRequestPacket; use shoghicp\BigBrother\network\protocol\EncryptionResponsePacket; +use shoghicp\BigBrother\network\protocol\EntityTeleportPacket; use shoghicp\BigBrother\network\protocol\KeepAlivePacket; use shoghicp\BigBrother\network\protocol\LoginDisconnectPacket; use shoghicp\BigBrother\network\protocol\LoginStartPacket; use shoghicp\BigBrother\network\protocol\LoginSuccessPacket; use shoghicp\BigBrother\network\protocol\PlayDisconnectPacket; +use shoghicp\BigBrother\network\protocol\SpawnPlayerPacket; use shoghicp\BigBrother\network\ProtocolInterface; use shoghicp\BigBrother\tasks\AuthenticateOnline; use shoghicp\BigBrother\utils\Binary; @@ -46,8 +50,9 @@ class DesktopPlayer extends Player{ private $bigBrother_status = 0; //0 = log in, 1 = playing - private $bigBrother_uuid; - private $bigBrother_formatedUUID; + protected $bigBrother_uuid; + protected $bigBrother_formatedUUID; + protected $bigBrother_properties = []; private $bigBrother_checkToken; private $bigBrother_secret; private $bigBrother_username; @@ -172,7 +177,54 @@ public function sendNextChunk(){ } } - public function bigBrother_authenticate($username, $uuid, $onlineMode){ + public function spawnTo(Player $player){ + if($player instanceof DesktopPlayer){ + if($this !== $player and $this->spawned === true and $player->getLevel() === $this->getLevel() and $player->canSee($this)){ + $this->hasSpawned[$player->getID()] = $player; + $pk = new SpawnPlayerPacket(); + if($player->getRemoveFormat()){ + $pk->name = TextFormat::clean($this->nameTag); + }else{ + $pk->name = $this->nameTag; + } + $pk->eid = $this->getID(); + $pk->uuid = $this->bigBrother_formatedUUID; + $pk->x = $this->x; + $pk->z = $this->y; + $pk->y = $this->z; + $pk->yaw = $this->yaw; + $pk->pitch = $this->pitch; + $pk->item = $this->inventory->getItemInHand()->getID(); + $pk->metadata = $this->getData(); + $pk->data = $this->bigBrother_properties; + $player->interface->putRawPacket($player, $pk); + + $pk = new EntityTeleportPacket(); + $pk->eid = $this->getID(); + $pk->x = $this->x; + $pk->z = $this->y; + $pk->y = $this->z; + $pk->yaw = $this->yaw; + $pk->pitch = $this->pitch; + $player->interface->putRawPacket($player, $pk); + + $pk = new SetEntityMotionPacket(); + $pk->eid = $this->getID(); + $pk->speedX = $this->motionX; + $pk->speedY = $this->motionY; + $pk->speedZ = $this->motionZ; + $player->dataPacket($pk); + + $this->inventory->sendHeldItem($player); + + $this->inventory->sendArmorContents($player); + } + }else{ + parent::spawnTo($player); + } + } + + public function bigBrother_authenticate($username, $uuid, $onlineModeData = null){ if($this->bigBrother_status === 0){ $this->bigBrother_uuid = $uuid; $this->bigBrother_formatedUUID = Binary::UUIDtoString($this->bigBrother_uuid); @@ -182,6 +234,9 @@ public function bigBrother_authenticate($username, $uuid, $onlineMode){ $pk->name = $this->username; $this->interface->putRawPacket($this, $pk); $this->bigBrother_status = 1; + if($onlineModeData !== null and is_array($onlineModeData)){ + $this->bigBrother_properties = $onlineModeData; + } $this->tasks[] = $this->server->getScheduler()->scheduleDelayedRepeatingTask(new CallbackTask([$this, "bigBrother_sendKeepAlive"]), 180, 2); $this->server->getScheduler()->scheduleDelayedTask(new CallbackTask([$this, "bigBrother_authenticationCallback"], [$username]), 1); @@ -220,7 +275,7 @@ public function bigBrother_handleAuthentication(BigBrother $plugin, $username, $ $pk->verifyToken = $this->bigBrother_checkToken = Utils::getRandomBytes(4, false, true, $pk->publicKey); $this->interface->putRawPacket($this, $pk); }else{ - $this->bigBrother_authenticate($username, "00000000000040008000000000000000", false); + $this->bigBrother_authenticate($username, "00000000000040008000000000000000", null); } } @@ -276,15 +331,11 @@ public function bigBrother_handleAuthentication(BigBrother $plugin, $username, $ public function close($message = "", $reason = "generic reason"){ if($this->bigBrother_status === 0){ $pk = new LoginDisconnectPacket(); - $pk->reason = json_encode([ - "text" => $reason === "" ? "You have been disconnected." : $reason - ]); + $pk->reason = TextFormat::toJSON($reason === "" ? "You have been disconnected." : $reason); $this->interface->putRawPacket($this, $pk); }else{ $pk = new PlayDisconnectPacket(); - $pk->reason = json_encode([ - "text" => $reason === "" ? "You have been disconnected." : $reason - ]); + $pk->reason = TextFormat::toJSON($reason === "" ? "You have been disconnected." : $reason);; $this->interface->putRawPacket($this, $pk); } parent::close($message, $reason); diff --git a/src/shoghicp/BigBrother/network/ServerThread.php b/src/shoghicp/BigBrother/network/ServerThread.php index 114dd791..20849cc8 100644 --- a/src/shoghicp/BigBrother/network/ServerThread.php +++ b/src/shoghicp/BigBrother/network/ServerThread.php @@ -55,7 +55,6 @@ public function __construct(\ThreadedLogger $logger, \SplAutoloader $loader, $po $this->loadPaths = array_reverse($loadPaths); $this->shutdown = false; - $sockets = []; if(($sockets = stream_socket_pair((strtoupper(substr(PHP_OS, 0, 3)) === 'WIN' ? STREAM_PF_INET : STREAM_PF_UNIX), STREAM_SOCK_STREAM, STREAM_IPPROTO_IP)) === false){ throw new \Exception("Could not create IPC streams. Reason: ".socket_strerror(socket_last_error())); } diff --git a/src/shoghicp/BigBrother/network/Session.php b/src/shoghicp/BigBrother/network/Session.php index 5e2da263..5b4c8fac 100644 --- a/src/shoghicp/BigBrother/network/Session.php +++ b/src/shoghicp/BigBrother/network/Session.php @@ -18,6 +18,7 @@ namespace shoghicp\BigBrother\network; use phpseclib\Crypt\AES; +use pocketmine\utils\TextFormat; use shoghicp\BigBrother\network\protocol\LoginDisconnectPacket; use shoghicp\BigBrother\network\protocol\PingPacket; use shoghicp\BigBrother\utils\Binary; @@ -44,8 +45,6 @@ public function __construct(ServerManager $manager, $identifier, $socket){ $this->address = substr($addr, 0, $final); $this->aes = new AES(CRYPT_AES_MODE_CFB); - $this->aes->setKeyLength(128); - $this->aes->disablePadding(); } public function write($data){ @@ -158,11 +157,11 @@ public function process(){ $this->status = -1; if($protocol < Info::PROTOCOL){ $packet = new LoginDisconnectPacket(); - $packet->reason = "{\"text\":\"§lOutdated client!§r\\n\\nPlease use ".Info::VERSION."\"}"; + $packet->reson = TextFormat::toJSON(TextFormat::BOLD . "Outdated client!".TextFormat::RESET."\n\nPlease use ".Info::VERSION); $this->writePacket($packet); }elseif($protocol > Info::PROTOCOL){ $packet = new LoginDisconnectPacket(); - $packet->reason = "{\"text\":\"§lOutdated server!§r\\n\\nI'm using ".Info::VERSION."\"}"; + $packet->reson = TextFormat::toJSON(TextFormat::BOLD . "Outdated server!".TextFormat::RESET."\n\nI'm using ".Info::VERSION); $this->writePacket($packet); }else{ $this->manager->openSession($this); diff --git a/src/shoghicp/BigBrother/network/protocol/EntityTeleportPacket.php b/src/shoghicp/BigBrother/network/protocol/EntityTeleportPacket.php index 0f04dd9a..2e6a722d 100644 --- a/src/shoghicp/BigBrother/network/protocol/EntityTeleportPacket.php +++ b/src/shoghicp/BigBrother/network/protocol/EntityTeleportPacket.php @@ -42,12 +42,6 @@ public function encode(){ } public function decode(){ - $this->x = $this->getDouble(); - $this->y = $this->getDouble(); - $this->headY = $this->getDouble(); - $this->z = $this->getDouble(); - $this->yaw = $this->getFloat(); - $this->pitch = $this->getFloat(); - $this->onGround = $this->getByte() > 0; + } } \ No newline at end of file diff --git a/src/shoghicp/BigBrother/network/protocol/SpawnPlayerPacket.php b/src/shoghicp/BigBrother/network/protocol/SpawnPlayerPacket.php index 830f4061..1309bb38 100644 --- a/src/shoghicp/BigBrother/network/protocol/SpawnPlayerPacket.php +++ b/src/shoghicp/BigBrother/network/protocol/SpawnPlayerPacket.php @@ -51,8 +51,8 @@ public function encode(){ $this->putInt(intval($this->x * 32)); $this->putInt(intval($this->y * 32)); $this->putInt(intval($this->z * 32)); - $this->putByte((int) ($this->yaw * (256 / 360))); - $this->putByte((int) ($this->pitch * (256 / 360))); + $this->putByte(($this->yaw / 360) << 8); + $this->putByte(($this->pitch / 360) << 8); $this->putShort($this->item); $this->put(Binary::writeMetadata($this->metadata)); } diff --git a/src/shoghicp/BigBrother/network/translation/Translator_16.php b/src/shoghicp/BigBrother/network/translation/Translator_16.php index 33fd45ad..99f896b3 100644 --- a/src/shoghicp/BigBrother/network/translation/Translator_16.php +++ b/src/shoghicp/BigBrother/network/translation/Translator_16.php @@ -21,9 +21,12 @@ use pocketmine\network\protocol\Info; use pocketmine\network\protocol\MessagePacket; use pocketmine\network\protocol\MovePlayerPacket; +use pocketmine\utils\TextFormat; use shoghicp\BigBrother\DesktopPlayer; use shoghicp\BigBrother\network\Packet; +use shoghicp\BigBrother\network\protocol\BlockChangePacket; use shoghicp\BigBrother\network\protocol\DestroyEntitiesPacket; +use shoghicp\BigBrother\network\protocol\EntityHeadLookPacket; use shoghicp\BigBrother\network\protocol\EntityTeleportPacket; use shoghicp\BigBrother\network\protocol\JoinGamePacket; use shoghicp\BigBrother\network\protocol\PlayerPositionAndLookPacket; @@ -85,6 +88,16 @@ public function interfaceToServer(DesktopPlayer $player, Packet $packet){ public function serverToInterface(DesktopPlayer $player, DataPacket $packet){ switch($packet->pid()){ + + case Info::UPDATE_BLOCK_PACKET: + $pk = new BlockChangePacket(); + $pk->x = $packet->x; + $pk->y = $packet->y; + $pk->z = $packet->z; + $pk->blockId = $packet->block; + $pk->blockMeta = $packet->meta; + return $pk; + case Info::START_GAME_PACKET: $packets = []; $pk = new JoinGamePacket(); @@ -93,7 +106,7 @@ public function serverToInterface(DesktopPlayer $player, DataPacket $packet){ $pk->dimension = 0; $pk->difficulty = $player->getServer()->getDifficulty(); $pk->maxPlayers = $player->getServer()->getMaxPlayers(); - $pk->levelType = "flat";//"default"; + $pk->levelType = "default"; $packets[] = $pk; $pk = new SpawnPositionPacket(); @@ -115,9 +128,7 @@ public function serverToInterface(DesktopPlayer $player, DataPacket $packet){ case Info::MESSAGE_PACKET: $pk = new STCChatPacket(); - $pk->message = json_encode([ - "text" => $packet->message - ]); + $pk->message = TextFormat::toJSON($packet->message); return $pk; case Info::SET_TIME_PACKET: @@ -148,7 +159,9 @@ public function serverToInterface(DesktopPlayer $player, DataPacket $packet){ $pk->yaw = $packet->yaw; $pk->pitch = $packet->pitch; $pk->onGround = $player->isOnGround(); + return $pk; }else{ + $packets = []; $pk = new EntityTeleportPacket(); $pk->eid = $packet->eid; $pk->x = $packet->x; @@ -156,10 +169,17 @@ public function serverToInterface(DesktopPlayer $player, DataPacket $packet){ $pk->z = $packet->z; $pk->yaw = $packet->yaw; $pk->pitch = $packet->pitch; + $packets[] = $pk; + + $pk = new EntityHeadLookPacket(); + $pk->eid = $packet->eid; + $pk->yaw = $packet->yaw; + $packets[] = $pk; + return $packets; } - return $pk; case Info::MOVE_ENTITY_PACKET_POSROT: + $packets = []; $pk = new EntityTeleportPacket(); $pk->eid = $packet->eid; $pk->x = $packet->x; @@ -167,7 +187,13 @@ public function serverToInterface(DesktopPlayer $player, DataPacket $packet){ $pk->z = $packet->z; $pk->yaw = $packet->yaw; $pk->pitch = $packet->pitch; - return $pk; + $packets[] = $pk; + + $pk = new EntityHeadLookPacket(); + $pk->eid = $packet->eid; + $pk->yaw = $packet->yaw; + $packets[] = $pk; + return $packets; case Info::ADD_PLAYER_PACKET: $packets = []; @@ -194,6 +220,8 @@ public function serverToInterface(DesktopPlayer $player, DataPacket $packet){ $packets[] = $pk; return $packets; + + default: return null; } diff --git a/src/shoghicp/BigBrother/tasks/AuthenticateOnline.php b/src/shoghicp/BigBrother/tasks/AuthenticateOnline.php index 418d1b48..72d0e4cd 100644 --- a/src/shoghicp/BigBrother/tasks/AuthenticateOnline.php +++ b/src/shoghicp/BigBrother/tasks/AuthenticateOnline.php @@ -42,9 +42,9 @@ public function onRun(){ public function onCompletion(Server $server){ foreach($server->getOnlinePlayers() as $clientID => $player){ if($player instanceof DesktopPlayer and $clientID === $this->clientID){ - $result = json_decode($this->getResult(), false); - if($result instanceof \stdClass and isset($result->id)){ - $player->bigBrother_authenticate($this->username, $result->id, true); + $result = json_decode($this->getResult(), true); + if(is_array($result) and isset($result["id"])){ + $player->bigBrother_authenticate($this->username, $result["id"], $result["properties"]); }else{ $player->close("", "User not premium"); }