Comparar commits
12 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| e8141ac49d | |||
| 4cf537888b | |||
| 2752b5bbb1 | |||
| cc6cbf3852 | |||
| 1a4fac8a25 | |||
| ae6443500e | |||
| e42452e4f2 | |||
| 1dd7e6165e | |||
| 01ef59346e | |||
| 9380a44469 | |||
| 3f859af167 | |||
| 55ecfbdbb6 |
@@ -443,6 +443,9 @@ static void pcre_log_error(const char *func, int line, int pcre_code,
|
||||
const char *repl, int repl_size,
|
||||
int arg1 = 0, int arg2 = 0,
|
||||
int arg3 = 0, int arg4 = 0) {
|
||||
if (!RuntimeOption::EnableHipHopSyntax) {
|
||||
return;
|
||||
}
|
||||
const char *escapedPattern;
|
||||
const char *escapedSubject;
|
||||
const char *escapedRepl;
|
||||
|
||||
@@ -1244,6 +1244,9 @@ void c_LibXMLError::t___construct() {
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// libxml
|
||||
|
||||
static xmlParserInputBufferPtr
|
||||
hphp_libxml_input_buffer(const char *URI, xmlCharEncoding enc);
|
||||
|
||||
class xmlErrorVec : public std::vector<xmlError> {
|
||||
public:
|
||||
~xmlErrorVec() {
|
||||
@@ -1263,13 +1266,15 @@ public:
|
||||
virtual void requestInit() {
|
||||
m_use_error = false;
|
||||
m_errors.reset();
|
||||
xmlParserInputBufferCreateFilenameDefault(nullptr);
|
||||
m_entity_loader_disabled = false;
|
||||
xmlParserInputBufferCreateFilenameDefault(hphp_libxml_input_buffer);
|
||||
}
|
||||
virtual void requestShutdown() {
|
||||
m_use_error = false;
|
||||
m_errors.reset();
|
||||
}
|
||||
|
||||
bool m_entity_loader_disabled;
|
||||
bool m_use_error;
|
||||
xmlErrorVec m_errors;
|
||||
};
|
||||
@@ -1376,19 +1381,19 @@ void f_libxml_set_streams_context(CResRef streams_context) {
|
||||
}
|
||||
|
||||
static xmlParserInputBufferPtr
|
||||
hphp_libxml_input_buffer_noload(const char *URI, xmlCharEncoding enc) {
|
||||
return nullptr;
|
||||
hphp_libxml_input_buffer(const char *URI, xmlCharEncoding enc) {
|
||||
if (s_libxml_errors->m_entity_loader_disabled) {
|
||||
return nullptr;
|
||||
}
|
||||
return __xmlParserInputBufferCreateFilename(URI, enc);
|
||||
}
|
||||
|
||||
bool f_libxml_disable_entity_loader(bool disable /* = true */) {
|
||||
xmlParserInputBufferCreateFilenameFunc old;
|
||||
bool old = s_libxml_errors->m_entity_loader_disabled;
|
||||
|
||||
if (disable) {
|
||||
old = xmlParserInputBufferCreateFilenameDefault(hphp_libxml_input_buffer_noload);
|
||||
} else {
|
||||
old = xmlParserInputBufferCreateFilenameDefault(nullptr);
|
||||
}
|
||||
return (old == hphp_libxml_input_buffer_noload);
|
||||
s_libxml_errors->m_entity_loader_disabled = disable;
|
||||
|
||||
return old;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -62,7 +62,8 @@ void FastCGIAcceptor::onNewConnection(
|
||||
localAddress = s_unknownSocketAddress;
|
||||
}
|
||||
|
||||
FastCGIConnection* conn = new FastCGIConnection(
|
||||
// Will delete itself when it gets a closing callback
|
||||
auto conn = new FastCGIConnection(
|
||||
m_server,
|
||||
std::move(sock),
|
||||
localAddress,
|
||||
@@ -145,6 +146,7 @@ void FastCGIConnection::onSessionError() {
|
||||
|
||||
void FastCGIConnection::onSessionClose() {
|
||||
shutdownTransport();
|
||||
delete this;
|
||||
}
|
||||
|
||||
void FastCGIConnection::setMaxConns(int max_conns) {
|
||||
|
||||
@@ -527,8 +527,8 @@ void FastCGISession::handleStdErr(RequestId request_id,
|
||||
}
|
||||
|
||||
void FastCGISession::handleComplete(RequestId request_id) {
|
||||
writeEndRequest(request_id, 0, ProtoStatus::REQUEST_COMPLETE);
|
||||
endTransaction(request_id);
|
||||
writeEndRequest(request_id, 0, ProtoStatus::REQUEST_COMPLETE);
|
||||
if (!m_keepConn) {
|
||||
handleClose();
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "hphp/util/timer.h"
|
||||
#include "folly/MoveWrapper.h"
|
||||
|
||||
#include <boost/algorithm/string/case_conv.hpp>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
|
||||
using folly::IOBuf;
|
||||
@@ -42,9 +43,14 @@ namespace HPHP {
|
||||
FastCGITransport::FastCGITransport(FastCGIConnection* connection, int id)
|
||||
: m_connection(connection),
|
||||
m_id(id),
|
||||
m_remotePort(0), m_method(Method::Unknown), m_requestSize(0),
|
||||
m_headersSent(false), m_readMore(false),
|
||||
m_waiting(0), m_readComplete(false) {}
|
||||
m_remotePort(0),
|
||||
m_serverPort(0),
|
||||
m_method(Method::Unknown),
|
||||
m_requestSize(0),
|
||||
m_headersSent(false),
|
||||
m_readMore(false),
|
||||
m_waiting(0),
|
||||
m_readComplete(false) {}
|
||||
|
||||
const char *FastCGITransport::getUrl() {
|
||||
return m_requestURI.c_str();
|
||||
@@ -58,10 +64,27 @@ const char *FastCGITransport::getRemoteHost() {
|
||||
return m_remoteHost.c_str();
|
||||
}
|
||||
|
||||
const char *FastCGITransport::getRemoteAddr() {
|
||||
return m_remoteAddr.c_str();
|
||||
}
|
||||
|
||||
uint16_t FastCGITransport::getRemotePort() {
|
||||
return m_remotePort;
|
||||
}
|
||||
|
||||
const char *FastCGITransport::getServerName() {
|
||||
return m_serverName.c_str();
|
||||
}
|
||||
|
||||
const char *FastCGITransport::getServerAddr() {
|
||||
return (!m_serverAddr.empty()) ? m_serverAddr.c_str() :
|
||||
Transport::getServerAddr();
|
||||
}
|
||||
|
||||
uint16_t FastCGITransport::getServerPort() {
|
||||
return (m_serverPort != 0) ? m_serverPort : Transport::getServerPort();
|
||||
}
|
||||
|
||||
const void *FastCGITransport::getPostData(int &size) {
|
||||
DCHECK(!m_readMore);
|
||||
return getPostDataImpl(size, false);
|
||||
@@ -192,9 +215,14 @@ void FastCGITransport::getHeaders(HeaderMap &headers) {
|
||||
}
|
||||
}
|
||||
|
||||
void FastCGITransport::getTransportParams(HeaderMap &serverParams) {
|
||||
for (auto& pair : m_requestHeaders) {
|
||||
serverParams[pair.first] = pair.second;
|
||||
}
|
||||
}
|
||||
|
||||
void FastCGITransport::addHeaderImpl(const char *name, const char *value) {
|
||||
CHECK(!m_headersSent);
|
||||
|
||||
if (!m_responseHeaders.count(name)) {
|
||||
m_responseHeaders.insert(std::make_pair(name,
|
||||
std::vector<std::string>()));
|
||||
@@ -274,11 +302,16 @@ void FastCGITransport::onBodyComplete() {
|
||||
|
||||
const std::string FastCGITransport::k_requestURIKey = "REQUEST_URI";
|
||||
const std::string FastCGITransport::k_remoteHostKey = "REMOTE_HOST";
|
||||
const std::string FastCGITransport::k_remoteAddrKey = "REMOTE_ADDR";
|
||||
const std::string FastCGITransport::k_remotePortKey = "REMOTE_PORT";
|
||||
const std::string FastCGITransport::k_methodKey = "REQUEST_METHOD";
|
||||
const std::string FastCGITransport::k_httpVersionKey = "HTTP_VERSION";
|
||||
const std::string FastCGITransport::k_contentLengthKey = "CONTENT_LENGTH";
|
||||
const std::string FastCGITransport::k_documentRoot = "DOCUMENT_ROOT";
|
||||
const std::string FastCGITransport::k_serverNameKey = "SERVER_NAME";
|
||||
const std::string FastCGITransport::k_serverPortKey = "SERVER_PORT";
|
||||
const std::string FastCGITransport::k_serverAddrKey = "SERVER_ADDR";
|
||||
const std::string FastCGITransport::k_httpsKey = "HTTPS";
|
||||
|
||||
void FastCGITransport::onHeader(std::unique_ptr<folly::IOBuf> key_chain,
|
||||
std::unique_ptr<folly::IOBuf> value_chain) {
|
||||
@@ -308,6 +341,8 @@ void FastCGITransport::handleHeader(const std::string& key,
|
||||
m_requestURI = value;
|
||||
} else if (compareKeys(key, k_remoteHostKey)) {
|
||||
m_remoteHost = value;
|
||||
} else if (compareKeys(key, k_remoteAddrKey)) {
|
||||
m_remoteAddr = value;
|
||||
} else if (compareKeys(key, k_remotePortKey)) {
|
||||
try {
|
||||
int remote_port = std::stoi(value);
|
||||
@@ -321,6 +356,27 @@ void FastCGITransport::handleHeader(const std::string& key,
|
||||
} catch (std::out_of_range&) {
|
||||
m_remotePort = 0;
|
||||
}
|
||||
} else if (compareKeys(key, k_serverNameKey)) {
|
||||
m_serverName = value;
|
||||
} else if (compareKeys(key, k_httpsKey)) {
|
||||
if (!value.empty()) {
|
||||
std::string lValue(value);
|
||||
boost::to_lower(lValue);
|
||||
// IIS sets this value but sets it to off when SSL is off.
|
||||
if (lValue.compare("off") != 0) {
|
||||
setSSL();
|
||||
}
|
||||
}
|
||||
} else if (compareKeys(key, k_serverAddrKey)) {
|
||||
m_serverAddr = value;
|
||||
} else if (compareKeys(key, k_serverPortKey)) {
|
||||
try {
|
||||
m_serverPort = std::stoi(value);
|
||||
} catch (std::invalid_argument&) {
|
||||
m_serverPort = 0;
|
||||
} catch (std::out_of_range&) {
|
||||
m_serverPort = 0;
|
||||
}
|
||||
} else if (compareKeys(key, k_methodKey)) {
|
||||
m_extendedMethod = value;
|
||||
if (compareValues(value, "GET")) {
|
||||
@@ -348,7 +404,16 @@ void FastCGITransport::handleHeader(const std::string& key,
|
||||
}
|
||||
|
||||
void FastCGITransport::onHeadersComplete() {
|
||||
m_serverObject = getRawHeader("SCRIPT_NAME");
|
||||
std::string pathTranslated = getRawHeader("PATH_TRANSLATED");
|
||||
std::string documentRoot = getRawHeader("DOCUMENT_ROOT");
|
||||
// use PATH_TRANSLATED - DOCUMENT_ROOT if it is valid instead of SCRIPT_NAME
|
||||
// for mod_fastcgi support
|
||||
if (!pathTranslated.empty() && !documentRoot.empty() &&
|
||||
pathTranslated.find(documentRoot) == 0) {
|
||||
m_serverObject = pathTranslated.substr(documentRoot.length());
|
||||
} else {
|
||||
m_serverObject = getRawHeader("SCRIPT_NAME");
|
||||
}
|
||||
std::string queryString = getRawHeader("QUERY_STRING");
|
||||
if (!queryString.empty()) {
|
||||
m_serverObject += "?" + queryString;
|
||||
|
||||
@@ -48,8 +48,12 @@ public:
|
||||
|
||||
virtual const char *getUrl() override;
|
||||
virtual const char *getRemoteHost() override;
|
||||
virtual const char *getRemoteAddr() override;
|
||||
virtual uint16_t getRemotePort() override;
|
||||
virtual const std::string getDocumentRoot() override;
|
||||
virtual const char *getServerName() override;
|
||||
virtual const char *getServerAddr() override;
|
||||
virtual uint16_t getServerPort() override;
|
||||
|
||||
virtual const void *getPostData(int &size) override;
|
||||
virtual bool hasMorePostData() override;
|
||||
@@ -66,6 +70,7 @@ public:
|
||||
|
||||
virtual std::string getHeader(const char *name) override;
|
||||
virtual void getHeaders(HeaderMap &headers) override;
|
||||
virtual void getTransportParams(HeaderMap &serverParams) override;
|
||||
|
||||
virtual void addHeaderImpl(const char *name, const char *value) override;
|
||||
virtual void removeHeaderImpl(const char *name) override;
|
||||
@@ -107,11 +112,16 @@ private:
|
||||
|
||||
static const std::string k_requestURIKey;
|
||||
static const std::string k_remoteHostKey;
|
||||
static const std::string k_remoteAddrKey;
|
||||
static const std::string k_remotePortKey;
|
||||
static const std::string k_methodKey;
|
||||
static const std::string k_httpVersionKey;
|
||||
static const std::string k_contentLengthKey;
|
||||
static const std::string k_documentRoot;
|
||||
static const std::string k_serverNameKey;
|
||||
static const std::string k_serverPortKey;
|
||||
static const std::string k_serverAddrKey;
|
||||
static const std::string k_httpsKey;
|
||||
|
||||
FastCGIConnection* m_connection;
|
||||
int m_id;
|
||||
@@ -121,7 +131,11 @@ private:
|
||||
std::string m_requestURI;
|
||||
std::string m_documentRoot;
|
||||
std::string m_remoteHost;
|
||||
std::string m_remoteAddr;
|
||||
uint16_t m_remotePort;
|
||||
std::string m_serverName;
|
||||
std::string m_serverAddr;
|
||||
uint16_t m_serverPort;
|
||||
Method m_method;
|
||||
std::string m_extendedMethod;
|
||||
std::string m_httpVersion;
|
||||
|
||||
@@ -377,12 +377,35 @@ void HttpProtocol::CopyHeaderVariables(Variant& server,
|
||||
}
|
||||
}
|
||||
|
||||
void HttpProtocol::CopyTransportParams(Variant& server,
|
||||
Transport *transport) {
|
||||
HeaderMap transportParams;
|
||||
// Get additional server params from the transport if it has any. In the case
|
||||
// of fastcgi this is basically a full header list from apache/nginx.
|
||||
transport->getTransportParams(transportParams);
|
||||
for (auto const& header : transportParams) {
|
||||
auto const& key = header.first;
|
||||
auto const& values = header.second;
|
||||
auto normalizedKey = string_replace(f_strtoupper(key), s_dash,
|
||||
s_underscore);
|
||||
|
||||
// Be careful here to not overwrite any _SERVER variable
|
||||
// that has already been set elsewhere and make sure it has a value.
|
||||
if (!values.empty() && !server.asArrRef().exists(normalizedKey)) {
|
||||
// When a header has multiple values, we always take the last one.
|
||||
server.set(normalizedKey, String(values.back()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void HttpProtocol::CopyServerInfo(Variant& server,
|
||||
Transport *transport,
|
||||
const VirtualHost *vhost) {
|
||||
|
||||
string hostHeader = transport->getHeader("Host");
|
||||
String hostName(vhost->serverName(hostHeader));
|
||||
String serverNameHeader(transport->getServerName());
|
||||
|
||||
if (hostHeader.empty()) {
|
||||
server.set(s_HTTP_HOST, hostName);
|
||||
@@ -390,19 +413,26 @@ void HttpProtocol::CopyServerInfo(Variant& server,
|
||||
} else {
|
||||
StackTraceNoHeap::AddExtraLogging("Server", hostHeader.c_str());
|
||||
}
|
||||
if (hostName.empty() || RuntimeOption::ForceServerNameToHeader) {
|
||||
|
||||
// Use the header from the transport if it is available
|
||||
if (!serverNameHeader.empty()) {
|
||||
hostName = serverNameHeader;
|
||||
} else if (hostName.empty() || RuntimeOption::ForceServerNameToHeader) {
|
||||
hostName = hostHeader;
|
||||
// _SERVER['SERVER_NAME'] shouldn't contain the port number
|
||||
int colonPos = hostName.find(':');
|
||||
if (colonPos != String::npos) {
|
||||
hostName = hostName.substr(0, colonPos);
|
||||
}
|
||||
}
|
||||
|
||||
// _SERVER['SERVER_NAME'] shouldn't contain the port number
|
||||
int colonPos = hostName.find(':');
|
||||
if (colonPos != String::npos) {
|
||||
hostName = hostName.substr(0, colonPos);
|
||||
}
|
||||
|
||||
StackTraceNoHeap::AddExtraLogging("Server_SERVER_NAME", hostName.data());
|
||||
|
||||
server.set(s_GATEWAY_INTERFACE, s_CGI_1_1);
|
||||
server.set(s_SERVER_ADDR, String(RuntimeOption::ServerPrimaryIP));
|
||||
server.set(s_SERVER_ADDR, transport->getServerAddr());
|
||||
server.set(s_SERVER_NAME, hostName);
|
||||
server.set(s_SERVER_PORT, RuntimeOption::ServerPort);
|
||||
server.set(s_SERVER_PORT, transport->getServerPort());
|
||||
server.set(s_SERVER_SOFTWARE, s_HPHP);
|
||||
server.set(s_SERVER_PROTOCOL, "HTTP/" + transport->getHTTPVersion());
|
||||
server.set(s_SERVER_ADMIN, empty_string);
|
||||
@@ -411,8 +441,17 @@ void HttpProtocol::CopyServerInfo(Variant& server,
|
||||
|
||||
void HttpProtocol::CopyRemoteInfo(Variant& server,
|
||||
Transport *transport) {
|
||||
server.set(s_REMOTE_ADDR, String(transport->getRemoteHost(), CopyString));
|
||||
server.set(s_REMOTE_HOST, empty_string); // I don't think we need to nslookup
|
||||
String remoteAddr(transport->getRemoteAddr(), CopyString);
|
||||
String remoteHost(transport->getRemoteHost(), CopyString);
|
||||
|
||||
if(remoteAddr.empty()) {
|
||||
remoteAddr = remoteHost;
|
||||
}
|
||||
|
||||
server.set(s_REMOTE_ADDR, remoteAddr);
|
||||
if(!remoteHost.empty()) {
|
||||
server.set(s_REMOTE_HOST, remoteHost);
|
||||
}
|
||||
server.set(s_REMOTE_PORT, transport->getRemotePort());
|
||||
}
|
||||
|
||||
@@ -601,6 +640,8 @@ void HttpProtocol::PrepareServerVariable(Variant& server,
|
||||
iter != vServerVars.end(); ++iter) {
|
||||
server.set(String(iter->first), String(iter->second));
|
||||
}
|
||||
// Do this last as to not overwrite any existing server variables.
|
||||
CopyTransportParams(server, transport);
|
||||
sri.setServerVariables(server);
|
||||
|
||||
const char *threadType = transport->getThreadTypeName();
|
||||
|
||||
@@ -60,6 +60,8 @@ public:
|
||||
const VirtualHost *vhost);
|
||||
static void CopyHeaderVariables(Variant& server,
|
||||
const HeaderMap& headers);
|
||||
static void CopyTransportParams(Variant& server,
|
||||
Transport *transport);
|
||||
static void CopyServerInfo(Variant& server,
|
||||
Transport *transport,
|
||||
const VirtualHost *vhost);
|
||||
|
||||
@@ -84,10 +84,10 @@ public:
|
||||
virtual ~Transport();
|
||||
|
||||
void onRequestStart(const timespec &queueTime);
|
||||
const timespec &getQueueTime() const { return m_queueTime;}
|
||||
const timespec &getWallTime() const { return m_wallTime;}
|
||||
const timespec &getCpuTime() const { return m_cpuTime;}
|
||||
const int64_t &getInstructions() const { return m_instructions;}
|
||||
const timespec &getQueueTime() const { return m_queueTime; }
|
||||
const timespec &getWallTime() const { return m_wallTime; }
|
||||
const timespec &getCpuTime() const { return m_cpuTime; }
|
||||
const int64_t &getInstructions() const { return m_instructions; }
|
||||
const int64_t &getSleepTime() const { return m_sleepTime; }
|
||||
void incSleepTime(unsigned int seconds) { m_sleepTime += seconds; }
|
||||
const int64_t &getuSleepTime() const { return m_usleepTime; }
|
||||
@@ -109,9 +109,24 @@ public:
|
||||
virtual const char *getUrl() = 0;
|
||||
virtual const char *getRemoteHost() = 0;
|
||||
virtual uint16_t getRemotePort() = 0;
|
||||
// The transport can override REMOTE_ADDR if it has one
|
||||
virtual const char *getRemoteAddr() { return ""; }
|
||||
// The transport can override the virtualhosts' docroot
|
||||
virtual const std::string getDocumentRoot() { return ""; }
|
||||
|
||||
/**
|
||||
* Server Headers
|
||||
*/
|
||||
virtual const char *getServerName() {
|
||||
return "";
|
||||
};
|
||||
virtual const char *getServerAddr() {
|
||||
return RuntimeOption::ServerPrimaryIP.c_str();
|
||||
};
|
||||
virtual uint16_t getServerPort() {
|
||||
return RuntimeOption::ServerPort;
|
||||
};
|
||||
|
||||
/**
|
||||
* POST request's data.
|
||||
*/
|
||||
@@ -141,6 +156,7 @@ public:
|
||||
*/
|
||||
virtual std::string getHeader(const char *name) = 0;
|
||||
virtual void getHeaders(HeaderMap &headers) = 0;
|
||||
virtual void getTransportParams(HeaderMap &serverParams) {};
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -1817,11 +1817,11 @@
|
||||
},
|
||||
{
|
||||
"name": "HPHP_VERSION",
|
||||
"value": "2.3.2"
|
||||
"value": "2.3.3"
|
||||
},
|
||||
{
|
||||
"name": "HHVM_VERSION",
|
||||
"value": "2.3.2"
|
||||
"value": "2.3.3"
|
||||
},
|
||||
{
|
||||
"name": "HTML_ENTITIES",
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
$xml = <<<EOT
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE test [<!ENTITY xxe SYSTEM "XXE_URI">]>
|
||||
<foo>&xxe;</foo>
|
||||
EOT;
|
||||
|
||||
$xml = str_replace('XXE_URI', __DIR__ . '/libxml_disable_entity_loader_payload.txt', $xml);
|
||||
|
||||
function parseXML($xml) {
|
||||
$doc = new DOMDocument();
|
||||
$doc->resolveExternals = true;
|
||||
$doc->substituteEntities = true;
|
||||
$doc->validateOnParse = false;
|
||||
$doc->loadXML($xml, 0);
|
||||
return $doc->saveXML();
|
||||
}
|
||||
|
||||
var_dump(strpos(parseXML($xml), 'SECRET_DATA') !== false);
|
||||
var_dump(libxml_disable_entity_loader(true));
|
||||
var_dump(strpos(parseXML($xml), 'SECRET_DATA') === false);
|
||||
|
||||
echo "Done\n";
|
||||
?>
|
||||
@@ -0,0 +1,7 @@
|
||||
bool(true)
|
||||
bool(false)
|
||||
I/O warning : failed to load external entity "%s"
|
||||
HipHop Warning: %s
|
||||
HipHop Warning: %s
|
||||
bool(true)
|
||||
Done
|
||||
@@ -0,0 +1 @@
|
||||
<?php if (!extension_loaded('simplexml') || !extension_loaded('dom') || defined('PHP_WINDOWS_VERSION_MAJOR')) die('skip'); ?>
|
||||
@@ -0,0 +1 @@
|
||||
SECRET_DATA
|
||||
+1
-1
@@ -1 +1 @@
|
||||
HHVM_VERSION(2.3.2)
|
||||
HHVM_VERSION(2.3.3)
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário