From 9a9d1b0feeea8927c55a97c1929e07da43dde596 Mon Sep 17 00:00:00 2001 From: 6C656C65 <73671374+6C656C65@users.noreply.github.com> Date: Mon, 9 Jun 2025 19:20:48 +0200 Subject: [PATCH 01/12] monitoring: add filter input --- pyproxy/handlers/https.py | 1 - pyproxy/monitoring/static/monitoring.js | 74 +++++++++++++++++++++---- pyproxy/monitoring/static/style.css | 29 ++++++++++ pyproxy/monitoring/templates/index.html | 6 +- 4 files changed, 98 insertions(+), 12 deletions(-) diff --git a/pyproxy/handlers/https.py b/pyproxy/handlers/https.py index 17ec5ce..08be289 100644 --- a/pyproxy/handlers/https.py +++ b/pyproxy/handlers/https.py @@ -415,7 +415,6 @@ def transfer_data_between_sockets(self, client_socket, server_socket): data ) except (socket.error, OSError): - self.logger_config.console_logger("error") client_socket.close() server_socket.close() self.active_connections.pop(threading.get_ident(), None) diff --git a/pyproxy/monitoring/static/monitoring.js b/pyproxy/monitoring/static/monitoring.js index 21f6e98..147a3e0 100644 --- a/pyproxy/monitoring/static/monitoring.js +++ b/pyproxy/monitoring/static/monitoring.js @@ -30,18 +30,31 @@ async function fetchAllData() { `).join('')} `; - document.getElementById('connections-section').innerHTML = ` -

Active Connections

+ document.getElementById('connections-table-container').innerHTML = ` ${monitoring.active_connections.length === 0 ? '

No active connections.

' - : monitoring.active_connections.map(conn => ` -
-

Client: ${conn.client_ip}:${conn.client_port}

-

Target: ${conn.target_domain} (${conn.target_ip}:${conn.target_port})

-

Sent: ${conn.bytes_sent} bytes

-

Received: ${formatBytes(conn.bytes_received)}

-
- `).join('')} + : ` + + + + + + + + + + + ${monitoring.active_connections.map(conn => ` + + + + + + + `).join('')} + +
ClientTargetSentReceived
${conn.client_ip}:${conn.client_port}${conn.target_domain} (${conn.target_ip}:${conn.target_port})${conn.bytes_sent} bytes${formatBytes(conn.bytes_received)}
+ `} `; document.getElementById('config-section').innerHTML = ` @@ -63,6 +76,11 @@ async function fetchAllData() {

Cancel inspect: ${config.ssl_config.cancel_inspect ? `${config.ssl_config.cancel_inspect}` : ''}

`; + const searchInput = document.getElementById('connection-search'); + if (searchInput) { + filterConnections(searchInput.value); + } + } catch (err) { console.error('Error loading data:', err); } @@ -86,6 +104,35 @@ function formatCountdown(seconds) { return `${m}:${s}`; } +function filterConnections(filter) { + filter = filter.toLowerCase(); + const rows = document.querySelectorAll('.connection-table tbody tr'); + rows.forEach(row => { + const client = row.children[0].textContent.toLowerCase(); + const target = row.children[1].textContent.toLowerCase(); + + row.querySelectorAll('td').forEach(td => { + td.innerHTML = td.textContent; + }); + + const match = client.includes(filter) || target.includes(filter); + row.style.display = match ? '' : 'none'; + + if (match && filter.length > 0) { + if (client.includes(filter)) { + const originalText = row.children[0].textContent; + const regex = new RegExp(`(${filter})`, 'gi'); + row.children[0].innerHTML = originalText.replace(regex, '$1'); + } + if (target.includes(filter)) { + const originalText = row.children[1].textContent; + const regex = new RegExp(`(${filter})`, 'gi'); + row.children[1].innerHTML = originalText.replace(regex, '$1'); + } + } + }); +} + setInterval(() => { countdown--; if (countdown <= 0) fetchAllData(); @@ -137,6 +184,13 @@ window.addEventListener('DOMContentLoaded', () => { } activateTab(tabs[0]); + const searchInput = document.getElementById('connection-search'); + if (searchInput) { + searchInput.addEventListener('input', () => { + filterConnections(searchInput.value); + }); + } + fetchAllData(); updateCountdown(); }); diff --git a/pyproxy/monitoring/static/style.css b/pyproxy/monitoring/static/style.css index 7941bb7..1bcbd15 100644 --- a/pyproxy/monitoring/static/style.css +++ b/pyproxy/monitoring/static/style.css @@ -140,4 +140,33 @@ h1 { .tab-content.active { display: block; +} + +.connection-table { + width: 100%; + border-collapse: collapse; + margin-top: 10px; +} + +.connection-table th, +.connection-table td { + border: 1px solid #ccc; + padding: 8px; + text-align: left; +} + +.connection-table th { + background-color: #f2f2f2; +} + +#connections-section { + max-width: 100%; +} + +input#connection-search, .connection-table { + box-sizing: border-box; +} + +.highlight { + background-color: yellow; } \ No newline at end of file diff --git a/pyproxy/monitoring/templates/index.html b/pyproxy/monitoring/templates/index.html index 812a100..1571810 100644 --- a/pyproxy/monitoring/templates/index.html +++ b/pyproxy/monitoring/templates/index.html @@ -33,7 +33,11 @@

-
+
+

Active Connections

+ +
+
From aef144ba26ec4da21cade76fc7e1ace826a14865 Mon Sep 17 00:00:00 2001 From: 6C656C65 <73671374+6C656C65@users.noreply.github.com> Date: Mon, 9 Jun 2025 19:41:39 +0200 Subject: [PATCH 02/12] monitoring: view filtering list --- pyproxy/monitoring/routes.py | 17 +++++++++++++++ pyproxy/monitoring/static/monitoring.js | 28 +++++++++++++++++++++++-- pyproxy/monitoring/templates/index.html | 13 ++++++++---- 3 files changed, 52 insertions(+), 6 deletions(-) diff --git a/pyproxy/monitoring/routes.py b/pyproxy/monitoring/routes.py index d5aeb6c..8e1c0ad 100644 --- a/pyproxy/monitoring/routes.py +++ b/pyproxy/monitoring/routes.py @@ -76,3 +76,20 @@ def config(): "flask_port": proxy_server.monitoring_config.flask_port, } return jsonify(config_data) + + @app.route("/blocked", methods=["GET"]) + @auth.login_required + def blocked(): + blocked_sites_content = "" + blocked_url_content = "" + + with open(proxy_server.filter_config.blocked_sites, "r", encoding="utf-8") as f: + blocked_sites_content = [line.strip() for line in f if line.strip()] + with open(proxy_server.filter_config.blocked_url, "r", encoding="utf-8") as f: + blocked_url_content = [line.strip() for line in f if line.strip()] + + blocked_data = { + "blocked_sites": blocked_sites_content, + "blocked_url": blocked_url_content, + } + return jsonify(blocked_data) diff --git a/pyproxy/monitoring/static/monitoring.js b/pyproxy/monitoring/static/monitoring.js index 147a3e0..d21cf55 100644 --- a/pyproxy/monitoring/static/monitoring.js +++ b/pyproxy/monitoring/static/monitoring.js @@ -2,13 +2,15 @@ let countdown = 2; async function fetchAllData() { try { - const [monitoringRes, configRes] = await Promise.all([ + const [monitoringRes, configRes, blockedRes] = await Promise.all([ fetch('/monitoring'), - fetch('/config') + fetch('/config'), + fetch('/blocked') ]); const monitoring = await monitoringRes.json(); const config = await configRes.json(); + const blocked = await blockedRes.json(); document.getElementById('status-section').innerHTML = `

Main Process

@@ -81,6 +83,28 @@ async function fetchAllData() { filterConnections(searchInput.value); } + const blockedSites = blocked.blocked_sites || []; + const blockedUrls = blocked.blocked_url || []; + + const blockedSection = document.getElementById('blocked-section'); + if (blockedSection) { + blockedSection.innerHTML = ` +

Filtering

+
+

Blocked sites

+ ${blockedSites.length === 0 + ? '

No blocked sites.

' + : ``} +
+
+

Blocked URLs

+ ${blockedUrls.length === 0 + ? '

No URLs blocked.

' + : ``} +
+ `; + } + } catch (err) { console.error('Error loading data:', err); } diff --git a/pyproxy/monitoring/templates/index.html b/pyproxy/monitoring/templates/index.html index 1571810..4a944c2 100644 --- a/pyproxy/monitoring/templates/index.html +++ b/pyproxy/monitoring/templates/index.html @@ -20,6 +20,7 @@

+ @@ -29,16 +30,20 @@

-
Loading config...
+
Loading...
-

Active Connections

- -
+

Active Connections

+ +
+ + From b3b0e6a3d6b143858db923a08f63a6653bee4eca Mon Sep 17 00:00:00 2001 From: 6C656C65 <73671374+6C656C65@users.noreply.github.com> Date: Tue, 10 Jun 2025 18:28:23 +0200 Subject: [PATCH 03/12] changelog for 0.4.4 & 0.4.5 --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f76a3f7..ce3b42c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +## [0.4.5] - 2025-06-09 +### Added +- Monitoring : refresh timer +### Change +- Rework monitoring code + +## [0.4.4] - 2025-06-08 +### Change +- Repository migration + ## [0.4.3] - 2025-06-08 ### Added - Docs: installation from compose From f70c32e0c297137392a26459a0f57ddb3e81776b Mon Sep 17 00:00:00 2001 From: 6C656C65 <73671374+6C656C65@users.noreply.github.com> Date: Wed, 11 Jun 2025 11:00:37 +0200 Subject: [PATCH 04/12] monitoring: add searchbar for filtering list --- pyproxy/monitoring/static/monitoring.js | 41 +++++++++++++++++++++++-- pyproxy/monitoring/templates/index.html | 6 +++- 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/pyproxy/monitoring/static/monitoring.js b/pyproxy/monitoring/static/monitoring.js index d21cf55..93f120b 100644 --- a/pyproxy/monitoring/static/monitoring.js +++ b/pyproxy/monitoring/static/monitoring.js @@ -86,10 +86,9 @@ async function fetchAllData() { const blockedSites = blocked.blocked_sites || []; const blockedUrls = blocked.blocked_url || []; - const blockedSection = document.getElementById('blocked-section'); + const blockedSection = document.getElementById('blocked-section-container'); if (blockedSection) { blockedSection.innerHTML = ` -

Filtering

Blocked sites

${blockedSites.length === 0 @@ -105,6 +104,11 @@ async function fetchAllData() { `; } + const blockedSearchInput = document.getElementById('blocked-search'); + if (blockedSearchInput) { + filterBlocked(blockedSearchInput.value); + } + } catch (err) { console.error('Error loading data:', err); } @@ -157,6 +161,32 @@ function filterConnections(filter) { }); } +function filterBlocked(filter) { + filter = filter.toLowerCase(); + + const blockedSection = document.getElementById('blocked-section-container'); + if (!blockedSection) return; + + const lists = blockedSection.querySelectorAll('ul'); + + lists.forEach(list => { + list.querySelectorAll('li').forEach(li => { + const text = li.textContent.toLowerCase(); + + li.innerHTML = li.textContent; + + const match = text.includes(filter); + li.style.display = match ? '' : 'none'; + + if (match && filter.length > 0) { + const originalText = li.textContent; + const regex = new RegExp(`(${filter})`, 'gi'); + li.innerHTML = originalText.replace(regex, '$1'); + } + }); + }); +} + setInterval(() => { countdown--; if (countdown <= 0) fetchAllData(); @@ -215,6 +245,13 @@ window.addEventListener('DOMContentLoaded', () => { }); } + const blockedSearchInput = document.getElementById('blocked-search'); + if (blockedSearchInput) { + blockedSearchInput.addEventListener('input', () => { + filterBlocked(blockedSearchInput.value); + }); + } + fetchAllData(); updateCountdown(); }); diff --git a/pyproxy/monitoring/templates/index.html b/pyproxy/monitoring/templates/index.html index 4a944c2..5f75447 100644 --- a/pyproxy/monitoring/templates/index.html +++ b/pyproxy/monitoring/templates/index.html @@ -42,7 +42,11 @@

Active Connections

From e61e146e2d15958c7ec0e04948406cd4b6d765db Mon Sep 17 00:00:00 2001 From: 6C656C65 <73671374+6C656C65@users.noreply.github.com> Date: Wed, 11 Jun 2025 14:36:12 +0200 Subject: [PATCH 05/12] monitoring: fix change tab refresh page --- pyproxy/monitoring/static/monitoring.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/pyproxy/monitoring/static/monitoring.js b/pyproxy/monitoring/static/monitoring.js index 93f120b..29640f9 100644 --- a/pyproxy/monitoring/static/monitoring.js +++ b/pyproxy/monitoring/static/monitoring.js @@ -234,9 +234,14 @@ window.addEventListener('DOMContentLoaded', () => { const savedTabId = localStorage.getItem('activeTabId'); if (savedTabId) { const savedTab = document.getElementById(savedTabId); - if (savedTab) activateTab(savedTab); + if (savedTab) { + activateTab(savedTab); + } else { + activateTab(tabs[0]); + } + } else { + activateTab(tabs[0]); } - activateTab(tabs[0]); const searchInput = document.getElementById('connection-search'); if (searchInput) { From 520303fcdcb2c8872ecdd646c5c3ae31ee77c922 Mon Sep 17 00:00:00 2001 From: 6C656C65 <73671374+6C656C65@users.noreply.github.com> Date: Wed, 11 Jun 2025 15:17:08 +0200 Subject: [PATCH 06/12] monitoring: delete filtering list --- pyproxy/monitoring/routes.py | 59 +++++++++++++---- pyproxy/monitoring/static/monitoring.js | 86 +++++++++++++++++++++---- pyproxy/monitoring/static/style.css | 19 ++++-- 3 files changed, 134 insertions(+), 30 deletions(-) diff --git a/pyproxy/monitoring/routes.py b/pyproxy/monitoring/routes.py index 8e1c0ad..95265dc 100644 --- a/pyproxy/monitoring/routes.py +++ b/pyproxy/monitoring/routes.py @@ -6,7 +6,7 @@ HTML-based index page. """ -from flask import jsonify, render_template +from flask import jsonify, render_template, request def register_routes(app, auth, proxy_server, ProxyMonitor): @@ -77,19 +77,52 @@ def config(): } return jsonify(config_data) - @app.route("/blocked", methods=["GET"]) + @app.route("/blocked", methods=["GET", "DELETE"]) @auth.login_required def blocked(): - blocked_sites_content = "" - blocked_url_content = "" + if request.method == "GET": + blocked_sites_content = "" + blocked_url_content = "" - with open(proxy_server.filter_config.blocked_sites, "r", encoding="utf-8") as f: - blocked_sites_content = [line.strip() for line in f if line.strip()] - with open(proxy_server.filter_config.blocked_url, "r", encoding="utf-8") as f: - blocked_url_content = [line.strip() for line in f if line.strip()] + with open(proxy_server.filter_config.blocked_sites, "r", encoding="utf-8") as f: + blocked_sites_content = [line.strip() for line in f if line.strip()] + with open(proxy_server.filter_config.blocked_url, "r", encoding="utf-8") as f: + blocked_url_content = [line.strip() for line in f if line.strip()] - blocked_data = { - "blocked_sites": blocked_sites_content, - "blocked_url": blocked_url_content, - } - return jsonify(blocked_data) + blocked_data = { + "blocked_sites": blocked_sites_content, + "blocked_url": blocked_url_content, + } + return jsonify(blocked_data) + + elif request.method == "DELETE": + data = request.get_json() + if not data or "type" not in data or "value" not in data: + return jsonify({"error": "Missing 'type' or 'value' in request body"}), 400 + + block_type = data["type"] + value = data["value"].strip() + + if block_type == "domain": + filepath = proxy_server.filter_config.blocked_sites + elif block_type == "url": + filepath = proxy_server.filter_config.blocked_url + else: + return jsonify({"error": "Invalid type, must be 'domain' or 'url'"}), 400 + + try: + with open(filepath, "r", encoding="utf-8") as f: + lines = [line.strip() for line in f if line.strip()] + + if value not in lines: + return jsonify({"error": f"{value} not found in {block_type} list"}), 404 + + lines = [line for line in lines if line != value] + + with open(filepath, "w", encoding="utf-8") as f: + for line in lines: + f.write(line + "\n") + + return jsonify({"message": f"{block_type} '{value}' removed successfully"}), 200 + except Exception as e: + return jsonify({"error": f"Server error: {str(e)}"}), 500 diff --git a/pyproxy/monitoring/static/monitoring.js b/pyproxy/monitoring/static/monitoring.js index 29640f9..682bfb4 100644 --- a/pyproxy/monitoring/static/monitoring.js +++ b/pyproxy/monitoring/static/monitoring.js @@ -36,7 +36,7 @@ async function fetchAllData() { ${monitoring.active_connections.length === 0 ? '

No active connections.

' : ` - +
@@ -89,18 +89,56 @@ async function fetchAllData() { const blockedSection = document.getElementById('blocked-section-container'); if (blockedSection) { blockedSection.innerHTML = ` -
-

Blocked sites

- ${blockedSites.length === 0 - ? '

No blocked sites.

' - : ``} -
-
-

Blocked URLs

- ${blockedUrls.length === 0 - ? '

No URLs blocked.

' - : ``} -
+
+

Blocked sites

+ ${blockedSites.length === 0 + ? '

No blocked sites.

' + : ` +
Client
+ + + + + + + + ${blockedSites.map(site => ` + + + + + `).join('')} + +
DomainAction
${site} + +
+ `} + +
+

Blocked URLs

+ ${blockedUrls.length === 0 + ? '

No URLs blocked.

' + : ` + + + + + + + + + ${blockedUrls.map(url => ` + + + + + `).join('')} + +
URLAction
${url} + +
+ `} +
`; } @@ -122,6 +160,28 @@ function formatBytes(bytes) { return (bytes / Math.pow(1024, i)).toFixed(2) + ' ' + sizes[i]; } +function handleUnblock(type, value) { + fetch('/blocked', { + method: 'DELETE', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + type: type, + value: value + }), + }) + .then(response => { + if (!response.ok) { + alert(`Error while deleting : ${value}`); + } + }) + .catch(err => { + console.error('Fetching error:', err); + alert('Network error'); + }); +} + function updateCountdown() { document.getElementById('refresh-timer').textContent = formatCountdown(countdown); } diff --git a/pyproxy/monitoring/static/style.css b/pyproxy/monitoring/static/style.css index 1bcbd15..74de6bb 100644 --- a/pyproxy/monitoring/static/style.css +++ b/pyproxy/monitoring/static/style.css @@ -142,23 +142,34 @@ h1 { display: block; } -.connection-table { +.generic-table { width: 100%; border-collapse: collapse; margin-top: 10px; } -.connection-table th, -.connection-table td { +.generic-table th, +.generic-table td { border: 1px solid #ccc; padding: 8px; text-align: left; } -.connection-table th { +.generic-table th { background-color: #f2f2f2; } +.filtering-table th:first-child, +.filtering-table td:first-child { + width: 70%; +} + +.filtering-table th:last-child, +.filtering-table td:last-child { + width: 30%; + text-align: center; +} + #connections-section { max-width: 100%; } From 0513df47d3105495ceb484ba8652bf280b8214fe Mon Sep 17 00:00:00 2001 From: 6C656C65 <73671374+6C656C65@users.noreply.github.com> Date: Wed, 11 Jun 2025 18:42:19 +0200 Subject: [PATCH 07/12] monitoring: add filtering list --- pyproxy/monitoring/routes.py | 25 ++++++++++++++++- pyproxy/monitoring/static/monitoring.js | 37 +++++++++++++++++++++++++ pyproxy/monitoring/templates/index.html | 15 ++++++++++ 3 files changed, 76 insertions(+), 1 deletion(-) diff --git a/pyproxy/monitoring/routes.py b/pyproxy/monitoring/routes.py index 95265dc..8ed9423 100644 --- a/pyproxy/monitoring/routes.py +++ b/pyproxy/monitoring/routes.py @@ -77,7 +77,7 @@ def config(): } return jsonify(config_data) - @app.route("/blocked", methods=["GET", "DELETE"]) + @app.route("/blocked", methods=["GET", "POST", "DELETE"]) @auth.login_required def blocked(): if request.method == "GET": @@ -95,6 +95,29 @@ def blocked(): } return jsonify(blocked_data) + elif request.method == "POST": + data = request.get_json() + typ = data.get("type") + val = data.get("value", "").strip() + if not val or typ not in ["domain", "url"]: + return jsonify({"error": "Invalid input"}), 400 + + filename = ( + proxy_server.filter_config.blocked_sites + if typ == "domain" + else proxy_server.filter_config.blocked_url + ) + + with open(filename, "r+", encoding="utf-8") as f: + lines = [line.strip() for line in f if line.strip()] + if val in lines: + return jsonify({"message": "Already blocked"}), 409 + lines.append(val) + f.seek(0) + f.truncate() + f.write("\n".join(lines) + "\n") + return jsonify({"message": "Added successfully"}), 201 + elif request.method == "DELETE": data = request.get_json() if not data or "type" not in data or "value" not in data: diff --git a/pyproxy/monitoring/static/monitoring.js b/pyproxy/monitoring/static/monitoring.js index 682bfb4..ce7a44c 100644 --- a/pyproxy/monitoring/static/monitoring.js +++ b/pyproxy/monitoring/static/monitoring.js @@ -174,6 +174,8 @@ function handleUnblock(type, value) { .then(response => { if (!response.ok) { alert(`Error while deleting : ${value}`); + } else { + fetchAllData(); } }) .catch(err => { @@ -317,6 +319,41 @@ window.addEventListener('DOMContentLoaded', () => { }); } + document.getElementById('add-block-form').addEventListener('submit', function(event) { + event.preventDefault(); + + const type = document.getElementById('block-type').value; + const value = document.getElementById('block-value').value.trim(); + + if (!value) { + alert('Please enter a value to block.'); + return; + } + + fetch('/blocked', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + type: type, + value: value + }), + }) + .then(response => { + if (response.ok) { + document.getElementById('block-value').value = ''; + fetchAllData(); + } else { + alert(`Error adding : ${value}`); + } + }) + .catch(err => { + console.error('Network error:', err); + alert('Network error'); + }); + }); + fetchAllData(); updateCountdown(); }); diff --git a/pyproxy/monitoring/templates/index.html b/pyproxy/monitoring/templates/index.html index 5f75447..f1da872 100644 --- a/pyproxy/monitoring/templates/index.html +++ b/pyproxy/monitoring/templates/index.html @@ -44,6 +44,21 @@

Active Connections