mirror of
https://github.com/anope/anope.git
synced 2026-06-25 02:46:37 +02:00
webcpanel: rate limit login attempts
This commit is contained in:
@@ -36,6 +36,14 @@ class WebpanelRequest : public IdentifyRequest
|
||||
return;
|
||||
}
|
||||
|
||||
// Rate limit logins to 1/sec
|
||||
time_t *last_login = na->nc->GetExt<time_t>("webcpanel_last_login");
|
||||
if (last_login != NULL && Anope::CurTime == *last_login)
|
||||
{
|
||||
this->OnFail();
|
||||
return;
|
||||
}
|
||||
|
||||
Anope::string id;
|
||||
for (int i = 0; i < 64; ++i)
|
||||
{
|
||||
@@ -48,6 +56,7 @@ class WebpanelRequest : public IdentifyRequest
|
||||
|
||||
na->Extend<Anope::string>("webcpanel_id", id);
|
||||
na->Extend<Anope::string>("webcpanel_ip", client->GetIP());
|
||||
na->nc->Extend<time_t>("webcpanel_last_login", Anope::CurTime);
|
||||
|
||||
{
|
||||
HTTPReply::cookie c;
|
||||
@@ -91,6 +100,30 @@ bool WebCPanel::Index::OnRequest(HTTPProvider *server, const Anope::string &page
|
||||
if (!user.empty() && !pass.empty())
|
||||
{
|
||||
// Rate limit check.
|
||||
Anope::string ip = client->clientaddr.addr();
|
||||
|
||||
Anope::hash_map<time_t>::iterator it = last_login_attempt.find(ip);
|
||||
if (it != last_login_attempt.end())
|
||||
{
|
||||
time_t last_time = it->second;
|
||||
|
||||
if (last_time == Anope::CurTime)
|
||||
{
|
||||
replacements["INVALID_LOGIN"] = "Rate limited";
|
||||
TemplateFileServer page("login.html");
|
||||
page.Serve(server, page_name, client, message, reply, replacements);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// don't let ip hash grow too long
|
||||
if (Anope::CurTime > last_clear + FLUSH_TIME)
|
||||
{
|
||||
last_login_attempt.clear();
|
||||
last_clear = Anope::CurTime;
|
||||
}
|
||||
|
||||
last_login_attempt[ip] = Anope::CurTime;
|
||||
|
||||
WebpanelRequest *req = new WebpanelRequest(me, reply, message, server, page_name, client, replacements, user, pass);
|
||||
FOREACH_MOD(OnCheckAuthentication, (NULL, req));
|
||||
|
||||
@@ -12,8 +12,13 @@ namespace WebCPanel
|
||||
|
||||
class Index : public WebPanelPage
|
||||
{
|
||||
static const int FLUSH_TIME = 60;
|
||||
|
||||
Anope::hash_map<time_t> last_login_attempt;
|
||||
time_t last_clear;
|
||||
|
||||
public:
|
||||
Index(const Anope::string &u) : WebPanelPage(u) { }
|
||||
Index(const Anope::string &u) : WebPanelPage(u), last_clear(0) { }
|
||||
|
||||
bool OnRequest(HTTPProvider *, const Anope::string &, HTTPClient *, HTTPMessage &, HTTPReply &) anope_override;
|
||||
};
|
||||
|
||||
@@ -15,6 +15,7 @@ class ModuleWebCPanel : public Module
|
||||
ServiceReference<HTTPProvider> provider;
|
||||
Panel panel;
|
||||
PrimitiveExtensibleItem<Anope::string> id, ip;
|
||||
PrimitiveExtensibleItem<time_t> last_login;
|
||||
|
||||
StaticFileServer style_css, logo_png, cubes_png, favicon_ico;
|
||||
|
||||
@@ -44,7 +45,8 @@ class ModuleWebCPanel : public Module
|
||||
|
||||
public:
|
||||
ModuleWebCPanel(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, EXTRA | VENDOR),
|
||||
panel(this, "webcpanel"), id(this, "webcpanel_id"), ip(this, "webcpanel_ip"),
|
||||
panel(this, "webcpanel"),
|
||||
id(this, "webcpanel_id"), ip(this, "webcpanel_ip"), last_login(this, "webcpanel_last_login"),
|
||||
style_css("style.css", "/static/style.css", "text/css"), logo_png("logo.png", "/static/logo.png", "image/png"), cubes_png("cubes.png", "/static/cubes.png", "image/png"), favicon_ico("favicon.ico", "/favicon.ico", "image/x-icon"),
|
||||
index("/"), logout("/logout"), _register("/register"), confirm("/confirm"),
|
||||
nickserv_info("NickServ", "/nickserv/info"), nickserv_cert("NickServ", "/nickserv/cert"), nickserv_access("NickServ", "/nickserv/access"), nickserv_alist("NickServ", "/nickserv/alist"),
|
||||
|
||||
Reference in New Issue
Block a user