Merge branch '3.0'

This commit is contained in:
terrafrost 2022-01-30 01:19:37 -06:00
commit 48259b20b3
10 changed files with 113 additions and 43 deletions

View File

@ -158,9 +158,9 @@ abstract class Strings
/** /**
* Create SSH2-style string * Create SSH2-style string
* *
* @param string[] ...$elements * @param string|int|float|array|bool ...$elements
* @access public * @access public
* @return mixed * @return string
*/ */
public static function packSSH2(...$elements) public static function packSSH2(...$elements)
{ {

View File

@ -123,6 +123,12 @@ abstract class AsymmetricKey
*/ */
private $comment; private $comment;
/**
* @param string $type
* @return string
*/
abstract public function toString($type, array $options = []);
/** /**
* The constructor * The constructor
*/ */
@ -245,7 +251,7 @@ abstract class AsymmetricKey
* @param string $type * @param string $type
* @param string $key * @param string $key
* @param string $password optional * @param string $password optional
* @return AsymmetricKey * @return static
*/ */
public static function loadFormat($type, $key, $password = false) public static function loadFormat($type, $key, $password = false)
{ {

View File

@ -213,6 +213,13 @@ abstract class SymmetricKey
self::ENGINE_OPENSSL_GCM => 'OpenSSL (GCM)' self::ENGINE_OPENSSL_GCM => 'OpenSSL (GCM)'
]; ];
/** @var string|null */
public $fixed;
/** @var string|null */
public $invocation_counter;
/** @var string|null */
public $name;
/** /**
* The Encryption Mode * The Encryption Mode
* *

View File

@ -78,7 +78,7 @@ abstract class DH extends AsymmetricKey
* - a string (eg. diffie-hellman-group14-sha1) * - a string (eg. diffie-hellman-group14-sha1)
* *
* @access public * @access public
* @return \phpseclib3\Crypt\DH|bool * @return Parameters
*/ */
public static function createParameters(...$args) public static function createParameters(...$args)
{ {

View File

@ -69,6 +69,11 @@ class Hash
*/ */
const PADDING_SHAKE = 3; const PADDING_SHAKE = 3;
/** @var int|false */
public $etm;
/** @var string|false */
public $name;
/** /**
* Padding Type * Padding Type
* *

View File

@ -51,7 +51,7 @@ abstract class Random
} }
try { try {
return \random_bytes($length); return random_bytes($length);
} catch (\Exception $e) { } catch (\Exception $e) {
// random_compat will throw an Exception, which in PHP 5 does not implement Throwable // random_compat will throw an Exception, which in PHP 5 does not implement Throwable
} catch (\Throwable $e) { } catch (\Throwable $e) {

View File

@ -116,6 +116,18 @@ class SFTP extends SSH2
*/ */
private $status_codes = []; private $status_codes = [];
/** @var array<int, string> */
private $attributes;
/** @var array<int, string> */
private $open_flags;
/** @var array<int, string> */
private $open_flags5;
/** @var array<int, string> */
private $file_types;
/** /**
* The Request ID * The Request ID
* *
@ -188,7 +200,7 @@ class SFTP extends SSH2
/** /**
* Current working directory * Current working directory
* *
* @var string * @var string|bool
* @see self::realpath() * @see self::realpath()
* @see self::chdir() * @see self::chdir()
* @access private * @access private
@ -242,7 +254,7 @@ class SFTP extends SSH2
* *
* @see self::__construct() * @see self::__construct()
* @see self::get() * @see self::get()
* @var array * @var int
* @access private * @access private
*/ */
private $max_sftp_packet; private $max_sftp_packet;
@ -781,7 +793,7 @@ class SFTP extends SSH2
/** /**
* Returns the current directory name * Returns the current directory name
* *
* @return string|false * @return string|bool
* @access public * @access public
*/ */
public function pwd() public function pwd()
@ -1226,7 +1238,7 @@ class SFTP extends SSH2
* $sftp->setListOrder(); * $sftp->setListOrder();
* Don't do any sort of sorting * Don't do any sort of sorting
* *
* @param string[] ...$args * @param string ...$args
* @access public * @access public
*/ */
public function setListOrder(...$args) public function setListOrder(...$args)
@ -1809,7 +1821,7 @@ class SFTP extends SSH2
$packet = Strings::packSSH2('s', $path); $packet = Strings::packSSH2('s', $path);
$packet.= $this->version >= 4 ? $packet.= $this->version >= 4 ?
pack('Ca*', NET_SFTP_TYPE_UNKNOWN, $attr) : pack('Ca*', NET_SFTP_TYPE_UNKNOWN, $attr) :
$atr; $attr;
$this->send_sftp_packet(NET_SFTP_SETSTAT, $packet); $this->send_sftp_packet(NET_SFTP_SETSTAT, $packet);
$i++; $i++;
@ -3131,7 +3143,7 @@ class SFTP extends SSH2
// see https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-13#section-7.4 // see https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-13#section-7.4
// represents the number of bytes that the file consumes on the disk. will // represents the number of bytes that the file consumes on the disk. will
// usually be larger than the 'size' field // usually be larger than the 'size' field
list($attr['allocation-size']) = Strings::unpack('Q', $response); list($attr['allocation-size']) = Strings::unpackSSH2('Q', $response);
break; break;
case NET_SFTP_ATTR_TEXT_HINT: // 0x00000800 case NET_SFTP_ATTR_TEXT_HINT: // 0x00000800
// https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-13#section-7.10 // https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-13#section-7.10
@ -3146,7 +3158,7 @@ class SFTP extends SSH2
break; break;
case NET_SFTP_ATTR_LINK_COUNT: // 0x00002000 case NET_SFTP_ATTR_LINK_COUNT: // 0x00002000
// see https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-13#section-7.12 // see https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-13#section-7.12
list($attr['link-count']) = Strings::unpackSS2('N', $response); list($attr['link-count']) = Strings::unpackSSH2('N', $response);
break; break;
case NET_SFTP_ATTR_UNTRANSLATED_NAME:// 0x00004000 case NET_SFTP_ATTR_UNTRANSLATED_NAME:// 0x00004000
// see https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-13#section-7.13 // see https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-13#section-7.13

View File

@ -204,7 +204,7 @@ class SSH2
/** /**
* The Socket Object * The Socket Object
* *
* @var object * @var resource|closed-resource|null
* @access private * @access private
*/ */
public $fsock; public $fsock;
@ -711,7 +711,7 @@ class SSH2
* Interactive Buffer * Interactive Buffer
* *
* @see self::read() * @see self::read()
* @var array * @var string
* @access private * @access private
*/ */
private $interactiveBuffer = ''; private $interactiveBuffer = '';
@ -756,7 +756,7 @@ class SSH2
* Real-time log file pointer * Real-time log file pointer
* *
* @see self::_append_log() * @see self::_append_log()
* @var resource * @var resource|closed-resource
* @access private * @access private
*/ */
private $realtime_log_file; private $realtime_log_file;
@ -798,7 +798,7 @@ class SSH2
/** /**
* Time of first network activity * Time of first network activity
* *
* @var int * @var float
* @access private * @access private
*/ */
private $last_packet; private $last_packet;
@ -966,7 +966,7 @@ class SSH2
/** /**
* A System_SSH_Agent for use in the SSH2 Agent Forwarding scenario * A System_SSH_Agent for use in the SSH2 Agent Forwarding scenario
* *
* @var \phpseclib3\System\Ssh\Agent * @var Agent
* @access private * @access private
*/ */
private $agent; private $agent;
@ -975,7 +975,7 @@ class SSH2
* Connection storage to replicates ssh2 extension functionality: * Connection storage to replicates ssh2 extension functionality:
* {@link http://php.net/manual/en/wrappers.ssh2.php#refsect1-wrappers.ssh2-examples} * {@link http://php.net/manual/en/wrappers.ssh2.php#refsect1-wrappers.ssh2-examples}
* *
* @var SSH2[] * @var array<string, SSH2|\WeakReference<SSH2>>
*/ */
private static $connections; private static $connections;
@ -1063,7 +1063,7 @@ class SSH2
/** /**
* Decompression method * Decompression method
* *
* @var resource|object * @var int
* @access private * @access private
*/ */
private $decompress = self::NET_SSH2_COMPRESSION_NONE; private $decompress = self::NET_SSH2_COMPRESSION_NONE;
@ -1071,7 +1071,7 @@ class SSH2
/** /**
* Compression context * Compression context
* *
* @var int * @var resource|false|null
* @access private * @access private
*/ */
private $compress_context; private $compress_context;
@ -1200,7 +1200,13 @@ class SSH2
31 => 'NET_SSH2_MSG_KEX_ECDH_REPLY'] 31 => 'NET_SSH2_MSG_KEX_ECDH_REPLY']
); );
self::$connections[$this->getResourceId()] = class_exists('WeakReference') ? \WeakReference::create($this) : $this; /**
* Typehint is required due to a bug in Psalm: https://github.com/vimeo/psalm/issues/7508
* @var \WeakReference<SSH2>|SSH2
*/
self::$connections[$this->getResourceId()] = class_exists('WeakReference')
? \WeakReference::create($this)
: $this;
if (is_resource($host)) { if (is_resource($host)) {
$this->fsock = $host; $this->fsock = $host;
@ -1411,7 +1417,7 @@ class SSH2
if (!$this->send_kex_first) { if (!$this->send_kex_first) {
$response = $this->get_binary_packet(); $response = $this->get_binary_packet();
if (!strlen($response) || ord($response[0]) != NET_SSH2_MSG_KEXINIT) { if (is_bool($response) || !strlen($response) || ord($response[0]) != NET_SSH2_MSG_KEXINIT) {
$this->bitmap = 0; $this->bitmap = 0;
throw new \UnexpectedValueException('Expected SSH_MSG_KEXINIT'); throw new \UnexpectedValueException('Expected SSH_MSG_KEXINIT');
} }
@ -1546,7 +1552,11 @@ class SSH2
$kexinit_payload_server = $this->get_binary_packet(); $kexinit_payload_server = $this->get_binary_packet();
if (!strlen($kexinit_payload_server) || ord($kexinit_payload_server[0]) != NET_SSH2_MSG_KEXINIT) { if (
is_bool($kexinit_payload_server)
|| !strlen($kexinit_payload_server)
|| ord($kexinit_payload_server[0]) != NET_SSH2_MSG_KEXINIT
) {
$this->disconnect_helper(NET_SSH2_DISCONNECT_PROTOCOL_ERROR); $this->disconnect_helper(NET_SSH2_DISCONNECT_PROTOCOL_ERROR);
throw new \UnexpectedValueException('Expected SSH_MSG_KEXINIT'); throw new \UnexpectedValueException('Expected SSH_MSG_KEXINIT');
} }
@ -2159,7 +2169,7 @@ class SSH2
* Login Helper * Login Helper
* *
* @param string $username * @param string $username
* @param string[] ...$args * @param string ...$args
* @return bool * @return bool
* @see self::_login_helper() * @see self::_login_helper()
* @access private * @access private
@ -2402,7 +2412,7 @@ class SSH2
* See {@link http://tools.ietf.org/html/rfc4256 RFC4256} for details. This is not a full-featured keyboard-interactive authenticator. * See {@link http://tools.ietf.org/html/rfc4256 RFC4256} for details. This is not a full-featured keyboard-interactive authenticator.
* *
* @param string $username * @param string $username
* @param string $password * @param string|array $password
* @return bool * @return bool
* @access private * @access private
*/ */
@ -2425,7 +2435,7 @@ class SSH2
/** /**
* Handle the keyboard-interactive requests / responses. * Handle the keyboard-interactive requests / responses.
* *
* @param mixed[] ...$responses * @param string|array ...$responses
* @return bool * @return bool
* @throws \RuntimeException on connection error * @throws \RuntimeException on connection error
* @access private * @access private
@ -2719,12 +2729,12 @@ class SSH2
* In all likelihood, this is not a feature you want to be taking advantage of. * In all likelihood, this is not a feature you want to be taking advantage of.
* *
* @param string $command * @param string $command
* @param callback $callback * @return string|bool
* @return string * @psalm-return ($callback is callable ? bool : string|bool)
* @throws \RuntimeException on connection error * @throws \RuntimeException on connection error
* @access public * @access public
*/ */
public function exec($command, $callback = null) public function exec($command, callable $callback = null)
{ {
$this->curTimeout = $this->timeout; $this->curTimeout = $this->timeout;
$this->is_timeout = false; $this->is_timeout = false;
@ -3290,12 +3300,15 @@ class SSH2
* *
* @see self::_send_binary_packet() * @see self::_send_binary_packet()
* @param bool $skip_channel_filter * @param bool $skip_channel_filter
* @return string * @return bool|string
* @access private * @access private
*/ */
private function get_binary_packet($skip_channel_filter = false) private function get_binary_packet($skip_channel_filter = false)
{ {
if ($skip_channel_filter) { if ($skip_channel_filter) {
if (!is_resource($this->fsock)) {
throw new \InvalidArgumentException('fsock is not a resource.');
}
$read = [$this->fsock]; $read = [$this->fsock];
$write = $except = null; $write = $except = null;
@ -3314,9 +3327,6 @@ class SSH2
return true; return true;
} }
$read = [$this->fsock];
$write = $except = null;
$start = microtime(true); $start = microtime(true);
if ($this->keepAlive > 0 && $this->keepAlive < $this->curTimeout) { if ($this->keepAlive > 0 && $this->keepAlive < $this->curTimeout) {
@ -3590,7 +3600,7 @@ class SSH2
* @see self::_get_binary_packet() * @see self::_get_binary_packet()
* @param string $payload * @param string $payload
* @param bool $skip_channel_filter * @param bool $skip_channel_filter
* @return string * @return string|bool
* @access private * @access private
*/ */
private function filter($payload, $skip_channel_filter) private function filter($payload, $skip_channel_filter)
@ -3624,7 +3634,7 @@ class SSH2
} }
// see http://tools.ietf.org/html/rfc4252#section-5.4; only called when the encryption has been activated and when we haven't already logged in // see http://tools.ietf.org/html/rfc4252#section-5.4; only called when the encryption has been activated and when we haven't already logged in
if (($this->bitmap & self::MASK_CONNECTED) && !$this->isAuthenticated() && ord($payload[0]) == NET_SSH2_MSG_USERAUTH_BANNER) { if (($this->bitmap & self::MASK_CONNECTED) && !$this->isAuthenticated() && !is_bool($payload) && ord($payload[0]) == NET_SSH2_MSG_USERAUTH_BANNER) {
Strings::shift($payload, 1); Strings::shift($payload, 1);
list($this->banner_message) = Strings::unpackSSH2('s', $payload); list($this->banner_message) = Strings::unpackSSH2('s', $payload);
$payload = $this->get_binary_packet(); $payload = $this->get_binary_packet();
@ -3632,8 +3642,8 @@ class SSH2
// only called when we've already logged in // only called when we've already logged in
if (($this->bitmap & self::MASK_CONNECTED) && $this->isAuthenticated()) { if (($this->bitmap & self::MASK_CONNECTED) && $this->isAuthenticated()) {
if ($payload === true) { if (is_bool($payload)) {
return true; return $payload;
} }
switch (ord($payload[0])) { switch (ord($payload[0])) {
@ -4364,7 +4374,7 @@ class SSH2
} }
$this->bitmap = 0; $this->bitmap = 0;
if (is_resource($this->fsock) && get_resource_type($this->fsock) == 'stream') { if (is_resource($this->fsock) && get_resource_type($this->fsock) === 'stream') {
fclose($this->fsock); fclose($this->fsock);
} }
@ -5115,11 +5125,12 @@ class SSH2
/** /**
* Return all excising connections * Return all excising connections
* *
* @return SSH2[] * @return array<string, SSH2>
*/ */
public static function getConnections() public static function getConnections()
{ {
if (!class_exists('WeakReference')) { if (!class_exists('WeakReference')) {
/** @var array<string, SSH2> */
return self::$connections; return self::$connections;
} }
$temp = []; $temp = [];

29
psalm.xml Normal file
View File

@ -0,0 +1,29 @@
<?xml version="1.0"?>
<psalm
errorLevel="6"
resolveFromConfigFile="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://getpsalm.org/schema/config"
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
findUnusedPsalmSuppress="true"
sealAllMethods="true"
>
<projectFiles>
<directory name="phpseclib/Net"/>
</projectFiles>
<fileExtensions>
<extension name=".php"/>
</fileExtensions>
<issueHandlers>
<Trace>
<errorLevel type="error">
<directory name="."/>
</errorLevel>
</Trace>
<UndefinedConstant>
<errorLevel type="suppress">
<directory name="phpseclib/Net"/>
</errorLevel>
</UndefinedConstant>
</issueHandlers>
</psalm>