Banning unbanning users now works.

This commit is contained in:
Marat Fayzullin 2023-11-15 23:43:52 -05:00
parent b2f1c245cf
commit 6757247596
8 changed files with 111 additions and 31 deletions

View File

@ -171,8 +171,12 @@ UI.toggleFrame = function(on) {
this.frame = on;
LS.save('ui_frame', on);
$('#openwebrx-frame-checkbox').attr('checked', on);
$('#openwebrx-panel-receiver').css( 'border', on ? '2px solid white' : '2px solid transparent');
$('#openwebrx-dialog-bookmark').css('border', on ? '2px solid white' : '2px solid transparent');
var border = on ? '2px solid white' : '2px solid transparent';
$('#openwebrx-panel-receiver').css( 'border', border);
$('#openwebrx-dialog-bookmark').css('border', border);
// $('#openwebrx-digimode-canvas-container').css('border', border);
// $('.openwebrx-message-panel').css('border', border);
}
};

View File

@ -0,0 +1,17 @@
$.fn.clientList = function() {
this.each(function() {
$(this).on('click', '.client-ban', function(e) {
$.ajax(document.location.href + "/ban/" + this.value).done(function() {
document.location.reload();
});
return false;
});
$(this).on('click', '.client-unban', function(e) {
$.ajax(document.location.href + "/unban/" + this.value).done(function() {
document.location.reload();
});
return false;
});
});
}

View File

@ -11,12 +11,6 @@
<body>
${header}
<div class="container">
<div class="row">
<h1 class="col-12">Clients</h1>
</div>
<div class="row mt-3">
${clients}
</div>
<div class="row">
<h1 class="col-12">Settings</h1>
</div>
@ -43,5 +37,11 @@ ${header}
<a class="btn btn-secondary" href="features">Feature report</a>
</div>
</div>
<div class="row">
<h1 class="col-12">Clients</h1>
</div>
<div class="row mt-3 client-list">
${clients}
</div>
</div>
</body>

View File

@ -9,4 +9,5 @@ $(function(){
$('#scheduler').schedulerInput();
$('.exponential-input').exponentialInput();
$('.device-log-messages').logMessages();
});
$('.client-list').clientList();
});

View File

@ -181,6 +181,7 @@ class CompiledAssetsController(GzipMixin, ModificationAwareController):
"lib/settings/SchedulerInput.js",
"lib/settings/ExponentialInput.js",
"lib/settings/LogMessages.js",
"lib/settings/ClientList.js",
"settings.js",
],
}

View File

@ -21,16 +21,13 @@ class SettingsController(AuthorizationMixin, WebpageController):
variables["clients"] = self.renderClients()
return variables
# <form class="settings-clients" method="POST">
# </form>
def renderClients(self):
return """
<table class='table'>
<tr>
<th>Connection Time</th>
<th>IP Address</th>
<th>SDR Profile</th>
<th>Local Time</th>
<th>Actions</th>
</tr>
{clients}
@ -40,11 +37,12 @@ class SettingsController(AuthorizationMixin, WebpageController):
)
def renderClient(self, c):
return "<tr><td>{0}</td><td>{1}</td><td>{2}</td><td>{3}</td></tr>".format(
c["ts"].strftime('%Y-%m-%d %H:%M:%S'),
return "<tr><td>{0}</td><td>{1}</td><td>{2} {3}</td><td>{4}</td></tr>".format(
self.renderIp(c["ip"]),
c["sdr"] + " " + c["band"] if "sdr" in c else "n/a",
self.renderButtons(c["ip"])
"banned" if c["ban"] else c["sdr"] + " " + c["band"] if "sdr" in c else "n/a",
"until" if c["ban"] else "since",
c["ts"].strftime('%H:%M:%S'),
self.renderButtons(c)
)
def renderIp(self, ip):
@ -53,10 +51,23 @@ class SettingsController(AuthorizationMixin, WebpageController):
<a href="https://www.geolocation.com/en_us?ip={0}#ipresult" target="_blank">{1}</a>
""".format(ip, ip)
def renderButtons(self, ip):
def renderButtons(self, c):
action = "unban" if c["ban"] else "ban"
return """
<button type="button" class="btn btn-sm btn-danger client-ban" value="{0}">ban</button>
""".format(ip)
<button type="button" class="btn btn-sm btn-danger client-{0}" value="{1}">{2}</button>
""".format(action, c["ip"], action)
def ban(self):
ip = self.request.matches.group(1)
logger.info("Banning {0} for {1} minutes".format(ip, 15))
WebSocketConnection.banIp(ip, 15)
self.send_response("{}", content_type="application/json", code=200)
def unban(self):
ip = self.request.matches.group(1)
logger.info("Unbanning {0}".format(ip))
WebSocketConnection.unbanIp(ip)
self.send_response("{}", content_type="application/json", code=200)
class SettingsFormController(AuthorizationMixin, BreadcrumbMixin, WebpageController, metaclass=ABCMeta):

View File

@ -23,12 +23,14 @@ from owrx.controllers.session import SessionController
from owrx.controllers.profile import ProfileController
from owrx.controllers.imageupload import ImageUploadController
from owrx.controllers.robots import RobotsController
from owrx.websocket import WebSocketConnection
from owrx.storage import Storage
from http.server import BaseHTTPRequestHandler
from urllib.parse import urlparse, parse_qs
import re
from abc import ABC, abstractmethod
from http.cookies import SimpleCookie
from datetime import datetime
import logging
@ -104,6 +106,8 @@ class Router(object):
StaticRoute("/metrics", MetricsController, options={"action": "prometheusAction"}),
StaticRoute("/metrics.json", MetricsController),
StaticRoute("/settings", SettingsController),
RegexRoute("^/settings/ban/(.+)$", SettingsController, options={"action": "ban"}),
RegexRoute("^/settings/unban/(.+)$", SettingsController, options={"action": "unban"}),
StaticRoute("/settings/general", GeneralSettingsController),
StaticRoute(
"/settings/general", GeneralSettingsController, method="POST", options={"action": "processFormData"}
@ -173,12 +177,15 @@ class Router(object):
return r
def route(self, handler, request):
route = self.find_route(request)
if route is not None:
controller = route.controller
controller(handler, request, route.controllerOptions).handle_request()
else:
if WebSocketConnection.isIpBanned(handler.client_address[0]):
handler.send_error(404, "Not Found", "The page you requested could not be found.")
else:
route = self.find_route(request)
if route is not None:
controller = route.controller
controller(handler, request, route.controllerOptions).handle_request()
else:
handler.send_error(404, "Not Found", "The page you requested could not be found.")
class RequestHandler(BaseHTTPRequestHandler):

View File

@ -6,7 +6,7 @@ from multiprocessing import Pipe
import select
import threading
from abc import ABC, abstractmethod
from datetime import datetime
from datetime import datetime, timedelta
import logging
@ -47,6 +47,7 @@ class Handler(ABC):
class WebSocketConnection(object):
connections = []
bans = {}
@staticmethod
def closeAll():
@ -59,20 +60,58 @@ class WebSocketConnection(object):
@staticmethod
def listAll():
result = []
for x in WebSocketConnection.connections:
for c in WebSocketConnection.connections:
entry = {
"ts" : x.startTime,
"ip" : x.handler.client_address[0]
"ts" : c.startTime,
"ip" : c.handler.client_address[0],
"ban" : False
}
rx = x.messageHandler
rx = c.messageHandler
if hasattr(rx, "sdr"):
entry["sdr"] = rx.sdr.getName()
entry["band"] = rx.sdr.getProfileName()
result.append(entry)
WebSocketConnection.cleanBans()
for ip in WebSocketConnection.bans:
result.append({
"ts" : WebSocketConnection.bans[ip],
"ip" : ip,
"ban" : True
})
return result
@staticmethod
def banIp(ip: str, minutes: int):
WebSocketConnection.cleanBans()
WebSocketConnection.bans[ip] = datetime.now() + timedelta(minutes=minutes)
banned = []
for c in WebSocketConnection.connections:
if ip == c.handler.client_address[0]:
banned.append(c)
for c in banned:
try:
c.close()
except:
logger.exception("exception while banning %s" % ip)
@staticmethod
def unbanIp(ip: str):
if ip in WebSocketConnection.bans:
del WebSocketConnection.bans[ip]
@staticmethod
def isIpBanned(ip: str):
return ip in WebSocketConnection.bans and datetime.now() < WebSocketConnection.bans[ip]
@staticmethod
def cleanBans():
now = datetime.now()
old = [ip for ip in WebSocketConnection.bans if now >= WebSocketConnection.bans[ip]]
for ip in old:
del WebSocketConnection.bans[ip]
def __init__(self, handler, messageHandler: Handler):
self.startTime = datetime.utcnow()
self.startTime = datetime.now()
self.handler = handler
self.handler.connection.setblocking(0)
self.messageHandler = None