From 0e2db3c3439591ae5ca910d30d89945426183170 Mon Sep 17 00:00:00 2001 From: Marat Fayzullin Date: Mon, 13 Nov 2023 22:11:10 -0500 Subject: [PATCH 1/9] Adding current users list to the Settings main page. --- htdocs/settings.html | 6 +++++ owrx/controllers/settings/__init__.py | 34 +++++++++++++++++++++++++++ owrx/source/__init__.py | 3 +++ owrx/websocket.py | 11 +++++++++ 4 files changed, 54 insertions(+) diff --git a/htdocs/settings.html b/htdocs/settings.html index 34e609bf..c9e6dadf 100644 --- a/htdocs/settings.html +++ b/htdocs/settings.html @@ -37,5 +37,11 @@ ${header} Feature report +
+

Clients

+
+
+ ${clients} +
diff --git a/owrx/controllers/settings/__init__.py b/owrx/controllers/settings/__init__.py index 8ad8a4e8..fc4e39e1 100644 --- a/owrx/controllers/settings/__init__.py +++ b/owrx/controllers/settings/__init__.py @@ -2,8 +2,10 @@ from owrx.config import Config from owrx.controllers.admin import AuthorizationMixin from owrx.controllers.template import WebpageController from owrx.breadcrumb import Breadcrumb, BreadcrumbItem, BreadcrumbMixin +from owrx.websocket import WebSocketConnection from abc import ABCMeta, abstractmethod from urllib.parse import parse_qs +import re import logging @@ -14,6 +16,37 @@ class SettingsController(AuthorizationMixin, WebpageController): def indexAction(self): self.serve_template("settings.html", **self.template_variables()) + def template_variables(self): + variables = super().template_variables() + variables["clients"] = self.renderClients() + return variables + + def renderClients(self): + return """ + + + + + + + + {clients} +
Connection TimeIP AddressSDR ProfileActions
+ """.format( + clients="".join(self.renderClient(c) for c in WebSocketConnection.listAll()) + ) + + def renderClient(self, c): + return "{0}{1}{2}".format( + c[0].strftime('%Y-%m-%d %H:%M:%S'), self.renderIp(c[1]), c[2] + " " + c[3] + ) + + def renderIp(self, ip): + ip = re.sub("^::ffff:", "", ip) + return """ + {1} + """.format(ip, ip) + class SettingsFormController(AuthorizationMixin, BreadcrumbMixin, WebpageController, metaclass=ABCMeta): def __init__(self, handler, request, options): @@ -64,6 +97,7 @@ class SettingsFormController(AuthorizationMixin, BreadcrumbMixin, WebpageControl variables["title"] = self.getTitle() variables["modal"] = self.buildModal() variables["error"] = self.renderGlobalError() + variables["clients"] = self.renderClients() return variables def parseFormData(self): diff --git a/owrx/source/__init__.py b/owrx/source/__init__.py index 5f5fe7c9..fcb566c8 100644 --- a/owrx/source/__init__.py +++ b/owrx/source/__init__.py @@ -280,6 +280,9 @@ class SdrSource(ABC): def getName(self): return self.props["name"] + def getProfileName(self): + return self.getProfiles()[self.getProfileId()]["name"] + def getProps(self): return self.props diff --git a/owrx/websocket.py b/owrx/websocket.py index 55badf63..ef37488e 100644 --- a/owrx/websocket.py +++ b/owrx/websocket.py @@ -6,6 +6,7 @@ from multiprocessing import Pipe import select import threading from abc import ABC, abstractmethod +from datetime import datetime import logging @@ -55,7 +56,17 @@ class WebSocketConnection(object): except: logger.exception("exception while shutting down websocket connections") + @staticmethod + def listAll(): + return [( + x.startTime, + x.handler.client_address[0], + x.messageHandler.sdr.getName(), + x.messageHandler.sdr.getProfileName() + ) for x in WebSocketConnection.connections] + def __init__(self, handler, messageHandler: Handler): + self.startTime = datetime.utcnow() self.handler = handler self.handler.connection.setblocking(0) self.messageHandler = None From 7382ebc60330ddde3923ac2efafe26e1ff87533f Mon Sep 17 00:00:00 2001 From: Marat Fayzullin Date: Mon, 13 Nov 2023 22:56:30 -0500 Subject: [PATCH 2/9] Fixing an error. --- owrx/controllers/settings/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/owrx/controllers/settings/__init__.py b/owrx/controllers/settings/__init__.py index fc4e39e1..070bf389 100644 --- a/owrx/controllers/settings/__init__.py +++ b/owrx/controllers/settings/__init__.py @@ -97,7 +97,6 @@ class SettingsFormController(AuthorizationMixin, BreadcrumbMixin, WebpageControl variables["title"] = self.getTitle() variables["modal"] = self.buildModal() variables["error"] = self.renderGlobalError() - variables["clients"] = self.renderClients() return variables def parseFormData(self): From 0edf441dfc2b18abf378fc105864d4452b6792ce Mon Sep 17 00:00:00 2001 From: Marat Fayzullin Date: Mon, 13 Nov 2023 22:57:54 -0500 Subject: [PATCH 3/9] Moved clients list up. --- htdocs/settings.html | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/htdocs/settings.html b/htdocs/settings.html index c9e6dadf..303d374a 100644 --- a/htdocs/settings.html +++ b/htdocs/settings.html @@ -11,6 +11,12 @@ ${header}
+
+

Clients

+
+
+ ${clients} +

Settings

@@ -37,11 +43,5 @@ ${header} Feature report
-
-

Clients

-
-
- ${clients} -
From b2f1c245cf0ee58e9eaa3c5de22bb1f323479469 Mon Sep 17 00:00:00 2001 From: Marat Fayzullin Date: Tue, 14 Nov 2023 17:02:27 -0500 Subject: [PATCH 4/9] Making sure map connections do not crash the list code. --- owrx/controllers/settings/__init__.py | 33 ++++++++++++++++++--------- owrx/websocket.py | 18 ++++++++++----- 2 files changed, 34 insertions(+), 17 deletions(-) diff --git a/owrx/controllers/settings/__init__.py b/owrx/controllers/settings/__init__.py index 070bf389..34d09027 100644 --- a/owrx/controllers/settings/__init__.py +++ b/owrx/controllers/settings/__init__.py @@ -21,24 +21,30 @@ class SettingsController(AuthorizationMixin, WebpageController): variables["clients"] = self.renderClients() return variables +#
+#
+ def renderClients(self): return """ - - - - - - - - {clients} -
Connection TimeIP AddressSDR ProfileActions
+ + + + + + + + {clients} +
Connection TimeIP AddressSDR ProfileActions
""".format( clients="".join(self.renderClient(c) for c in WebSocketConnection.listAll()) ) def renderClient(self, c): - return "{0}{1}{2}".format( - c[0].strftime('%Y-%m-%d %H:%M:%S'), self.renderIp(c[1]), c[2] + " " + c[3] + return "{0}{1}{2}{3}".format( + c["ts"].strftime('%Y-%m-%d %H:%M:%S'), + self.renderIp(c["ip"]), + c["sdr"] + " " + c["band"] if "sdr" in c else "n/a", + self.renderButtons(c["ip"]) ) def renderIp(self, ip): @@ -47,6 +53,11 @@ class SettingsController(AuthorizationMixin, WebpageController): {1} """.format(ip, ip) + def renderButtons(self, ip): + return """ + + """.format(ip) + class SettingsFormController(AuthorizationMixin, BreadcrumbMixin, WebpageController, metaclass=ABCMeta): def __init__(self, handler, request, options): diff --git a/owrx/websocket.py b/owrx/websocket.py index ef37488e..69dc047a 100644 --- a/owrx/websocket.py +++ b/owrx/websocket.py @@ -58,12 +58,18 @@ class WebSocketConnection(object): @staticmethod def listAll(): - return [( - x.startTime, - x.handler.client_address[0], - x.messageHandler.sdr.getName(), - x.messageHandler.sdr.getProfileName() - ) for x in WebSocketConnection.connections] + result = [] + for x in WebSocketConnection.connections: + entry = { + "ts" : x.startTime, + "ip" : x.handler.client_address[0] + } + rx = x.messageHandler + if hasattr(rx, "sdr"): + entry["sdr"] = rx.sdr.getName() + entry["band"] = rx.sdr.getProfileName() + result.append(entry) + return result def __init__(self, handler, messageHandler: Handler): self.startTime = datetime.utcnow() From 675724759694938dcaeb22d0bf1c0b0aa83135a4 Mon Sep 17 00:00:00 2001 From: Marat Fayzullin Date: Wed, 15 Nov 2023 23:43:52 -0500 Subject: [PATCH 5/9] Banning unbanning users now works. --- htdocs/lib/UI.js | 8 +++-- htdocs/lib/settings/ClientList.js | 17 +++++++++ htdocs/settings.html | 12 +++---- htdocs/settings.js | 3 +- owrx/controllers/assets.py | 1 + owrx/controllers/settings/__init__.py | 33 +++++++++++------ owrx/http.py | 17 ++++++--- owrx/websocket.py | 51 +++++++++++++++++++++++---- 8 files changed, 111 insertions(+), 31 deletions(-) create mode 100644 htdocs/lib/settings/ClientList.js diff --git a/htdocs/lib/UI.js b/htdocs/lib/UI.js index 2bea4b3a..63d6ec23 100644 --- a/htdocs/lib/UI.js +++ b/htdocs/lib/UI.js @@ -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); } }; diff --git a/htdocs/lib/settings/ClientList.js b/htdocs/lib/settings/ClientList.js new file mode 100644 index 00000000..b4abc438 --- /dev/null +++ b/htdocs/lib/settings/ClientList.js @@ -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; + }); + }); +} diff --git a/htdocs/settings.html b/htdocs/settings.html index 303d374a..b16304e3 100644 --- a/htdocs/settings.html +++ b/htdocs/settings.html @@ -11,12 +11,6 @@ ${header}
-
-

Clients

-
-
- ${clients} -

Settings

@@ -43,5 +37,11 @@ ${header} Feature report
+
+

Clients

+
+
+ ${clients} +
diff --git a/htdocs/settings.js b/htdocs/settings.js index b1bc7361..c222bde0 100644 --- a/htdocs/settings.js +++ b/htdocs/settings.js @@ -9,4 +9,5 @@ $(function(){ $('#scheduler').schedulerInput(); $('.exponential-input').exponentialInput(); $('.device-log-messages').logMessages(); -}); \ No newline at end of file + $('.client-list').clientList(); +}); diff --git a/owrx/controllers/assets.py b/owrx/controllers/assets.py index e5da4a25..37b36880 100644 --- a/owrx/controllers/assets.py +++ b/owrx/controllers/assets.py @@ -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", ], } diff --git a/owrx/controllers/settings/__init__.py b/owrx/controllers/settings/__init__.py index 34d09027..baa97776 100644 --- a/owrx/controllers/settings/__init__.py +++ b/owrx/controllers/settings/__init__.py @@ -21,16 +21,13 @@ class SettingsController(AuthorizationMixin, WebpageController): variables["clients"] = self.renderClients() return variables -#
-#
- def renderClients(self): return """ - + {clients} @@ -40,11 +37,12 @@ class SettingsController(AuthorizationMixin, WebpageController): ) def renderClient(self, c): - return "".format( - c["ts"].strftime('%Y-%m-%d %H:%M:%S'), + return "".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): {1} """.format(ip, ip) - def renderButtons(self, ip): + def renderButtons(self, c): + action = "unban" if c["ban"] else "ban" return """ - - """.format(ip) + + """.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): diff --git a/owrx/http.py b/owrx/http.py index 12995cac..c2ab9ce7 100644 --- a/owrx/http.py +++ b/owrx/http.py @@ -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): diff --git a/owrx/websocket.py b/owrx/websocket.py index 69dc047a..6708fbe0 100644 --- a/owrx/websocket.py +++ b/owrx/websocket.py @@ -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 From 5ba68d346a3ea2ac4bcbab371d6281b860aff6bb Mon Sep 17 00:00:00 2001 From: Marat Fayzullin Date: Thu, 16 Nov 2023 00:14:31 -0500 Subject: [PATCH 6/9] Moved ClientController to a separate file. --- htdocs/clients.html | 21 ++++++++ owrx/controllers/clients.py | 71 +++++++++++++++++++++++++++ owrx/controllers/settings/__init__.py | 52 +------------------- owrx/http.py | 8 ++- 4 files changed, 100 insertions(+), 52 deletions(-) create mode 100644 htdocs/clients.html create mode 100644 owrx/controllers/clients.py diff --git a/htdocs/clients.html b/htdocs/clients.html new file mode 100644 index 00000000..37ba9dfd --- /dev/null +++ b/htdocs/clients.html @@ -0,0 +1,21 @@ + + + + OpenWebRX+ Clients + + + + + + + +${header} +
+
+

Clients

+
+
+ ${clients} +
+
+ diff --git a/owrx/controllers/clients.py b/owrx/controllers/clients.py new file mode 100644 index 00000000..c11d2a83 --- /dev/null +++ b/owrx/controllers/clients.py @@ -0,0 +1,71 @@ +from owrx.controllers.admin import AuthorizationMixin +from owrx.controllers.template import WebpageController +from owrx.breadcrumb import Breadcrumb, BreadcrumbItem, BreadcrumbMixin +from owrx.websocket import WebSocketConnection +import re + +import logging + +logger = logging.getLogger(__name__) + + +class ClientController(AuthorizationMixin, WebpageController): + def indexAction(self): + self.serve_template("clients.html", **self.template_variables()) + + def template_variables(self): + variables = super().template_variables() + variables["clients"] = self.renderClients() + return variables + + @staticmethod + def renderClients(): + return """ +
Connection Time IP Address SDR ProfileLocal Time Actions
{0}{1}{2}{3}
{0}{1}{2} {3}{4}
+ + + + + + + {clients} +
IP AddressSDR ProfileLocal TimeActions
+ """.format( + clients="".join(ClientController.renderClient(c) for c in WebSocketConnection.listAll()) + ) + + @staticmethod + def renderClient(c): + return "{0}{1}{2} {3}{4}".format( + ClientController.renderIp(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'), + ClientController.renderButtons(c) + ) + + @staticmethod + def renderIp(ip): + ip = re.sub("^::ffff:", "", ip) + return """ + {1} + """.format(ip, ip) + + @staticmethod + def renderButtons(c): + action = "unban" if c["ban"] else "ban" + return """ + + """.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) diff --git a/owrx/controllers/settings/__init__.py b/owrx/controllers/settings/__init__.py index baa97776..e02404cc 100644 --- a/owrx/controllers/settings/__init__.py +++ b/owrx/controllers/settings/__init__.py @@ -1,11 +1,11 @@ from owrx.config import Config from owrx.controllers.admin import AuthorizationMixin from owrx.controllers.template import WebpageController +from owrx.controllers.clients import ClientController from owrx.breadcrumb import Breadcrumb, BreadcrumbItem, BreadcrumbMixin from owrx.websocket import WebSocketConnection from abc import ABCMeta, abstractmethod from urllib.parse import parse_qs -import re import logging @@ -18,57 +18,9 @@ class SettingsController(AuthorizationMixin, WebpageController): def template_variables(self): variables = super().template_variables() - variables["clients"] = self.renderClients() + variables["clients"] = ClientController.renderClients() return variables - def renderClients(self): - return """ - - - - - - - - {clients} -
IP AddressSDR ProfileLocal TimeActions
- """.format( - clients="".join(self.renderClient(c) for c in WebSocketConnection.listAll()) - ) - - def renderClient(self, c): - return "{0}{1}{2} {3}{4}".format( - self.renderIp(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): - ip = re.sub("^::ffff:", "", ip) - return """ - {1} - """.format(ip, ip) - - def renderButtons(self, c): - action = "unban" if c["ban"] else "ban" - return """ - - """.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): def __init__(self, handler, request, options): diff --git a/owrx/http.py b/owrx/http.py index c2ab9ce7..6245f8ee 100644 --- a/owrx/http.py +++ b/owrx/http.py @@ -6,6 +6,7 @@ from owrx.controllers.assets import OwrxAssetsController, AprsSymbolsController, from owrx.controllers.websocket import WebSocketController from owrx.controllers.api import ApiController from owrx.controllers.metrics import MetricsController +from owrx.controllers.clients import ClientController from owrx.controllers.settings import SettingsController from owrx.controllers.settings.general import GeneralSettingsController from owrx.controllers.settings.sdr import ( @@ -106,8 +107,11 @@ 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("/clients", ClientController), + RegexRoute("^/clients/ban/(.+)$", ClientController, options={"action": "ban"}), + RegexRoute("^/clients/unban/(.+)$", ClientController, options={"action": "unban"}), + RegexRoute("^/settings/ban/(.+)$", ClientController, options={"action": "ban"}), + RegexRoute("^/settings/unban/(.+)$", ClientController, options={"action": "unban"}), StaticRoute("/settings/general", GeneralSettingsController), StaticRoute( "/settings/general", GeneralSettingsController, method="POST", options={"action": "processFormData"} From 9937f49b73cc24ebffacd4df5398cfd34478d96d Mon Sep 17 00:00:00 2001 From: Marat Fayzullin Date: Thu, 16 Nov 2023 11:46:01 -0500 Subject: [PATCH 7/9] Single endpoints to ban/unban. --- htdocs/lib/settings/ClientList.js | 4 ++-- owrx/http.py | 8 +++----- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/htdocs/lib/settings/ClientList.js b/htdocs/lib/settings/ClientList.js index b4abc438..b896b3fd 100644 --- a/htdocs/lib/settings/ClientList.js +++ b/htdocs/lib/settings/ClientList.js @@ -1,14 +1,14 @@ $.fn.clientList = function() { this.each(function() { $(this).on('click', '.client-ban', function(e) { - $.ajax(document.location.href + "/ban/" + this.value).done(function() { + $.ajax("/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() { + $.ajax("/unban/" + this.value).done(function() { document.location.reload(); }); return false; diff --git a/owrx/http.py b/owrx/http.py index 6245f8ee..16aa6648 100644 --- a/owrx/http.py +++ b/owrx/http.py @@ -107,11 +107,6 @@ class Router(object): StaticRoute("/metrics", MetricsController, options={"action": "prometheusAction"}), StaticRoute("/metrics.json", MetricsController), StaticRoute("/settings", SettingsController), - StaticRoute("/clients", ClientController), - RegexRoute("^/clients/ban/(.+)$", ClientController, options={"action": "ban"}), - RegexRoute("^/clients/unban/(.+)$", ClientController, options={"action": "unban"}), - RegexRoute("^/settings/ban/(.+)$", ClientController, options={"action": "ban"}), - RegexRoute("^/settings/unban/(.+)$", ClientController, options={"action": "unban"}), StaticRoute("/settings/general", GeneralSettingsController), StaticRoute( "/settings/general", GeneralSettingsController, method="POST", options={"action": "processFormData"} @@ -166,6 +161,9 @@ class Router(object): StaticRoute( "/settings/decoding", DecodingSettingsController, method="POST", options={"action": "processFormData"} ), + StaticRoute("/clients", ClientController), + RegexRoute("^/ban/(.+)$", ClientController, options={"action": "ban"}), + RegexRoute("^/unban/(.+)$", ClientController, options={"action": "unban"}), StaticRoute("/login", SessionController, options={"action": "loginAction"}), StaticRoute("/login", SessionController, method="POST", options={"action": "processLoginAction"}), StaticRoute("/logout", SessionController, options={"action": "logoutAction"}), From c59f549ab9a1750d0abda13262574ce9a422734e Mon Sep 17 00:00:00 2001 From: Marat Fayzullin Date: Thu, 16 Nov 2023 21:20:24 -0500 Subject: [PATCH 8/9] Added ban time selector. --- htdocs/clients.html | 2 +- htdocs/lib/settings/ClientList.js | 13 ++++++++-- htdocs/settings.html | 2 +- owrx/controllers/clients.py | 42 +++++++++++++++++++++++++------ owrx/http.py | 4 +-- 5 files changed, 49 insertions(+), 14 deletions(-) diff --git a/htdocs/clients.html b/htdocs/clients.html index 37ba9dfd..f828d879 100644 --- a/htdocs/clients.html +++ b/htdocs/clients.html @@ -14,7 +14,7 @@ ${header}

Clients

-
+
${clients}
diff --git a/htdocs/lib/settings/ClientList.js b/htdocs/lib/settings/ClientList.js index b896b3fd..e1f091f1 100644 --- a/htdocs/lib/settings/ClientList.js +++ b/htdocs/lib/settings/ClientList.js @@ -1,14 +1,23 @@ $.fn.clientList = function() { this.each(function() { $(this).on('click', '.client-ban', function(e) { - $.ajax("/ban/" + this.value).done(function() { + var mins = $('#ban-minutes').val(); + $.ajax("/ban", { + data: JSON.stringify({ ip: this.value, mins: mins }), + contentType: 'application/json', + method: 'POST' + }).done(function() { document.location.reload(); }); return false; }); $(this).on('click', '.client-unban', function(e) { - $.ajax("/unban/" + this.value).done(function() { + $.ajax("/unban", { + data: JSON.stringify({ ip: this.value }), + contentType: 'application/json', + method: 'POST' + }).done(function() { document.location.reload(); }); return false; diff --git a/htdocs/settings.html b/htdocs/settings.html index b16304e3..7effe03f 100644 --- a/htdocs/settings.html +++ b/htdocs/settings.html @@ -40,7 +40,7 @@ ${header}

Clients

-
+
${clients}
diff --git a/owrx/controllers/clients.py b/owrx/controllers/clients.py index c11d2a83..8782e645 100644 --- a/owrx/controllers/clients.py +++ b/owrx/controllers/clients.py @@ -2,6 +2,7 @@ from owrx.controllers.admin import AuthorizationMixin from owrx.controllers.template import WebpageController from owrx.breadcrumb import Breadcrumb, BreadcrumbItem, BreadcrumbMixin from owrx.websocket import WebSocketConnection +import json import re import logging @@ -29,6 +30,22 @@ class ClientController(AuthorizationMixin, WebpageController): Actions {clients} + + + + + ban for + + + """.format( clients="".join(ClientController.renderClient(c) for c in WebSocketConnection.listAll()) @@ -59,13 +76,22 @@ class ClientController(AuthorizationMixin, WebpageController): """.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) + try: + data = json.loads(self.get_body().decode("utf-8")) + mins = int(data["mins"]) if "mins" in data else 0 + if "ip" in data and mins > 0: + logger.info("Banning {0} for {1} minutes".format(data["ip"], mins)) + WebSocketConnection.banIp(data["ip"], mins) + self.send_response("{}", content_type="application/json", code=200) + except: + self.send_response("{}", content_type="application/json", code=400) 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) + try: + data = json.loads(self.get_body().decode("utf-8")) + if "ip" in data: + logger.info("Unbanning {0}".format(data["ip"])) + WebSocketConnection.unbanIp(data["ip"]) + self.send_response("{}", content_type="application/json", code=200) + except: + self.send_response("{}", content_type="application/json", code=400) diff --git a/owrx/http.py b/owrx/http.py index 16aa6648..26de6dd5 100644 --- a/owrx/http.py +++ b/owrx/http.py @@ -162,8 +162,8 @@ class Router(object): "/settings/decoding", DecodingSettingsController, method="POST", options={"action": "processFormData"} ), StaticRoute("/clients", ClientController), - RegexRoute("^/ban/(.+)$", ClientController, options={"action": "ban"}), - RegexRoute("^/unban/(.+)$", ClientController, options={"action": "unban"}), + StaticRoute("/ban", ClientController, method="POST", options={"action": "ban"}), + StaticRoute("/unban", ClientController, method="POST", options={"action": "unban"}), StaticRoute("/login", SessionController, options={"action": "loginAction"}), StaticRoute("/login", SessionController, method="POST", options={"action": "processLoginAction"}), StaticRoute("/logout", SessionController, options={"action": "logoutAction"}), From b76f8ad391b26acc8d9cc593ca3fa5092fd1d8c5 Mon Sep 17 00:00:00 2001 From: Marat Fayzullin Date: Thu, 16 Nov 2023 21:25:43 -0500 Subject: [PATCH 9/9] Reordered some code. --- owrx/http.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/owrx/http.py b/owrx/http.py index 26de6dd5..aff0f8a4 100644 --- a/owrx/http.py +++ b/owrx/http.py @@ -183,11 +183,11 @@ class Router(object): 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: + if route is None: + handler.send_error(404, "Not Found", "The page you requested could not be found.") + else: 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):