mirror of
https://github.com/misterunknown/ifm.git
synced 2025-08-09 17:46:31 +02:00
fix code style warnings by latest psr
This commit is contained in:
43
compiler.php
43
compiler.php
@@ -26,16 +26,19 @@ $IFM_SRC_PHP = [
|
||||
$options = getopt(null, ["language::", "languages::", "lang::", "cdn"]);
|
||||
|
||||
// build CDN version?
|
||||
if (isset($options['cdn']))
|
||||
if (isset($options['cdn'])) {
|
||||
define("IFM_CDN", true);
|
||||
else
|
||||
} else {
|
||||
define("IFM_CDN", false);
|
||||
}
|
||||
|
||||
// process languages
|
||||
$langs = [];
|
||||
foreach ($options as $key => $value)
|
||||
if (substr($key, 0, 4) == "lang")
|
||||
foreach ($options as $key => $value) {
|
||||
if (substr($key, 0, 4) == "lang") {
|
||||
$langs = array_merge($langs, explode(",", $value));
|
||||
}
|
||||
}
|
||||
|
||||
$langs = array_unique($langs);
|
||||
if (!empty($langs)) {
|
||||
@@ -45,25 +48,28 @@ if (!empty($langs)) {
|
||||
}
|
||||
// ensure english is available, as it gets merged with the other languages
|
||||
// in case of missing keys in other languages.
|
||||
if (!in_array("all", $langs) || !in_array("en", $langs))
|
||||
if (!in_array("all", $langs) || !in_array("en", $langs)) {
|
||||
array_push($langs, "en");
|
||||
}
|
||||
|
||||
if (in_array("all", $langs))
|
||||
$langs = array_map(
|
||||
function($lang_file) {return pathinfo($lang_file)['filename']; },
|
||||
function ($lang_file) { return pathinfo($lang_file)['filename']; },
|
||||
glob("src/i18n/*.json")
|
||||
);
|
||||
|
||||
$vars['languageincludes'] = "";
|
||||
foreach ($langs as $l)
|
||||
if (file_exists("src/i18n/".$l.".json"))
|
||||
foreach ($langs as $l) {
|
||||
if (file_exists("src/i18n/".$l.".json")) {
|
||||
$vars['languageincludes'] .=
|
||||
'$i18n["'.$l.'"] = <<<\'f00bar\'' . "\n"
|
||||
. file_get_contents( "src/i18n/".$l.".json" ) . "\n"
|
||||
. 'f00bar;' . "\n"
|
||||
. '$i18n["'.$l.'"] = json_decode( $i18n["'.$l.'"], true );' . "\n" ;
|
||||
else
|
||||
} else {
|
||||
print "WARNING: Language file src/i18n/".$l.".json not found.\n";
|
||||
}
|
||||
}
|
||||
|
||||
// Concat PHP Files
|
||||
$compiled = ["<?php"];
|
||||
@@ -79,13 +85,14 @@ $compiled = str_replace("@@@ASSETS_CSS@@@", file_get_contents("src/assets".(IFM_
|
||||
$compiled = str_replace("@@@ASSETS_JS@@@", file_get_contents("src/assets".(IFM_CDN?".cdn":"").".js"), $compiled);
|
||||
|
||||
// Process file includes
|
||||
$includes = NULL;
|
||||
$includes = null;
|
||||
preg_match_all("/\@\@\@file:([^\@]+)\@\@\@/", $compiled, $includes, PREG_SET_ORDER);
|
||||
foreach ($includes as $file)
|
||||
foreach ($includes as $file) {
|
||||
$compiled = str_replace($file[0], file_get_contents($file[1]), $compiled);
|
||||
}
|
||||
|
||||
// Process ace includes
|
||||
$includes = NULL;
|
||||
$includes = null;
|
||||
$vars['ace_includes'] = "";
|
||||
preg_match_all("/\@\@\@acedir:([^\@]+)\@\@\@/", $compiled, $includes, PREG_SET_ORDER);
|
||||
foreach ($includes as $dir) {
|
||||
@@ -100,15 +107,17 @@ foreach ($includes as $dir) {
|
||||
}
|
||||
|
||||
// Process variable includes
|
||||
$includes = NULL;
|
||||
$includes = null;
|
||||
preg_match_all("/\@\@\@vars:([^\@]+)\@\@\@/", $compiled, $includes, PREG_SET_ORDER);
|
||||
foreach( $includes as $var )
|
||||
foreach ($includes as $var) {
|
||||
$compiled = str_replace($var[0], $vars[$var[1]], $compiled);
|
||||
}
|
||||
|
||||
$compiled = str_replace('IFM_VERSION', IFM_VERSION, $compiled);
|
||||
|
||||
if (!is_dir(IFM_RELEASE_DIR))
|
||||
mkdir(IFM_RELEASE_DIR);
|
||||
if (!is_dir(IFM_RELEASE_DIR)) {
|
||||
mkdir(IFM_RELEASE_DIR);
|
||||
}
|
||||
|
||||
// build standalone ifm
|
||||
file_put_contents(IFM_RELEASE_DIR . (IFM_CDN ? 'cdn.' : '') . IFM_STANDALONE, $compiled);
|
||||
@@ -123,7 +132,7 @@ $ifm->run();
|
||||
// build compressed ifm
|
||||
file_put_contents(
|
||||
IFM_RELEASE_DIR . (IFM_CDN ? 'cdn.' : '') . IFM_STANDALONE_GZ,
|
||||
'<?php eval( gzdecode( file_get_contents( __FILE__, false, null, 85 ) ) ); exit(0); ?>'
|
||||
'<?php eval(gzdecode(file_get_contents(__FILE__, false, null, 85))); exit(0); ?>'
|
||||
. gzencode(file_get_contents(IFM_RELEASE_DIR . (IFM_CDN ? 'cdn.' : '') . IFM_STANDALONE, false, null, 5))
|
||||
);
|
||||
// build lib
|
||||
|
187
src/htpasswd.php
187
src/htpasswd.php
@@ -6,53 +6,55 @@
|
||||
class Htpasswd {
|
||||
public $users = [];
|
||||
|
||||
public function __construct( $filename="" ) {
|
||||
if( $filename )
|
||||
$this->load( $filename );
|
||||
public function __construct($filename="") {
|
||||
if ($filename) {
|
||||
$this->load($filename);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a new htpasswd file
|
||||
*/
|
||||
public function load( $filename ) {
|
||||
unset( $this->users );
|
||||
if( file_exists( $filename ) && is_readable( $filename ) ) {
|
||||
public function load($filename) {
|
||||
unset($this->users);
|
||||
if (file_exists($filename) && is_readable($filename)) {
|
||||
$lines = file( $filename );
|
||||
foreach( $lines as $line ) {
|
||||
list( $user, $pass ) = explode( ":", $line );
|
||||
$this->users[$user] = trim( $pass );
|
||||
foreach ($lines as $line) {
|
||||
list($user, $pass) = explode(":", $line);
|
||||
$this->users[$user] = trim($pass);
|
||||
}
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getUsers() {
|
||||
return array_keys( $this->users );
|
||||
}
|
||||
|
||||
public function userExist( $user ) {
|
||||
return isset( $this->users[ $user ] );
|
||||
}
|
||||
|
||||
public function verify( $user, $pass ) {
|
||||
if( isset( $this->users[$user] ) ) {
|
||||
return $this->verifyPassword( $pass, $this->users[$user] );
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function verifyPassword( $pass, $hash ) {
|
||||
if( substr( $hash, 0, 4 ) == '$2y$' ) {
|
||||
return password_verify( $pass, $hash );
|
||||
} elseif( substr( $hash, 0, 6 ) == '$apr1$' ) {
|
||||
public function getUsers() {
|
||||
return array_keys($this->users);
|
||||
}
|
||||
|
||||
public function userExist($user) {
|
||||
return isset($this->users[$user]);
|
||||
}
|
||||
|
||||
public function verify($user, $pass) {
|
||||
if (isset($this->users[$user])) {
|
||||
return $this->verifyPassword($pass, $this->users[$user]);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function verifyPassword($pass, $hash) {
|
||||
if (substr($hash, 0, 4) == '$2y$') {
|
||||
return password_verify($pass, $hash);
|
||||
} elseif (substr($hash, 0, 6) == '$apr1$') {
|
||||
$apr1 = new APR1_MD5();
|
||||
return $apr1->check( $pass, $hash );
|
||||
} elseif( substr( $hash, 0, 5 ) == '{SHA}' ) {
|
||||
return base64_encode( sha1( $pass, TRUE ) ) == substr( $hash, 5 );
|
||||
return $apr1->check($pass, $hash);
|
||||
} elseif (substr($hash, 0, 5) == '{SHA}') {
|
||||
return base64_encode(sha1($pass, true)) == substr($hash, 5);
|
||||
} else { // assume CRYPT
|
||||
return crypt( $pass, $hash ) == $hash;
|
||||
return crypt($pass, $hash) == $hash;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -64,64 +66,73 @@ class Htpasswd {
|
||||
*/
|
||||
class APR1_MD5 {
|
||||
|
||||
const BASE64_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
||||
const APRMD5_ALPHABET = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
|
||||
const BASE64_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
||||
const APRMD5_ALPHABET = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
|
||||
|
||||
// Source/References for core algorithm:
|
||||
// http://www.cryptologie.net/article/126/bruteforce-apr1-hashes/
|
||||
// http://svn.apache.org/viewvc/apr/apr-util/branches/1.3.x/crypto/apr_md5.c?view=co
|
||||
// http://www.php.net/manual/en/function.crypt.php#73619
|
||||
// http://httpd.apache.org/docs/2.2/misc/password_encryptions.html
|
||||
// Wikipedia
|
||||
// Source/References for core algorithm:
|
||||
// http://www.cryptologie.net/article/126/bruteforce-apr1-hashes/
|
||||
// http://svn.apache.org/viewvc/apr/apr-util/branches/1.3.x/crypto/apr_md5.c?view=co
|
||||
// http://www.php.net/manual/en/function.crypt.php#73619
|
||||
// http://httpd.apache.org/docs/2.2/misc/password_encryptions.html
|
||||
// Wikipedia
|
||||
|
||||
public static function hash($mdp, $salt = null) {
|
||||
if (is_null($salt))
|
||||
$salt = self::salt();
|
||||
$salt = substr($salt, 0, 8);
|
||||
$max = strlen($mdp);
|
||||
$context = $mdp.'$apr1$'.$salt;
|
||||
$binary = pack('H32', md5($mdp.$salt.$mdp));
|
||||
for($i=$max; $i>0; $i-=16)
|
||||
$context .= substr($binary, 0, min(16, $i));
|
||||
for($i=$max; $i>0; $i>>=1)
|
||||
$context .= ($i & 1) ? chr(0) : $mdp[0];
|
||||
$binary = pack('H32', md5($context));
|
||||
for($i=0; $i<1000; $i++) {
|
||||
$new = ($i & 1) ? $mdp : $binary;
|
||||
if($i % 3) $new .= $salt;
|
||||
if($i % 7) $new .= $mdp;
|
||||
$new .= ($i & 1) ? $binary : $mdp;
|
||||
$binary = pack('H32', md5($new));
|
||||
}
|
||||
$hash = '';
|
||||
for ($i = 0; $i < 5; $i++) {
|
||||
$k = $i+6;
|
||||
$j = $i+12;
|
||||
if($j == 16) $j = 5;
|
||||
$hash = $binary[$i].$binary[$k].$binary[$j].$hash;
|
||||
}
|
||||
$hash = chr(0).chr(0).$binary[11].$hash;
|
||||
$hash = strtr(
|
||||
strrev(substr(base64_encode($hash), 2)),
|
||||
self::BASE64_ALPHABET,
|
||||
self::APRMD5_ALPHABET
|
||||
);
|
||||
return '$apr1$'.$salt.'$'.$hash;
|
||||
}
|
||||
public static function hash($mdp, $salt = null) {
|
||||
if (is_null($salt)) {
|
||||
$salt = self::salt();
|
||||
}
|
||||
$salt = substr($salt, 0, 8);
|
||||
$max = strlen($mdp);
|
||||
$context = $mdp.'$apr1$'.$salt;
|
||||
$binary = pack('H32', md5($mdp.$salt.$mdp));
|
||||
for ($i=$max; $i>0; $i-=16) {
|
||||
$context .= substr($binary, 0, min(16, $i));
|
||||
}
|
||||
for ($i=$max; $i>0; $i>>=1) {
|
||||
$context .= ($i & 1) ? chr(0) : $mdp[0];
|
||||
}
|
||||
$binary = pack('H32', md5($context));
|
||||
for ($i=0; $i<1000; $i++) {
|
||||
$new = ($i & 1) ? $mdp : $binary;
|
||||
if ($i % 3) {
|
||||
$new .= $salt;
|
||||
}
|
||||
if ($i % 7) {
|
||||
$new .= $mdp;
|
||||
}
|
||||
$new .= ($i & 1) ? $binary : $mdp;
|
||||
$binary = pack('H32', md5($new));
|
||||
}
|
||||
$hash = '';
|
||||
for ($i = 0; $i < 5; $i++) {
|
||||
$k = $i+6;
|
||||
$j = $i+12;
|
||||
if ($j == 16) {
|
||||
$j = 5;
|
||||
}
|
||||
$hash = $binary[$i].$binary[$k].$binary[$j].$hash;
|
||||
}
|
||||
$hash = chr(0).chr(0).$binary[11].$hash;
|
||||
$hash = strtr(
|
||||
strrev(substr(base64_encode($hash), 2)),
|
||||
self::BASE64_ALPHABET,
|
||||
self::APRMD5_ALPHABET
|
||||
);
|
||||
return '$apr1$'.$salt.'$'.$hash;
|
||||
}
|
||||
|
||||
// 8 character salts are the best. Don't encourage anything but the best.
|
||||
public static function salt() {
|
||||
$alphabet = self::APRMD5_ALPHABET;
|
||||
$salt = '';
|
||||
for($i=0; $i<8; $i++) {
|
||||
$offset = hexdec(bin2hex(openssl_random_pseudo_bytes(1))) % 64;
|
||||
$salt .= $alphabet[$offset];
|
||||
}
|
||||
return $salt;
|
||||
}
|
||||
// 8 character salts are the best. Don't encourage anything but the best.
|
||||
public static function salt() {
|
||||
$alphabet = self::APRMD5_ALPHABET;
|
||||
$salt = '';
|
||||
for ($i=0; $i<8; $i++) {
|
||||
$offset = hexdec(bin2hex(openssl_random_pseudo_bytes(1))) % 64;
|
||||
$salt .= $alphabet[$offset];
|
||||
}
|
||||
return $salt;
|
||||
}
|
||||
|
||||
public static function check($plain, $hash) {
|
||||
$parts = explode('$', $hash);
|
||||
return self::hash($plain, $parts[2]) === $hash;
|
||||
}
|
||||
public static function check($plain, $hash) {
|
||||
$parts = explode('$', $hash);
|
||||
return self::hash($plain, $parts[2]) === $hash;
|
||||
}
|
||||
}
|
||||
|
@@ -1399,7 +1399,7 @@ function IFM(params) {
|
||||
* @returns {boolean}
|
||||
*/
|
||||
this.inArray = function(needle, haystack) {
|
||||
for( let i = 0; i < haystack.length; i++ )
|
||||
for ( let i = 0; i < haystack.length; i++ )
|
||||
if( haystack[i] == needle )
|
||||
return true;
|
||||
return false;
|
||||
@@ -1575,7 +1575,7 @@ function IFM(params) {
|
||||
this.generateGuid = function() {
|
||||
let result, i, j;
|
||||
result = '';
|
||||
for( j = 0; j < 20; j++ ) {
|
||||
for ( j = 0; j < 20; j++ ) {
|
||||
i = Math.floor( Math.random() * 16 ).toString( 16 ).toUpperCase();
|
||||
result = result + i;
|
||||
}
|
||||
|
@@ -24,8 +24,9 @@ class IFMArchive {
|
||||
* Add a folder to an archive
|
||||
*/
|
||||
private static function addFolder(&$archive, $folder, $offset=0, $exclude_callback=null) {
|
||||
if ($offset == 0)
|
||||
if ($offset == 0) {
|
||||
$offset = strlen(dirname($folder)) + 1;
|
||||
}
|
||||
$archive->addEmptyDir(substr($folder, $offset));
|
||||
$handle = opendir($folder);
|
||||
while (false !== $f = readdir($handle)) {
|
||||
@@ -33,13 +34,15 @@ class IFMArchive {
|
||||
$filePath = $folder . '/' . $f;
|
||||
if (file_exists($filePath) && is_readable($filePath)) {
|
||||
if (is_file($filePath)) {
|
||||
if (!is_callable($exclude_callback) || $exclude_callback($f))
|
||||
$archive->addFile( $filePath, substr( $filePath, $offset ) );
|
||||
if (!is_callable($exclude_callback) || $exclude_callback($f)) {
|
||||
$archive->addFile($filePath, substr($filePath, $offset));
|
||||
}
|
||||
} elseif (is_dir($filePath)) {
|
||||
if (is_callable($exclude_callback))
|
||||
if (is_callable($exclude_callback)) {
|
||||
self::addFolder($archive, $filePath, $offset, $exclude_callback);
|
||||
else
|
||||
} else {
|
||||
self::addFolder($archive, $filePath, $offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -54,18 +57,22 @@ class IFMArchive {
|
||||
$a = new ZipArchive();
|
||||
$a->open($archivename, ZIPARCHIVE::CREATE);
|
||||
|
||||
if (!is_array($filenames))
|
||||
if (!is_array($filenames)) {
|
||||
$filenames = array($filenames);
|
||||
}
|
||||
|
||||
foreach ($filenames as $f)
|
||||
if (is_dir($f))
|
||||
if (is_callable($exclude_callback))
|
||||
self::addFolder( $a, $f, null, $exclude_callback );
|
||||
else
|
||||
self::addFolder( $a, $f );
|
||||
elseif (is_file($f))
|
||||
if (!is_callable($exclude_callback) || $exclude_callback($f))
|
||||
if (is_dir($f)) {
|
||||
if (is_callable($exclude_callback)) {
|
||||
self::addFolder($a, $f, null, $exclude_callback);
|
||||
} else {
|
||||
self::addFolder($a, $f);
|
||||
}
|
||||
} elseif (is_file($f)) {
|
||||
if (!is_callable($exclude_callback) || $exclude_callback($f)) {
|
||||
$a->addFile($f, pathinfo($f, PATHINFO_BASENAME));
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
return $a->close();
|
||||
@@ -78,16 +85,18 @@ class IFMArchive {
|
||||
* Unzip a zip file
|
||||
*/
|
||||
public static function extractZip($file, $destination="./") {
|
||||
if (!file_exists($file))
|
||||
if (!file_exists($file)) {
|
||||
return false;
|
||||
}
|
||||
$zip = new ZipArchive;
|
||||
$res = $zip->open($file);
|
||||
if ($res === true) {
|
||||
$zip->extractTo($destination);
|
||||
$zip->close();
|
||||
return true;
|
||||
} else
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -98,14 +107,17 @@ class IFMArchive {
|
||||
$a = new PharData($tmpf);
|
||||
|
||||
try {
|
||||
if (!is_array($filenames))
|
||||
if (!is_array($filenames)) {
|
||||
$filenames = array($filenames);
|
||||
}
|
||||
|
||||
foreach ($filenames as $f)
|
||||
if (is_dir($f))
|
||||
foreach ($filenames as $f) {
|
||||
if (is_dir($f)) {
|
||||
self::addFolder($a, $f);
|
||||
elseif (is_file($f))
|
||||
} elseif (is_file($f)) {
|
||||
$a->addFile($f, pathinfo($f, PATHINFO_BASENAME));
|
||||
}
|
||||
}
|
||||
switch ($format) {
|
||||
case "tar.gz":
|
||||
$a->compress(Phar::GZ);
|
||||
@@ -127,8 +139,9 @@ class IFMArchive {
|
||||
* Extracts a tar archive
|
||||
*/
|
||||
public static function extractTar($file, $destination="./") {
|
||||
if (!file_exists($file))
|
||||
if (!file_exists($file)) {
|
||||
return false;
|
||||
}
|
||||
$tar = new PharData($file);
|
||||
try {
|
||||
$tar->extractTo($destination, null, true);
|
||||
|
14
src/main.php
14
src/main.php
@@ -581,7 +581,7 @@ f00bar;
|
||||
if (isset($d['filename']) && $this->isFilenameValid($d['filename'])) {
|
||||
if (isset($d['content'])) {
|
||||
// work around magic quotes
|
||||
if((function_exists("get_magic_quotes_gpc") && get_magic_quotes_gpc())
|
||||
if ((function_exists("get_magic_quotes_gpc") && get_magic_quotes_gpc())
|
||||
|| (ini_get('magic_quotes_sybase') && (strtolower(ini_get('magic_quotes_sybase'))!="off")) ) {
|
||||
$content = stripslashes($d['content']);
|
||||
} else {
|
||||
@@ -1024,7 +1024,7 @@ f00bar;
|
||||
if ($login_failed === true)
|
||||
throw new IFMException("Authentication failed: Wrong credentials", true);
|
||||
else
|
||||
throw new IFMException("Not authenticated" , true);
|
||||
throw new IFMException("Not authenticated", true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1057,7 +1057,7 @@ f00bar;
|
||||
}
|
||||
$u = $uuid . "=" . $user . "," . $basedn;
|
||||
if (!$ds = ldap_connect($ldap_server)) {
|
||||
throw new IFMException("Could not reach the ldap server." , true);
|
||||
throw new IFMException("Could not reach the ldap server.", true);
|
||||
//trigger_error("Could not reach the ldap server.", E_USER_ERROR);
|
||||
return false;
|
||||
}
|
||||
@@ -1069,14 +1069,14 @@ f00bar;
|
||||
if (ldap_count_entries($ds, ldap_search($ds, $u, $ufilter)) == 1) {
|
||||
$authenticated = true;
|
||||
} else {
|
||||
throw new IFMException("User not allowed." , true);
|
||||
throw new IFMException("User not allowed.", true);
|
||||
//trigger_error("User not allowed.", E_USER_ERROR);
|
||||
$authenticated = false;
|
||||
}
|
||||
} else
|
||||
$authenticated = true;
|
||||
} else {
|
||||
throw new IFMException(ldap_error($ds) , true);
|
||||
throw new IFMException(ldap_error($ds), true);
|
||||
//trigger_error(ldap_error($ds), E_USER_ERROR);
|
||||
$authenticated = false;
|
||||
}
|
||||
@@ -1104,7 +1104,7 @@ f00bar;
|
||||
private function isAbsolutePath($path) {
|
||||
if ($path === null || $path === '')
|
||||
return false;
|
||||
return $path[0] === DIRECTORY_SEPARATOR || preg_match('~^[A-Z]:(?![^/\\\\])~i',$path) > 0;
|
||||
return $path[0] === DIRECTORY_SEPARATOR || preg_match('~^[A-Z]:(?![^/\\\\])~i', $path) > 0;
|
||||
}
|
||||
|
||||
private function getRootDir() {
|
||||
@@ -1248,7 +1248,7 @@ f00bar;
|
||||
$ret = "";
|
||||
foreach ($parts as $part)
|
||||
if (trim($part) != "")
|
||||
$ret .= (empty($ret) ? rtrim($part,"/") : trim($part, '/'))."/";
|
||||
$ret .= (empty($ret) ? rtrim($part, "/") : trim($part, '/'))."/";
|
||||
return rtrim($ret, "/");
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user