mirror of
https://github.com/phpseclib/phpseclib.git
synced 2024-11-08 23:00:58 +00:00
Remove Dynamic Constants
Remove Dynamic Constants
This commit is contained in:
parent
cc65aa3b0e
commit
61f2bc1c06
@ -17,10 +17,5 @@
|
||||
<directory name=".."/>
|
||||
</errorLevel>
|
||||
</Trace>
|
||||
<UndefinedConstant>
|
||||
<errorLevel type="suppress">
|
||||
<directory name="../phpseclib/Net"/>
|
||||
</errorLevel>
|
||||
</UndefinedConstant>
|
||||
</issueHandlers>
|
||||
</psalm>
|
||||
|
42
phpseclib/Common/ConstantUtilityTrait.php
Normal file
42
phpseclib/Common/ConstantUtilityTrait.php
Normal file
@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace phpseclib3\Common;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
trait ConstantUtilityTrait
|
||||
{
|
||||
/** @var string[]|null */
|
||||
private static $valueToConstantNameMap = null;
|
||||
|
||||
/**
|
||||
* @param string|int $value
|
||||
* @return string|null
|
||||
*/
|
||||
public static function findConstantNameByValue($value)
|
||||
{
|
||||
if (!self::$valueToConstantNameMap) {
|
||||
$reflectionClass = new \ReflectionClass(static::class);
|
||||
$constantNameToValueMap = $reflectionClass->getConstants();
|
||||
self::$valueToConstantNameMap = array_flip($constantNameToValueMap);
|
||||
}
|
||||
if (isset(self::$valueToConstantNameMap[$value])) {
|
||||
return self::$valueToConstantNameMap[$value];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|int $value
|
||||
* @return string
|
||||
*/
|
||||
public static function getConstantNameByValue($value)
|
||||
{
|
||||
$constantName = static::findConstantNameByValue($value);
|
||||
if ($constantName === null) {
|
||||
throw new \InvalidArgumentException(sprintf('"%s" does not have constant with value "%s".', static::class, $value));
|
||||
}
|
||||
return $constantName;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
40
phpseclib/Net/SFTP/Attribute.php
Normal file
40
phpseclib/Net/SFTP/Attribute.php
Normal file
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace phpseclib3\Net\SFTP;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
abstract class Attribute
|
||||
{
|
||||
const SIZE = 0x00000001;
|
||||
const UIDGID = 0x00000002; // defined in SFTPv3, removed in SFTPv4+
|
||||
const OWNERGROUP = 0x00000080; // defined in SFTPv4+
|
||||
const PERMISSIONS = 0x00000004;
|
||||
const ACCESSTIME = 0x00000008;
|
||||
const CREATETIME = 0x00000010; // SFTPv4+
|
||||
const MODIFYTIME = 0x00000020;
|
||||
const ACL = 0x00000040;
|
||||
const SUBSECOND_TIMES = 0x00000100;
|
||||
const BITS = 0x00000200; // SFTPv5+
|
||||
const ALLOCATION_SIZE = 0x00000400; // SFTPv6+
|
||||
const TEXT_HINT = 0x00000800;
|
||||
const MIME_TYPE = 0x00001000;
|
||||
const LINK_COUNT = 0x00002000;
|
||||
const UNTRANSLATED_NAME = 0x00004000;
|
||||
const CTIME = 0x00008000;
|
||||
// 0x80000000 will yield a floating point on 32-bit systems and converting floating points to integers
|
||||
// yields inconsistent behavior depending on how php is compiled. so we left shift -1 (which, in
|
||||
// two's compliment, consists of all 1 bits) by 31. on 64-bit systems this'll yield 0xFFFFFFFF80000000.
|
||||
// that's not a problem, however, and 'anded' and a 32-bit number, as all the leading 1 bits are ignored.
|
||||
const EXTENDED = (-1 << 31) & 0xFFFFFFFF;
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function getConstants()
|
||||
{
|
||||
$reflectionClass = new \ReflectionClass(static::class);
|
||||
return $reflectionClass->getConstants();
|
||||
}
|
||||
}
|
21
phpseclib/Net/SFTP/FileType.php
Normal file
21
phpseclib/Net/SFTP/FileType.php
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace phpseclib3\Net\SFTP;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
abstract class FileType
|
||||
{
|
||||
const REGULAR = 1;
|
||||
const DIRECTORY = 2;
|
||||
const SYMLINK = 3;
|
||||
const SPECIAL = 4;
|
||||
const UNKNOWN = 5;
|
||||
// the following types were first defined for use in SFTPv5+
|
||||
// http://tools.ietf.org/html/draft-ietf-secsh-filexfer-05#section-5.2
|
||||
const SOCKET = 6;
|
||||
const CHAR_DEVICE = 7;
|
||||
const BLOCK_DEVICE = 8;
|
||||
const FIFO = 9;
|
||||
}
|
17
phpseclib/Net/SFTP/OpenFlag.php
Normal file
17
phpseclib/Net/SFTP/OpenFlag.php
Normal file
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace phpseclib3\Net\SFTP;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
abstract class OpenFlag
|
||||
{
|
||||
const READ = 0x00000001;
|
||||
const WRITE = 0x00000002;
|
||||
const APPEND = 0x00000004;
|
||||
const CREATE = 0x00000008;
|
||||
const TRUNCATE = 0x00000010;
|
||||
const EXCL = 0x00000020;
|
||||
const TEXT = 0x00000040; // defined in SFTPv4
|
||||
}
|
30
phpseclib/Net/SFTP/OpenFlag5.php
Normal file
30
phpseclib/Net/SFTP/OpenFlag5.php
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace phpseclib3\Net\SFTP;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
abstract class OpenFlag5
|
||||
{
|
||||
// when SSH_FXF_ACCESS_DISPOSITION is a 3 bit field that controls how the file is opened
|
||||
const CREATE_NEW = 0x00000000;
|
||||
const CREATE_TRUNCATE = 0x00000001;
|
||||
const OPEN_EXISTING = 0x00000002;
|
||||
const OPEN_OR_CREATE = 0x00000003;
|
||||
const TRUNCATE_EXISTING = 0x00000004;
|
||||
// the rest of the flags are not supported
|
||||
const APPEND_DATA = 0x00000008; // "the offset field of SS_FXP_WRITE requests is ignored"
|
||||
const APPEND_DATA_ATOMIC = 0x00000010;
|
||||
const TEXT_MODE = 0x00000020;
|
||||
const BLOCK_READ = 0x00000040;
|
||||
const BLOCK_WRITE = 0x00000080;
|
||||
const BLOCK_DELETE = 0x00000100;
|
||||
const BLOCK_ADVISORY = 0x00000200;
|
||||
const NOFOLLOW = 0x00000400;
|
||||
const DELETE_ON_CLOSE = 0x00000800;
|
||||
const ACCESS_AUDIT_ALARM_INFO = 0x00001000;
|
||||
const ACCESS_BACKUP = 0x00002000;
|
||||
const BACKUP_STREAM = 0x00004000;
|
||||
const OVERRIDE_OWNER = 0x00008000;
|
||||
}
|
42
phpseclib/Net/SFTP/PacketType.php
Normal file
42
phpseclib/Net/SFTP/PacketType.php
Normal file
@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace phpseclib3\Net\SFTP;
|
||||
|
||||
use phpseclib3\Common\ConstantUtilityTrait;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
abstract class PacketType
|
||||
{
|
||||
use ConstantUtilityTrait;
|
||||
|
||||
const INIT = 1;
|
||||
const VERSION = 2;
|
||||
const OPEN = 3;
|
||||
const CLOSE = 4;
|
||||
const READ = 5;
|
||||
const WRITE = 6;
|
||||
const LSTAT = 7;
|
||||
const SETSTAT = 9;
|
||||
const FSETSTAT = 10;
|
||||
const OPENDIR = 11;
|
||||
const READDIR = 12;
|
||||
const REMOVE = 13;
|
||||
const MKDIR = 14;
|
||||
const RMDIR = 15;
|
||||
const REALPATH = 16;
|
||||
const STAT = 17;
|
||||
const RENAME = 18;
|
||||
const READLINK = 19;
|
||||
const SYMLINK = 20;
|
||||
const LINK = 21;
|
||||
|
||||
const STATUS = 101;
|
||||
const HANDLE = 102;
|
||||
const DATA = 103;
|
||||
const NAME = 104;
|
||||
const ATTRS = 105;
|
||||
|
||||
const EXTENDED = 200;
|
||||
}
|
46
phpseclib/Net/SFTP/StatusCode.php
Normal file
46
phpseclib/Net/SFTP/StatusCode.php
Normal file
@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace phpseclib3\Net\SFTP;
|
||||
|
||||
use phpseclib3\Common\ConstantUtilityTrait;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
abstract class StatusCode
|
||||
{
|
||||
use ConstantUtilityTrait;
|
||||
|
||||
const OK = 0;
|
||||
const EOF = 1;
|
||||
const NO_SUCH_FILE = 2;
|
||||
const PERMISSION_DENIED = 3;
|
||||
const FAILURE = 4;
|
||||
const BAD_MESSAGE = 5;
|
||||
const NO_CONNECTION = 6;
|
||||
const CONNECTION_LOST = 7;
|
||||
const OP_UNSUPPORTED = 8;
|
||||
const INVALID_HANDLE = 9;
|
||||
const NO_SUCH_PATH = 10;
|
||||
const FILE_ALREADY_EXISTS = 11;
|
||||
const WRITE_PROTECT = 12;
|
||||
const NO_MEDIA = 13;
|
||||
const NO_SPACE_ON_FILESYSTEM = 14;
|
||||
const QUOTA_EXCEEDED = 15;
|
||||
const UNKNOWN_PRINCIPAL = 16;
|
||||
const LOCK_CONFLICT = 17;
|
||||
const DIR_NOT_EMPTY = 18;
|
||||
const NOT_A_DIRECTORY = 19;
|
||||
const INVALID_FILENAME = 20;
|
||||
const LINK_LOOP = 21;
|
||||
const CANNOT_DELETE = 22;
|
||||
const INVALID_PARAMETER = 23;
|
||||
const FILE_IS_A_DIRECTORY = 24;
|
||||
const BYTE_RANGE_LOCK_CONFLICT = 25;
|
||||
const BYTE_RANGE_LOCK_REFUSED = 26;
|
||||
const DELETE_PENDING = 27;
|
||||
const FILE_CORRUPT = 28;
|
||||
const OWNER_INVALID = 29;
|
||||
const GROUP_INVALID = 30;
|
||||
const NO_MATCHING_BYTE_RANGE_LOCK = 31;
|
||||
}
|
@ -20,6 +20,7 @@ namespace phpseclib3\Net\SFTP;
|
||||
use phpseclib3\Crypt\Common\PrivateKey;
|
||||
use phpseclib3\Net\SFTP;
|
||||
use phpseclib3\Net\SSH2;
|
||||
use phpseclib3\Net\SshMsg;
|
||||
|
||||
/**
|
||||
* SFTP Stream Wrapper
|
||||
@ -146,7 +147,7 @@ class Stream
|
||||
* Extract a path from a URI and actually connect to an SSH server if appropriate
|
||||
*
|
||||
* If "notification" is set as a context parameter the message code for successful login is
|
||||
* NET_SSH2_MSG_USERAUTH_SUCCESS. For a failed login it's NET_SSH2_MSG_USERAUTH_FAILURE.
|
||||
* SshMsg::USERAUTH_SUCCESS. For a failed login it's SshMsg::USERAUTH_FAILURE.
|
||||
*
|
||||
* @param string $path
|
||||
* @return string
|
||||
@ -231,10 +232,10 @@ class Stream
|
||||
call_user_func($this->notification, STREAM_NOTIFY_CONNECT, STREAM_NOTIFY_SEVERITY_INFO, '', 0, 0, 0);
|
||||
call_user_func($this->notification, STREAM_NOTIFY_AUTH_REQUIRED, STREAM_NOTIFY_SEVERITY_INFO, '', 0, 0, 0);
|
||||
if (!$this->sftp->login($user, $pass)) {
|
||||
call_user_func($this->notification, STREAM_NOTIFY_AUTH_RESULT, STREAM_NOTIFY_SEVERITY_ERR, 'Login Failure', NET_SSH2_MSG_USERAUTH_FAILURE, 0, 0);
|
||||
call_user_func($this->notification, STREAM_NOTIFY_AUTH_RESULT, STREAM_NOTIFY_SEVERITY_ERR, 'Login Failure', SshMsg::USERAUTH_FAILURE, 0, 0);
|
||||
return false;
|
||||
}
|
||||
call_user_func($this->notification, STREAM_NOTIFY_AUTH_RESULT, STREAM_NOTIFY_SEVERITY_INFO, 'Login Success', NET_SSH2_MSG_USERAUTH_SUCCESS, 0, 0);
|
||||
call_user_func($this->notification, STREAM_NOTIFY_AUTH_RESULT, STREAM_NOTIFY_SEVERITY_INFO, 'Login Success', SshMsg::USERAUTH_SUCCESS, 0, 0);
|
||||
} else {
|
||||
if (!$this->sftp->login($user, $pass)) {
|
||||
return false;
|
||||
@ -318,7 +319,7 @@ class Stream
|
||||
$result = $this->sftp->get($this->path, false, $this->pos, $count);
|
||||
if (isset($this->notification) && is_callable($this->notification)) {
|
||||
if ($result === false) {
|
||||
call_user_func($this->notification, STREAM_NOTIFY_FAILURE, STREAM_NOTIFY_SEVERITY_ERR, $this->sftp->getLastSFTPError(), NET_SFTP_OPEN, 0, 0);
|
||||
call_user_func($this->notification, STREAM_NOTIFY_FAILURE, STREAM_NOTIFY_SEVERITY_ERR, $this->sftp->getLastSFTPError(), PacketType::OPEN, 0, 0);
|
||||
return 0;
|
||||
}
|
||||
// seems that PHP calls stream_read in 8k chunks
|
||||
@ -351,7 +352,7 @@ class Stream
|
||||
$result = $this->sftp->put($this->path, $data, SFTP::SOURCE_STRING, $this->pos);
|
||||
if (isset($this->notification) && is_callable($this->notification)) {
|
||||
if (!$result) {
|
||||
call_user_func($this->notification, STREAM_NOTIFY_FAILURE, STREAM_NOTIFY_SEVERITY_ERR, $this->sftp->getLastSFTPError(), NET_SFTP_OPEN, 0, 0);
|
||||
call_user_func($this->notification, STREAM_NOTIFY_FAILURE, STREAM_NOTIFY_SEVERITY_ERR, $this->sftp->getLastSFTPError(), PacketType::OPEN, 0, 0);
|
||||
return 0;
|
||||
}
|
||||
// seems that PHP splits up strings into 8k blocks before calling stream_write
|
||||
|
File diff suppressed because it is too large
Load Diff
29
phpseclib/Net/SshDisconnect.php
Normal file
29
phpseclib/Net/SshDisconnect.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace phpseclib3\Net;
|
||||
|
||||
use phpseclib3\Common\ConstantUtilityTrait;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
abstract class SshDisconnect
|
||||
{
|
||||
use ConstantUtilityTrait;
|
||||
|
||||
const HOST_NOT_ALLOWED_TO_CONNECT = 1;
|
||||
const PROTOCOL_ERROR = 2;
|
||||
const KEY_EXCHANGE_FAILED = 3;
|
||||
const RESERVED = 4;
|
||||
const MAC_ERROR = 5;
|
||||
const COMPRESSION_ERROR = 6;
|
||||
const SERVICE_NOT_AVAILABLE = 7;
|
||||
const PROTOCOL_VERSION_NOT_SUPPORTED = 8;
|
||||
const HOST_KEY_NOT_VERIFIABLE = 9;
|
||||
const CONNECTION_LOST = 10;
|
||||
const BY_APPLICATION = 11;
|
||||
const TOO_MANY_CONNECTIONS = 12;
|
||||
const AUTH_CANCELLED_BY_USER = 13;
|
||||
const NO_MORE_AUTH_METHODS_AVAILABLE = 14;
|
||||
const ILLEGAL_USER_NAME = 15;
|
||||
}
|
49
phpseclib/Net/SshMsg.php
Normal file
49
phpseclib/Net/SshMsg.php
Normal file
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace phpseclib3\Net;
|
||||
|
||||
use phpseclib3\Common\ConstantUtilityTrait;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
abstract class SshMsg
|
||||
{
|
||||
use ConstantUtilityTrait;
|
||||
|
||||
const DISCONNECT = 1;
|
||||
const IGNORE = 2;
|
||||
const UNIMPLEMENTED = 3;
|
||||
const DEBUG = 4;
|
||||
const SERVICE_REQUEST = 5;
|
||||
const SERVICE_ACCEPT = 6;
|
||||
const EXT_INFO = 7;
|
||||
const NEWCOMPRESS = 8;
|
||||
|
||||
const KEXINIT = 20;
|
||||
const NEWKEYS = 21;
|
||||
|
||||
const USERAUTH_REQUEST = 50;
|
||||
const USERAUTH_FAILURE = 51;
|
||||
const USERAUTH_SUCCESS = 52;
|
||||
const USERAUTH_BANNER = 53;
|
||||
|
||||
const USERAUTH_INFO_REQUEST = 60;
|
||||
const USERAUTH_INFO_RESPONSE = 61;
|
||||
|
||||
const GLOBAL_REQUEST = 80;
|
||||
const REQUEST_SUCCESS = 81;
|
||||
const REQUEST_FAILURE = 82;
|
||||
|
||||
const CHANNEL_OPEN = 90;
|
||||
const CHANNEL_OPEN_CONFIRMATION = 91;
|
||||
const CHANNEL_OPEN_FAILURE = 92;
|
||||
const CHANNEL_WINDOW_ADJUST = 93;
|
||||
const CHANNEL_DATA = 94;
|
||||
const CHANNEL_EXTENDED_DATA = 95;
|
||||
const CHANNEL_EOF = 96;
|
||||
const CHANNEL_CLOSE = 97;
|
||||
const CHANNEL_REQUEST = 98;
|
||||
const CHANNEL_SUCCESS = 99;
|
||||
const CHANNEL_FAILURE = 100;
|
||||
}
|
27
phpseclib/Net/SshMsgCustom.php
Normal file
27
phpseclib/Net/SshMsgCustom.php
Normal file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace phpseclib3\Net;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
abstract class SshMsgCustom
|
||||
{
|
||||
const KEXDH_INIT = 30;
|
||||
const KEXDH_REPLY = 31;
|
||||
|
||||
// RFC 4419 - diffie-hellman-group-exchange-sha{1,256}
|
||||
const KEXDH_GEX_REQUEST_OLD = 30;
|
||||
const KEXDH_GEX_GROUP = 31;
|
||||
const KEXDH_GEX_INIT = 32;
|
||||
const KEXDH_GEX_REPLY = 33;
|
||||
const KEXDH_GEX_REQUEST = 34;
|
||||
|
||||
// RFC 5656 - Elliptic Curves (for curve25519-sha256@libssh.org)
|
||||
const KEX_ECDH_INIT = 30;
|
||||
const KEX_ECDH_REPLY = 31;
|
||||
|
||||
const USERAUTH_PASSWD_CHANGEREQ = 60;
|
||||
|
||||
const USERAUTH_PK_OK = 60;
|
||||
}
|
14
phpseclib/Net/SshOpen.php
Normal file
14
phpseclib/Net/SshOpen.php
Normal file
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace phpseclib3\Net;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
abstract class SshOpen
|
||||
{
|
||||
const ADMINISTRATIVELY_PROHIBITED = 1;
|
||||
const CONNECT_FAILED = 2;
|
||||
const UNKNOWN_CHANNEL_TYPE = 3;
|
||||
const RESOURCE_SHORTAGE = 4;
|
||||
}
|
11
phpseclib/Net/TerminalMode.php
Normal file
11
phpseclib/Net/TerminalMode.php
Normal file
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace phpseclib3\Net;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
abstract class TerminalMode
|
||||
{
|
||||
const TTY_OP_END = 0;
|
||||
}
|
@ -7,6 +7,7 @@
|
||||
*/
|
||||
|
||||
use phpseclib3\Net\SFTP;
|
||||
use phpseclib3\Net\SFTP\FileType;
|
||||
|
||||
class Functional_Net_SFTPUserStoryTest extends PhpseclibFunctionalTestCase
|
||||
{
|
||||
@ -654,28 +655,28 @@ class Functional_Net_SFTPUserStoryTest extends PhpseclibFunctionalTestCase
|
||||
$sftp->nlist();
|
||||
|
||||
$stat = $sftp->stat('link.txt');
|
||||
$this->assertSame($stat['type'], NET_SFTP_TYPE_REGULAR);
|
||||
$this->assertSame($stat['type'], FileType::REGULAR);
|
||||
$stat = $sftp->lstat('link.txt');
|
||||
$this->assertSame($stat['type'], NET_SFTP_TYPE_SYMLINK);
|
||||
$this->assertSame($stat['type'], FileType::SYMLINK);
|
||||
|
||||
$stat = $sftp->stat('linkdir');
|
||||
$this->assertSame($stat['type'], NET_SFTP_TYPE_DIRECTORY);
|
||||
$this->assertSame($stat['type'], FileType::DIRECTORY);
|
||||
$stat = $sftp->lstat('link.txt');
|
||||
$this->assertSame($stat['type'], NET_SFTP_TYPE_SYMLINK);
|
||||
$this->assertSame($stat['type'], FileType::SYMLINK);
|
||||
|
||||
$sftp->disableStatCache();
|
||||
|
||||
$sftp->nlist();
|
||||
|
||||
$stat = $sftp->stat('link.txt');
|
||||
$this->assertSame($stat['type'], NET_SFTP_TYPE_REGULAR);
|
||||
$this->assertSame($stat['type'], FileType::REGULAR);
|
||||
$stat = $sftp->lstat('link.txt');
|
||||
$this->assertSame($stat['type'], NET_SFTP_TYPE_SYMLINK);
|
||||
$this->assertSame($stat['type'], FileType::SYMLINK);
|
||||
|
||||
$stat = $sftp->stat('linkdir');
|
||||
$this->assertSame($stat['type'], NET_SFTP_TYPE_DIRECTORY);
|
||||
$this->assertSame($stat['type'], FileType::DIRECTORY);
|
||||
$stat = $sftp->lstat('link.txt');
|
||||
$this->assertSame($stat['type'], NET_SFTP_TYPE_SYMLINK);
|
||||
$this->assertSame($stat['type'], FileType::SYMLINK);
|
||||
|
||||
$sftp->enableStatCache();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user