pyproxytools 0.4.4__tar.gz → 0.4.6__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pyproxytools-0.4.4/pyproxytools.egg-info → pyproxytools-0.4.6}/PKG-INFO +1 -1
- {pyproxytools-0.4.4 → pyproxytools-0.4.6}/pyproxy/__init__.py +1 -1
- {pyproxytools-0.4.4 → pyproxytools-0.4.6}/pyproxy/handlers/client.py +19 -18
- {pyproxytools-0.4.4 → pyproxytools-0.4.6}/pyproxy/handlers/http.py +15 -6
- {pyproxytools-0.4.4 → pyproxytools-0.4.6}/pyproxy/handlers/https.py +24 -6
- pyproxytools-0.4.6/pyproxy/monitoring/__init__.py +38 -0
- pyproxytools-0.4.6/pyproxy/monitoring/auth.py +31 -0
- pyproxytools-0.4.6/pyproxy/monitoring/monitor.py +196 -0
- pyproxytools-0.4.6/pyproxy/monitoring/routes.py +211 -0
- {pyproxytools-0.4.4 → pyproxytools-0.4.6}/pyproxy/server.py +1 -1
- {pyproxytools-0.4.4 → pyproxytools-0.4.6/pyproxytools.egg-info}/PKG-INFO +1 -1
- {pyproxytools-0.4.4 → pyproxytools-0.4.6}/pyproxytools.egg-info/SOURCES.txt +3 -1
- pyproxytools-0.4.4/pyproxy/monitoring/web.py +0 -279
- pyproxytools-0.4.4/tests/utils/__init__.py +0 -0
- {pyproxytools-0.4.4 → pyproxytools-0.4.6}/LICENSE +0 -0
- {pyproxytools-0.4.4 → pyproxytools-0.4.6}/README.md +0 -0
- {pyproxytools-0.4.4 → pyproxytools-0.4.6}/benchmark/benchmark.py +0 -0
- {pyproxytools-0.4.4 → pyproxytools-0.4.6}/benchmark/utils/__init__.py +0 -0
- {pyproxytools-0.4.4 → pyproxytools-0.4.6}/benchmark/utils/html.py +0 -0
- {pyproxytools-0.4.4 → pyproxytools-0.4.6}/benchmark/utils/req.py +0 -0
- {pyproxytools-0.4.4 → pyproxytools-0.4.6}/pyproject.toml +0 -0
- {pyproxytools-0.4.4 → pyproxytools-0.4.6}/pyproxy/__main__.py +0 -0
- {pyproxytools-0.4.4 → pyproxytools-0.4.6}/pyproxy/handlers/__init__.py +0 -0
- {pyproxytools-0.4.4 → pyproxytools-0.4.6}/pyproxy/modules/__init__.py +0 -0
- {pyproxytools-0.4.4 → pyproxytools-0.4.6}/pyproxy/modules/cancel_inspect.py +0 -0
- {pyproxytools-0.4.4 → pyproxytools-0.4.6}/pyproxy/modules/custom_header.py +0 -0
- {pyproxytools-0.4.4 → pyproxytools-0.4.6}/pyproxy/modules/filter.py +0 -0
- {pyproxytools-0.4.4 → pyproxytools-0.4.6}/pyproxy/modules/shortcuts.py +0 -0
- {pyproxytools-0.4.4 → pyproxytools-0.4.6}/pyproxy/pyproxy.py +0 -0
- {pyproxytools-0.4.4/pyproxy/monitoring → pyproxytools-0.4.6/pyproxy/utils}/__init__.py +0 -0
- {pyproxytools-0.4.4 → pyproxytools-0.4.6}/pyproxy/utils/args.py +0 -0
- {pyproxytools-0.4.4 → pyproxytools-0.4.6}/pyproxy/utils/config.py +0 -0
- {pyproxytools-0.4.4 → pyproxytools-0.4.6}/pyproxy/utils/crypto.py +0 -0
- {pyproxytools-0.4.4 → pyproxytools-0.4.6}/pyproxy/utils/http_req.py +0 -0
- {pyproxytools-0.4.4 → pyproxytools-0.4.6}/pyproxy/utils/logger.py +0 -0
- {pyproxytools-0.4.4 → pyproxytools-0.4.6}/pyproxytools.egg-info/dependency_links.txt +0 -0
- {pyproxytools-0.4.4 → pyproxytools-0.4.6}/pyproxytools.egg-info/entry_points.txt +0 -0
- {pyproxytools-0.4.4 → pyproxytools-0.4.6}/pyproxytools.egg-info/requires.txt +0 -0
- {pyproxytools-0.4.4 → pyproxytools-0.4.6}/pyproxytools.egg-info/top_level.txt +0 -0
- {pyproxytools-0.4.4 → pyproxytools-0.4.6}/requirements.txt +0 -0
- {pyproxytools-0.4.4 → pyproxytools-0.4.6}/setup.cfg +0 -0
- {pyproxytools-0.4.4 → pyproxytools-0.4.6}/setup.py +0 -0
- {pyproxytools-0.4.4/pyproxy/utils → pyproxytools-0.4.6/tests/modules}/__init__.py +0 -0
- {pyproxytools-0.4.4 → pyproxytools-0.4.6}/tests/modules/test_cancel_inspect.py +0 -0
- {pyproxytools-0.4.4 → pyproxytools-0.4.6}/tests/modules/test_custom_header.py +0 -0
- {pyproxytools-0.4.4 → pyproxytools-0.4.6}/tests/modules/test_filter.py +0 -0
- {pyproxytools-0.4.4 → pyproxytools-0.4.6}/tests/modules/test_shortcuts.py +0 -0
- {pyproxytools-0.4.4/tests/modules → pyproxytools-0.4.6/tests/utils}/__init__.py +0 -0
- {pyproxytools-0.4.4 → pyproxytools-0.4.6}/tests/utils/test_crypto.py +0 -0
- {pyproxytools-0.4.4 → pyproxytools-0.4.6}/tests/utils/test_http_req.py +0 -0
- {pyproxytools-0.4.4 → pyproxytools-0.4.6}/tests/utils/test_logger.py +0 -0
|
@@ -90,24 +90,25 @@ class ProxyHandlers:
|
|
|
90
90
|
Args:
|
|
91
91
|
client_socket (socket): The socket object for the client connection.
|
|
92
92
|
"""
|
|
93
|
-
|
|
93
|
+
try:
|
|
94
|
+
client_socket.settimeout(10)
|
|
95
|
+
request = client_socket.recv(4096)
|
|
94
96
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
+
if not request:
|
|
98
|
+
return
|
|
99
|
+
|
|
100
|
+
first_line = request.decode(errors="ignore").split("\n")[0]
|
|
101
|
+
if first_line.startswith("CONNECT"):
|
|
102
|
+
https_handler = self._create_handler(
|
|
103
|
+
HttpsHandler,
|
|
104
|
+
ssl_config=self.ssl_config,
|
|
105
|
+
cancel_inspect_queue=self.cancel_inspect_queue,
|
|
106
|
+
cancel_inspect_result_queue=self.cancel_inspect_result_queue,
|
|
107
|
+
)
|
|
108
|
+
https_handler.handle_https_connection(client_socket, first_line)
|
|
109
|
+
else:
|
|
110
|
+
http_handler = self._create_handler(HttpHandler)
|
|
111
|
+
http_handler.handle_http_request(client_socket, request)
|
|
112
|
+
finally:
|
|
97
113
|
client_socket.close()
|
|
98
114
|
self.active_connections.pop(threading.get_ident(), None)
|
|
99
|
-
return
|
|
100
|
-
|
|
101
|
-
first_line = request.decode(errors="ignore").split("\n")[0]
|
|
102
|
-
|
|
103
|
-
if first_line.startswith("CONNECT"):
|
|
104
|
-
https_handler = self._create_handler(
|
|
105
|
-
HttpsHandler,
|
|
106
|
-
ssl_config=self.ssl_config,
|
|
107
|
-
cancel_inspect_queue=self.cancel_inspect_queue,
|
|
108
|
-
cancel_inspect_result_queue=self.cancel_inspect_result_queue,
|
|
109
|
-
)
|
|
110
|
-
https_handler.handle_https_connection(client_socket, first_line)
|
|
111
|
-
else:
|
|
112
|
-
http_handler = self._create_handler(HttpHandler)
|
|
113
|
-
http_handler.handle_http_request(client_socket, request)
|
|
@@ -202,15 +202,24 @@ class HttpHandler:
|
|
|
202
202
|
server_port = parsed_url.port or (
|
|
203
203
|
443 if parsed_url.scheme == "https" else 80
|
|
204
204
|
)
|
|
205
|
+
|
|
206
|
+
try:
|
|
207
|
+
ip_address = socket.gethostbyname(server_host)
|
|
208
|
+
except socket.gaierror:
|
|
209
|
+
ip_address = server_host
|
|
210
|
+
|
|
205
211
|
thread_id = threading.get_ident()
|
|
206
212
|
|
|
207
213
|
if thread_id in self.active_connections:
|
|
208
|
-
self.active_connections[thread_id]
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
+
self.active_connections[thread_id].update(
|
|
215
|
+
{
|
|
216
|
+
"target_ip": ip_address,
|
|
217
|
+
"target_domain": server_host,
|
|
218
|
+
"target_port": server_port,
|
|
219
|
+
"bytes_sent": 0,
|
|
220
|
+
"bytes_received": 0,
|
|
221
|
+
}
|
|
222
|
+
)
|
|
214
223
|
|
|
215
224
|
try:
|
|
216
225
|
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
@@ -206,6 +206,21 @@ class HttpsHandler:
|
|
|
206
206
|
if self._is_blocked(f"{server_host}{path}"):
|
|
207
207
|
return None, full_url, True
|
|
208
208
|
|
|
209
|
+
if not self.logger_config.no_logging_access:
|
|
210
|
+
method, domain_port, protocol = first_line.split(" ")
|
|
211
|
+
domain, port = domain_port.split(":")
|
|
212
|
+
self.logger_config.access_logger.info(
|
|
213
|
+
"",
|
|
214
|
+
extra={
|
|
215
|
+
"ip_src": ssl_client_socket.getpeername()[0],
|
|
216
|
+
"url": full_url,
|
|
217
|
+
"method": method,
|
|
218
|
+
"domain": server_host,
|
|
219
|
+
"port": port,
|
|
220
|
+
"protocol": protocol,
|
|
221
|
+
},
|
|
222
|
+
)
|
|
223
|
+
|
|
209
224
|
return first_request, full_url, False
|
|
210
225
|
except Exception as e:
|
|
211
226
|
self.logger_config.error_logger.error(f"SSL request processing error : {e}")
|
|
@@ -231,10 +246,13 @@ class HttpsHandler:
|
|
|
231
246
|
not_inspect = self._should_skip_inspection(server_host)
|
|
232
247
|
|
|
233
248
|
thread_id = threading.get_ident()
|
|
234
|
-
self.active_connections[thread_id]
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
249
|
+
self.active_connections[thread_id].update(
|
|
250
|
+
{
|
|
251
|
+
"target_domain": server_host,
|
|
252
|
+
"bytes_sent": 0,
|
|
253
|
+
"bytes_received": 0,
|
|
254
|
+
}
|
|
255
|
+
)
|
|
238
256
|
|
|
239
257
|
if self.ssl_config.ssl_inspect and not not_inspect:
|
|
240
258
|
try:
|
|
@@ -317,13 +335,13 @@ class HttpsHandler:
|
|
|
317
335
|
)
|
|
318
336
|
|
|
319
337
|
if not self.logger_config.no_logging_access:
|
|
320
|
-
|
|
338
|
+
method, _, protocol = first_line.split(" ")
|
|
321
339
|
self.logger_config.access_logger.info(
|
|
322
340
|
"",
|
|
323
341
|
extra={
|
|
324
342
|
"ip_src": client_ip,
|
|
325
343
|
"url": target,
|
|
326
|
-
"method":
|
|
344
|
+
"method": method,
|
|
327
345
|
"domain": server_host,
|
|
328
346
|
"port": server_port,
|
|
329
347
|
"protocol": protocol,
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"""
|
|
2
|
+
pyproxy.monitoring.__init__.py
|
|
3
|
+
|
|
4
|
+
Provides a monitoring system for the ProxyServer, exposing information about
|
|
5
|
+
processes, threads, active connections, and subprocesses. Implements an HTTP
|
|
6
|
+
server using Flask to provide monitoring endpoints.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import logging
|
|
10
|
+
from flask import Flask
|
|
11
|
+
from .monitor import ProxyMonitor
|
|
12
|
+
from .auth import create_basic_auth
|
|
13
|
+
from .routes import register_routes
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def start_flask_server(proxy_server, flask_port, flask_pass, debug) -> None:
|
|
17
|
+
"""
|
|
18
|
+
Launches a Flask HTTP server to monitor the ProxyServer.
|
|
19
|
+
|
|
20
|
+
The server exposes endpoints that provide status information about
|
|
21
|
+
the proxy server, including process details, thread information,
|
|
22
|
+
subprocess statuses, and active connections.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
proxy_server (ProxyServer): The ProxyServer instance to monitor.
|
|
26
|
+
flask_port (int): The port number on which the Flask server will listen.
|
|
27
|
+
flask_pass (str): The password used for basic HTTP authentication.
|
|
28
|
+
debug (bool): Flag to enable or disable Flask debug mode.
|
|
29
|
+
"""
|
|
30
|
+
auth = create_basic_auth(flask_pass)
|
|
31
|
+
|
|
32
|
+
app = Flask(__name__, static_folder="static")
|
|
33
|
+
if not debug:
|
|
34
|
+
log = logging.getLogger("werkzeug")
|
|
35
|
+
log.setLevel(logging.ERROR)
|
|
36
|
+
|
|
37
|
+
register_routes(app, auth, proxy_server, ProxyMonitor)
|
|
38
|
+
app.run(host="0.0.0.0", port=flask_port) # nosec
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"""
|
|
2
|
+
pyproxy.monitoring.auth.py
|
|
3
|
+
|
|
4
|
+
Provides HTTP Basic Authentication setup for the monitoring Flask server,
|
|
5
|
+
using a single hardcoded user 'admin' with a hashed password.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from flask_httpauth import HTTPBasicAuth
|
|
9
|
+
from werkzeug.security import check_password_hash, generate_password_hash
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def create_basic_auth(password: str):
|
|
13
|
+
"""
|
|
14
|
+
Creates and configures an HTTPBasicAuth instance with a single user.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
password (str): The password for the 'admin' user.
|
|
18
|
+
|
|
19
|
+
Returns:
|
|
20
|
+
HTTPBasicAuth: Configured HTTPBasicAuth instance for use in Flask.
|
|
21
|
+
"""
|
|
22
|
+
auth = HTTPBasicAuth()
|
|
23
|
+
users = {"admin": generate_password_hash(password)}
|
|
24
|
+
|
|
25
|
+
@auth.verify_password
|
|
26
|
+
def verify_password(username, passwd):
|
|
27
|
+
if username in users and check_password_hash(users.get(username), passwd):
|
|
28
|
+
return username
|
|
29
|
+
return None
|
|
30
|
+
|
|
31
|
+
return auth
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
"""
|
|
2
|
+
pyproxy.monitoring.monitor
|
|
3
|
+
|
|
4
|
+
This module defines the ProxyMonitor class, which provides monitoring capabilities
|
|
5
|
+
for the ProxyServer. It collects and exposes real-time information about the
|
|
6
|
+
main process, threads, subprocesses, and active client connections using `psutil`,
|
|
7
|
+
`threading`, and `multiprocessing` libraries.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import os
|
|
11
|
+
import threading
|
|
12
|
+
import multiprocessing
|
|
13
|
+
from datetime import datetime
|
|
14
|
+
from typing import List, Dict, Union
|
|
15
|
+
import psutil
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ProxyMonitor:
|
|
19
|
+
"""
|
|
20
|
+
Monitors the status of the ProxyServer, including details about
|
|
21
|
+
the main process, threads, subprocesses, and active client connections.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
proxy_server (ProxyServer): The instance of the ProxyServer to monitor.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
def __init__(self, proxy_server):
|
|
28
|
+
self.proxy_server = proxy_server
|
|
29
|
+
|
|
30
|
+
def get_process_info(
|
|
31
|
+
self,
|
|
32
|
+
) -> Dict[str, Union[int, str, List[Dict[str, Union[int, str]]]]]:
|
|
33
|
+
"""
|
|
34
|
+
Retrieves overall process information for the ProxyServer,
|
|
35
|
+
including the PID, name, status, and details about threads,
|
|
36
|
+
subprocesses, and active connections.
|
|
37
|
+
|
|
38
|
+
Returns:
|
|
39
|
+
dict: A dictionary containing the process information.
|
|
40
|
+
"""
|
|
41
|
+
process_info = {
|
|
42
|
+
"pid": os.getpid(),
|
|
43
|
+
"name": "ProxyServer",
|
|
44
|
+
"status": "running",
|
|
45
|
+
"start_time": datetime.fromtimestamp(
|
|
46
|
+
psutil.Process(os.getpid()).create_time()
|
|
47
|
+
).strftime("%Y-%m-%d %H:%M:%S"),
|
|
48
|
+
"threads": self.get_threads_info(),
|
|
49
|
+
"subprocesses": self.get_subprocesses_info(),
|
|
50
|
+
"active_connections": self.get_active_connections(),
|
|
51
|
+
}
|
|
52
|
+
return process_info
|
|
53
|
+
|
|
54
|
+
def get_threads_info(self) -> List[Dict[str, Union[int, str]]]:
|
|
55
|
+
"""
|
|
56
|
+
Retrieves information about the threads running in the ProxyServer.
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
list: A list of dictionaries, each containing information
|
|
60
|
+
about a thread.
|
|
61
|
+
"""
|
|
62
|
+
threads_info = []
|
|
63
|
+
for thread in threading.enumerate():
|
|
64
|
+
threads_info.append(
|
|
65
|
+
{
|
|
66
|
+
"thread_id": thread.ident,
|
|
67
|
+
"name": thread.name,
|
|
68
|
+
"status": self.get_thread_status(thread),
|
|
69
|
+
}
|
|
70
|
+
)
|
|
71
|
+
return threads_info
|
|
72
|
+
|
|
73
|
+
def get_thread_status(self, thread: threading.Thread) -> str:
|
|
74
|
+
"""
|
|
75
|
+
Gets the status of a given thread.
|
|
76
|
+
|
|
77
|
+
Args:
|
|
78
|
+
thread (threading.Thread): The thread whose status is to be retrieved.
|
|
79
|
+
|
|
80
|
+
Returns:
|
|
81
|
+
str: The status of the thread ('running', 'terminated', or 'unknown').
|
|
82
|
+
"""
|
|
83
|
+
try:
|
|
84
|
+
if thread.is_alive():
|
|
85
|
+
return "running"
|
|
86
|
+
return "terminated"
|
|
87
|
+
except AttributeError:
|
|
88
|
+
return "unknown"
|
|
89
|
+
|
|
90
|
+
def get_subprocesses_info(
|
|
91
|
+
self,
|
|
92
|
+
) -> Dict[str, Dict[str, Union[str, List[Dict[str, Union[int, str]]]]]]:
|
|
93
|
+
"""
|
|
94
|
+
Retrieves the status of the ProxyServer's subprocesses, including
|
|
95
|
+
filtering, shortcuts, cancel inspection, and custom header processes.
|
|
96
|
+
|
|
97
|
+
Returns:
|
|
98
|
+
dict: A dictionary containing subprocess statuses.
|
|
99
|
+
"""
|
|
100
|
+
subprocesses_info = {}
|
|
101
|
+
|
|
102
|
+
subprocesses = {
|
|
103
|
+
"filter": self.proxy_server.filter_proc,
|
|
104
|
+
"shortcuts": self.proxy_server.shortcuts_proc,
|
|
105
|
+
"cancel_inspect": self.proxy_server.cancel_inspect_proc,
|
|
106
|
+
"custom_header": self.proxy_server.custom_header_proc,
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
for name, process in subprocesses.items():
|
|
110
|
+
if process is not None and process.is_alive():
|
|
111
|
+
subprocesses_info[name] = self.get_subprocess_status(process, name)
|
|
112
|
+
return subprocesses_info
|
|
113
|
+
|
|
114
|
+
def get_subprocess_status(
|
|
115
|
+
self, process: multiprocessing.Process, name: str
|
|
116
|
+
) -> Dict[str, Union[str, None, List[Dict[str, Union[int, str]]]]]:
|
|
117
|
+
"""
|
|
118
|
+
Retrieves the status of a subprocess.
|
|
119
|
+
|
|
120
|
+
Args:
|
|
121
|
+
process (multiprocessing.Process): The subprocess to check.
|
|
122
|
+
name (str): The name of the subprocess.
|
|
123
|
+
|
|
124
|
+
Returns:
|
|
125
|
+
dict: A dictionary containing the subprocess status.
|
|
126
|
+
"""
|
|
127
|
+
if process is None:
|
|
128
|
+
return {"status": "not started", "name": name, "threads": []}
|
|
129
|
+
try:
|
|
130
|
+
status = "running" if process.is_alive() else "terminated"
|
|
131
|
+
threads_info = self.get_subprocess_threads_info(process)
|
|
132
|
+
except AttributeError:
|
|
133
|
+
status = "terminated"
|
|
134
|
+
threads_info = []
|
|
135
|
+
return {
|
|
136
|
+
"pid": process.pid if hasattr(process, "pid") else None,
|
|
137
|
+
"status": status,
|
|
138
|
+
"name": name,
|
|
139
|
+
"threads": threads_info,
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
def get_subprocess_threads_info(
|
|
143
|
+
self, process: multiprocessing.Process
|
|
144
|
+
) -> List[Dict[str, Union[int, str]]]:
|
|
145
|
+
"""
|
|
146
|
+
Retrieves the threads associated with a subprocess.
|
|
147
|
+
|
|
148
|
+
Args:
|
|
149
|
+
process (multiprocessing.Process): The subprocess to check.
|
|
150
|
+
|
|
151
|
+
Returns:
|
|
152
|
+
list: A list of dictionaries containing thread information.
|
|
153
|
+
"""
|
|
154
|
+
threads_info = []
|
|
155
|
+
try:
|
|
156
|
+
for proc_thread in psutil.Process(process.pid).threads():
|
|
157
|
+
threads_info.append(
|
|
158
|
+
{
|
|
159
|
+
"thread_id": proc_thread.id,
|
|
160
|
+
"name": f"Thread-{proc_thread.id}",
|
|
161
|
+
"status": self.get_thread_status_by_pid(proc_thread.id),
|
|
162
|
+
}
|
|
163
|
+
)
|
|
164
|
+
except (psutil.NoSuchProcess, psutil.AccessDenied):
|
|
165
|
+
pass
|
|
166
|
+
return threads_info
|
|
167
|
+
|
|
168
|
+
def get_thread_status_by_pid(self, thread_id: int) -> str:
|
|
169
|
+
"""
|
|
170
|
+
Attempts to retrieve the status of a thread by its PID.
|
|
171
|
+
|
|
172
|
+
Args:
|
|
173
|
+
thread_id (int): The thread's ID.
|
|
174
|
+
|
|
175
|
+
Returns:
|
|
176
|
+
str: The status of the thread ('running' or 'terminated').
|
|
177
|
+
"""
|
|
178
|
+
try:
|
|
179
|
+
process = psutil.Process(thread_id)
|
|
180
|
+
if process.is_running():
|
|
181
|
+
return "running"
|
|
182
|
+
return "terminated"
|
|
183
|
+
except psutil.NoSuchProcess:
|
|
184
|
+
return "terminated"
|
|
185
|
+
|
|
186
|
+
def get_active_connections(self) -> List[Dict[str, Union[int, Dict]]]:
|
|
187
|
+
"""
|
|
188
|
+
Retrieves information about the active client connections to the ProxyServer.
|
|
189
|
+
|
|
190
|
+
Returns:
|
|
191
|
+
list: A list of dictionaries containing information about active connections.
|
|
192
|
+
"""
|
|
193
|
+
return [
|
|
194
|
+
{"thread_id": thread_id, **conn}
|
|
195
|
+
for thread_id, conn in self.proxy_server.active_connections.items()
|
|
196
|
+
]
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
"""
|
|
2
|
+
pyproxy.monitoring.routes.py
|
|
3
|
+
|
|
4
|
+
Defines and registers monitoring-related routes for the Flask application,
|
|
5
|
+
including endpoints for system information, configuration, and a secured
|
|
6
|
+
HTML-based index page.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from flask import jsonify, render_template, request
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def register_routes(app, auth, proxy_server, ProxyMonitor):
|
|
13
|
+
"""
|
|
14
|
+
Registers the monitoring routes to the Flask app, secured with HTTP Basic Auth.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
app (Flask): The Flask application instance.
|
|
18
|
+
auth (HTTPBasicAuth): The HTTP Basic Auth instance used to secure routes.
|
|
19
|
+
proxy_server (ProxyServer): The running ProxyServer instance to monitor.
|
|
20
|
+
ProxyMonitor (class): The monitoring class used to gather runtime information.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
@app.route("/")
|
|
24
|
+
@auth.login_required
|
|
25
|
+
def index():
|
|
26
|
+
"""
|
|
27
|
+
Serves the main index HTML page for the monitoring dashboard.
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
Response: Rendered HTML page.
|
|
31
|
+
"""
|
|
32
|
+
return render_template("index.html")
|
|
33
|
+
|
|
34
|
+
@app.route("/api/status", methods=["GET"])
|
|
35
|
+
@auth.login_required
|
|
36
|
+
def monitoring():
|
|
37
|
+
"""
|
|
38
|
+
Provides real-time monitoring information about the ProxyServer,
|
|
39
|
+
including process, thread, and connection status.
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
Response: JSON object containing monitoring data.
|
|
43
|
+
"""
|
|
44
|
+
monitor = ProxyMonitor(proxy_server)
|
|
45
|
+
return jsonify(monitor.get_process_info())
|
|
46
|
+
|
|
47
|
+
@app.route("/api/settings", methods=["GET"])
|
|
48
|
+
@auth.login_required
|
|
49
|
+
def config():
|
|
50
|
+
"""
|
|
51
|
+
Returns the current configuration of the ProxyServer.
|
|
52
|
+
|
|
53
|
+
The configuration includes:
|
|
54
|
+
- Host and port
|
|
55
|
+
- Debug mode
|
|
56
|
+
- 403 HTML page usage
|
|
57
|
+
- Logger configuration (if present)
|
|
58
|
+
- Filter configuration (if present)
|
|
59
|
+
- SSL configuration (if present)
|
|
60
|
+
- Flask monitoring port
|
|
61
|
+
|
|
62
|
+
Returns:
|
|
63
|
+
Response: JSON object containing configuration data.
|
|
64
|
+
"""
|
|
65
|
+
config_data = {
|
|
66
|
+
"host": proxy_server.host_port[0],
|
|
67
|
+
"port": proxy_server.host_port[1],
|
|
68
|
+
"debug": proxy_server.debug,
|
|
69
|
+
"html_403": proxy_server.html_403,
|
|
70
|
+
"logger_config": (
|
|
71
|
+
proxy_server.logger_config.to_dict()
|
|
72
|
+
if proxy_server.logger_config
|
|
73
|
+
else None
|
|
74
|
+
),
|
|
75
|
+
"filter_config": (
|
|
76
|
+
proxy_server.filter_config.to_dict()
|
|
77
|
+
if proxy_server.filter_config
|
|
78
|
+
else None
|
|
79
|
+
),
|
|
80
|
+
"ssl_config": (
|
|
81
|
+
proxy_server.ssl_config.to_dict() if proxy_server.ssl_config else None
|
|
82
|
+
),
|
|
83
|
+
"flask_port": proxy_server.monitoring_config.flask_port,
|
|
84
|
+
}
|
|
85
|
+
return jsonify(config_data)
|
|
86
|
+
|
|
87
|
+
@app.route("/api/filtering", methods=["GET", "POST", "DELETE"])
|
|
88
|
+
@auth.login_required
|
|
89
|
+
def blocked():
|
|
90
|
+
"""
|
|
91
|
+
Manages the blocked sites and URLs list.
|
|
92
|
+
|
|
93
|
+
GET:
|
|
94
|
+
Reads and returns the current blocked domains and URLs from the corresponding files.
|
|
95
|
+
Returns:
|
|
96
|
+
Response: JSON object with 'blocked_sites' and 'blocked_url' lists.
|
|
97
|
+
|
|
98
|
+
POST:
|
|
99
|
+
Adds a new domain or URL to the blocked lists based on
|
|
100
|
+
'type' and 'value' from JSON input.
|
|
101
|
+
Request JSON:
|
|
102
|
+
{
|
|
103
|
+
"type": "domain" | "url",
|
|
104
|
+
"value": "<value_to_block>"
|
|
105
|
+
}
|
|
106
|
+
Returns:
|
|
107
|
+
201: Successfully added.
|
|
108
|
+
400: Invalid input.
|
|
109
|
+
409: Value already blocked.
|
|
110
|
+
|
|
111
|
+
DELETE:
|
|
112
|
+
Removes a domain or URL from the blocked lists based on
|
|
113
|
+
'type' and 'value' from JSON input.
|
|
114
|
+
Request JSON:
|
|
115
|
+
{
|
|
116
|
+
"type": "domain" | "url",
|
|
117
|
+
"value": "<value_to_unblock>"
|
|
118
|
+
}
|
|
119
|
+
Returns:
|
|
120
|
+
200: Successfully removed.
|
|
121
|
+
400: Invalid input.
|
|
122
|
+
404: Value not found.
|
|
123
|
+
500: Server error.
|
|
124
|
+
"""
|
|
125
|
+
if request.method == "GET":
|
|
126
|
+
blocked_sites_content = ""
|
|
127
|
+
blocked_url_content = ""
|
|
128
|
+
|
|
129
|
+
with open(
|
|
130
|
+
proxy_server.filter_config.blocked_sites, "r", encoding="utf-8"
|
|
131
|
+
) as f:
|
|
132
|
+
blocked_sites_content = [line.strip() for line in f if line.strip()]
|
|
133
|
+
with open(
|
|
134
|
+
proxy_server.filter_config.blocked_url, "r", encoding="utf-8"
|
|
135
|
+
) as f:
|
|
136
|
+
blocked_url_content = [line.strip() for line in f if line.strip()]
|
|
137
|
+
|
|
138
|
+
blocked_data = {
|
|
139
|
+
"blocked_sites": blocked_sites_content,
|
|
140
|
+
"blocked_url": blocked_url_content,
|
|
141
|
+
}
|
|
142
|
+
return jsonify(blocked_data)
|
|
143
|
+
|
|
144
|
+
elif request.method == "POST":
|
|
145
|
+
data = request.get_json()
|
|
146
|
+
typ = data.get("type")
|
|
147
|
+
val = data.get("value", "").strip()
|
|
148
|
+
if not val or typ not in ["domain", "url"]:
|
|
149
|
+
return jsonify({"error": "Invalid input"}), 400
|
|
150
|
+
|
|
151
|
+
filename = (
|
|
152
|
+
proxy_server.filter_config.blocked_sites
|
|
153
|
+
if typ == "domain"
|
|
154
|
+
else proxy_server.filter_config.blocked_url
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
with open(filename, "r+", encoding="utf-8") as f:
|
|
158
|
+
lines = [line.strip() for line in f if line.strip()]
|
|
159
|
+
if val in lines:
|
|
160
|
+
return jsonify({"message": "Already blocked"}), 409
|
|
161
|
+
lines.append(val)
|
|
162
|
+
f.seek(0)
|
|
163
|
+
f.truncate()
|
|
164
|
+
f.write("\n".join(lines) + "\n")
|
|
165
|
+
return jsonify({"message": "Added successfully"}), 201
|
|
166
|
+
|
|
167
|
+
elif request.method == "DELETE":
|
|
168
|
+
data = request.get_json()
|
|
169
|
+
if not data or "type" not in data or "value" not in data:
|
|
170
|
+
return (
|
|
171
|
+
jsonify({"error": "Missing 'type' or 'value' in request body"}),
|
|
172
|
+
400,
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
block_type = data["type"]
|
|
176
|
+
value = data["value"].strip()
|
|
177
|
+
|
|
178
|
+
if block_type == "domain":
|
|
179
|
+
filepath = proxy_server.filter_config.blocked_sites
|
|
180
|
+
elif block_type == "url":
|
|
181
|
+
filepath = proxy_server.filter_config.blocked_url
|
|
182
|
+
else:
|
|
183
|
+
return (
|
|
184
|
+
jsonify({"error": "Invalid type, must be 'domain' or 'url'"}),
|
|
185
|
+
400,
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
try:
|
|
189
|
+
with open(filepath, "r", encoding="utf-8") as f:
|
|
190
|
+
lines = [line.strip() for line in f if line.strip()]
|
|
191
|
+
|
|
192
|
+
if value not in lines:
|
|
193
|
+
return (
|
|
194
|
+
jsonify({"error": f"{value} not found in {block_type} list"}),
|
|
195
|
+
404,
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
lines = [line for line in lines if line != value]
|
|
199
|
+
|
|
200
|
+
with open(filepath, "w", encoding="utf-8") as f:
|
|
201
|
+
for line in lines:
|
|
202
|
+
f.write(line + "\n")
|
|
203
|
+
|
|
204
|
+
return (
|
|
205
|
+
jsonify(
|
|
206
|
+
{"message": f"{block_type} '{value}' removed successfully"}
|
|
207
|
+
),
|
|
208
|
+
200,
|
|
209
|
+
)
|
|
210
|
+
except Exception as e:
|
|
211
|
+
return jsonify({"error": f"Server error: {str(e)}"}), 500
|
|
@@ -27,7 +27,7 @@ if not __slim__:
|
|
|
27
27
|
if not __slim__:
|
|
28
28
|
from pyproxy.modules.custom_header import custom_header_process
|
|
29
29
|
if not __slim__:
|
|
30
|
-
from pyproxy.monitoring
|
|
30
|
+
from pyproxy.monitoring import start_flask_server
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
class ProxyServer:
|
|
@@ -21,7 +21,9 @@ pyproxy/modules/custom_header.py
|
|
|
21
21
|
pyproxy/modules/filter.py
|
|
22
22
|
pyproxy/modules/shortcuts.py
|
|
23
23
|
pyproxy/monitoring/__init__.py
|
|
24
|
-
pyproxy/monitoring/
|
|
24
|
+
pyproxy/monitoring/auth.py
|
|
25
|
+
pyproxy/monitoring/monitor.py
|
|
26
|
+
pyproxy/monitoring/routes.py
|
|
25
27
|
pyproxy/utils/__init__.py
|
|
26
28
|
pyproxy/utils/args.py
|
|
27
29
|
pyproxy/utils/config.py
|
|
@@ -1,279 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
pyproxy.monitoring.web.py
|
|
3
|
-
|
|
4
|
-
This module defines a monitoring system for the ProxyServer that provides
|
|
5
|
-
information about the server's processes, threads, active connections, and
|
|
6
|
-
subprocesses. It includes an HTTP server implemented with Flask to expose
|
|
7
|
-
monitoring endpoints for the proxy server.
|
|
8
|
-
"""
|
|
9
|
-
|
|
10
|
-
import os
|
|
11
|
-
import threading
|
|
12
|
-
import multiprocessing
|
|
13
|
-
import logging
|
|
14
|
-
from datetime import datetime
|
|
15
|
-
from typing import List, Dict, Union
|
|
16
|
-
from flask import Flask, jsonify, render_template
|
|
17
|
-
from flask_httpauth import HTTPBasicAuth
|
|
18
|
-
from werkzeug.security import check_password_hash, generate_password_hash
|
|
19
|
-
import psutil
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
def start_flask_server(proxy_server, flask_port, flask_pass, debug) -> None:
|
|
23
|
-
"""
|
|
24
|
-
Starts the Flask server for monitoring the ProxyServer. It creates and
|
|
25
|
-
runs an HTTP server that exposes the proxy server's status, including
|
|
26
|
-
process and thread details, subprocess statuses, and active connections.
|
|
27
|
-
|
|
28
|
-
Args:
|
|
29
|
-
proxy_server (ProxyServer): The ProxyServer instance to monitor.
|
|
30
|
-
|
|
31
|
-
The server will expose two routes:
|
|
32
|
-
- '/' : Renders a simple index page.
|
|
33
|
-
- '/monitoring' : Returns a JSON response with the monitoring data.
|
|
34
|
-
"""
|
|
35
|
-
|
|
36
|
-
class ProxyMonitor:
|
|
37
|
-
"""
|
|
38
|
-
Monitors the status of the ProxyServer, including process, thread,
|
|
39
|
-
and subprocess information, as well as active client connections.
|
|
40
|
-
|
|
41
|
-
Args:
|
|
42
|
-
proxy_server (ProxyServer): The ProxyServer instance to monitor.
|
|
43
|
-
"""
|
|
44
|
-
|
|
45
|
-
def __init__(self, proxy_server):
|
|
46
|
-
self.proxy_server = proxy_server
|
|
47
|
-
|
|
48
|
-
def get_process_info(
|
|
49
|
-
self,
|
|
50
|
-
) -> Dict[str, Union[int, str, List[Dict[str, Union[int, str]]]]]:
|
|
51
|
-
"""
|
|
52
|
-
Retrieves overall process information for the ProxyServer,
|
|
53
|
-
including the PID, name, status, and details about threads,
|
|
54
|
-
subprocesses, and active connections.
|
|
55
|
-
|
|
56
|
-
Returns:
|
|
57
|
-
dict: A dictionary containing the process information.
|
|
58
|
-
"""
|
|
59
|
-
process_info = {
|
|
60
|
-
"pid": os.getpid(),
|
|
61
|
-
"name": "ProxyServer",
|
|
62
|
-
"status": "running",
|
|
63
|
-
"start_time": datetime.fromtimestamp(
|
|
64
|
-
psutil.Process(os.getpid()).create_time()
|
|
65
|
-
).strftime("%Y-%m-%d %H:%M:%S"),
|
|
66
|
-
"threads": self.get_threads_info(),
|
|
67
|
-
"subprocesses": self.get_subprocesses_info(),
|
|
68
|
-
"active_connections": self.get_active_connections(),
|
|
69
|
-
}
|
|
70
|
-
return process_info
|
|
71
|
-
|
|
72
|
-
def get_threads_info(self) -> List[Dict[str, Union[int, str]]]:
|
|
73
|
-
"""
|
|
74
|
-
Retrieves information about the threads running in the ProxyServer.
|
|
75
|
-
|
|
76
|
-
Returns:
|
|
77
|
-
list: A list of dictionaries, each containing information
|
|
78
|
-
about a thread.
|
|
79
|
-
"""
|
|
80
|
-
threads_info = []
|
|
81
|
-
for thread in threading.enumerate():
|
|
82
|
-
threads_info.append(
|
|
83
|
-
{
|
|
84
|
-
"thread_id": thread.ident,
|
|
85
|
-
"name": thread.name,
|
|
86
|
-
"status": self.get_thread_status(thread),
|
|
87
|
-
}
|
|
88
|
-
)
|
|
89
|
-
return threads_info
|
|
90
|
-
|
|
91
|
-
def get_thread_status(self, thread: threading.Thread) -> str:
|
|
92
|
-
"""
|
|
93
|
-
Gets the status of a given thread.
|
|
94
|
-
|
|
95
|
-
Args:
|
|
96
|
-
thread (threading.Thread): The thread whose status is to be retrieved.
|
|
97
|
-
|
|
98
|
-
Returns:
|
|
99
|
-
str: The status of the thread ('running', 'terminated', or 'unknown').
|
|
100
|
-
"""
|
|
101
|
-
try:
|
|
102
|
-
if thread.is_alive():
|
|
103
|
-
return "running"
|
|
104
|
-
return "terminated"
|
|
105
|
-
except AttributeError:
|
|
106
|
-
return "unknown"
|
|
107
|
-
|
|
108
|
-
def get_subprocesses_info(
|
|
109
|
-
self,
|
|
110
|
-
) -> Dict[str, Dict[str, Union[str, List[Dict[str, Union[int, str]]]]]]:
|
|
111
|
-
"""
|
|
112
|
-
Retrieves the status of the ProxyServer's subprocesses, including
|
|
113
|
-
filtering, shortcuts, cancel inspection, and custom header processes.
|
|
114
|
-
|
|
115
|
-
Returns:
|
|
116
|
-
dict: A dictionary containing subprocess statuses.
|
|
117
|
-
"""
|
|
118
|
-
subprocesses_info = {}
|
|
119
|
-
|
|
120
|
-
subprocesses = {
|
|
121
|
-
"filter": self.proxy_server.filter_proc,
|
|
122
|
-
"shortcuts": self.proxy_server.shortcuts_proc,
|
|
123
|
-
"cancel_inspect": self.proxy_server.cancel_inspect_proc,
|
|
124
|
-
"custom_header": self.proxy_server.custom_header_proc,
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
for name, process in subprocesses.items():
|
|
128
|
-
if process is not None and process.is_alive():
|
|
129
|
-
subprocesses_info[name] = self.get_subprocess_status(process, name)
|
|
130
|
-
return subprocesses_info
|
|
131
|
-
|
|
132
|
-
def get_subprocess_status(
|
|
133
|
-
self, process: multiprocessing.Process, name: str
|
|
134
|
-
) -> Dict[str, Union[str, None, List[Dict[str, Union[int, str]]]]]:
|
|
135
|
-
"""
|
|
136
|
-
Retrieves the status of a subprocess.
|
|
137
|
-
|
|
138
|
-
Args:
|
|
139
|
-
process (multiprocessing.Process): The subprocess to check.
|
|
140
|
-
name (str): The name of the subprocess.
|
|
141
|
-
|
|
142
|
-
Returns:
|
|
143
|
-
dict: A dictionary containing the subprocess status.
|
|
144
|
-
"""
|
|
145
|
-
if process is None:
|
|
146
|
-
return {"status": "not started", "name": name, "threads": []}
|
|
147
|
-
try:
|
|
148
|
-
status = "running" if process.is_alive() else "terminated"
|
|
149
|
-
threads_info = self.get_subprocess_threads_info(process)
|
|
150
|
-
except AttributeError:
|
|
151
|
-
status = "terminated"
|
|
152
|
-
threads_info = []
|
|
153
|
-
return {
|
|
154
|
-
"pid": process.pid if hasattr(process, "pid") else None,
|
|
155
|
-
"status": status,
|
|
156
|
-
"name": name,
|
|
157
|
-
"threads": threads_info,
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
def get_subprocess_threads_info(
|
|
161
|
-
self, process: multiprocessing.Process
|
|
162
|
-
) -> List[Dict[str, Union[int, str]]]:
|
|
163
|
-
"""
|
|
164
|
-
Retrieves the threads associated with a subprocess.
|
|
165
|
-
|
|
166
|
-
Args:
|
|
167
|
-
process (multiprocessing.Process): The subprocess to check.
|
|
168
|
-
|
|
169
|
-
Returns:
|
|
170
|
-
list: A list of dictionaries containing thread information.
|
|
171
|
-
"""
|
|
172
|
-
threads_info = []
|
|
173
|
-
try:
|
|
174
|
-
for proc_thread in psutil.Process(process.pid).threads():
|
|
175
|
-
threads_info.append(
|
|
176
|
-
{
|
|
177
|
-
"thread_id": proc_thread.id,
|
|
178
|
-
"name": f"Thread-{proc_thread.id}",
|
|
179
|
-
"status": self.get_thread_status_by_pid(proc_thread.id),
|
|
180
|
-
}
|
|
181
|
-
)
|
|
182
|
-
except (psutil.NoSuchProcess, psutil.AccessDenied):
|
|
183
|
-
pass
|
|
184
|
-
return threads_info
|
|
185
|
-
|
|
186
|
-
def get_thread_status_by_pid(self, thread_id: int) -> str:
|
|
187
|
-
"""
|
|
188
|
-
Attempts to retrieve the status of a thread by its PID.
|
|
189
|
-
|
|
190
|
-
Args:
|
|
191
|
-
thread_id (int): The thread's ID.
|
|
192
|
-
|
|
193
|
-
Returns:
|
|
194
|
-
str: The status of the thread ('running' or 'terminated').
|
|
195
|
-
"""
|
|
196
|
-
try:
|
|
197
|
-
process = psutil.Process(thread_id)
|
|
198
|
-
if process.is_running():
|
|
199
|
-
return "running"
|
|
200
|
-
return "terminated"
|
|
201
|
-
except psutil.NoSuchProcess:
|
|
202
|
-
return "terminated"
|
|
203
|
-
|
|
204
|
-
def get_active_connections(self) -> List[Dict[str, Union[int, Dict]]]:
|
|
205
|
-
"""
|
|
206
|
-
Retrieves information about the active client connections to the ProxyServer.
|
|
207
|
-
|
|
208
|
-
Returns:
|
|
209
|
-
list: A list of dictionaries containing information about active connections.
|
|
210
|
-
"""
|
|
211
|
-
return [
|
|
212
|
-
{"thread_id": thread_id, **conn}
|
|
213
|
-
for thread_id, conn in self.proxy_server.active_connections.items()
|
|
214
|
-
]
|
|
215
|
-
|
|
216
|
-
auth = HTTPBasicAuth()
|
|
217
|
-
|
|
218
|
-
users = {"admin": generate_password_hash(flask_pass)}
|
|
219
|
-
|
|
220
|
-
@auth.verify_password
|
|
221
|
-
def verify_password(username, password):
|
|
222
|
-
if username in users and check_password_hash(users.get(username), password):
|
|
223
|
-
return username
|
|
224
|
-
return None
|
|
225
|
-
|
|
226
|
-
app = Flask(__name__, static_folder="static")
|
|
227
|
-
if not debug:
|
|
228
|
-
log = logging.getLogger("werkzeug")
|
|
229
|
-
log.setLevel(logging.ERROR)
|
|
230
|
-
|
|
231
|
-
@app.route("/")
|
|
232
|
-
@auth.login_required
|
|
233
|
-
def index():
|
|
234
|
-
"""
|
|
235
|
-
Renders the index page for the Flask application.
|
|
236
|
-
|
|
237
|
-
Returns:
|
|
238
|
-
str: The rendered HTML content of the index page.
|
|
239
|
-
"""
|
|
240
|
-
return render_template("index.html")
|
|
241
|
-
|
|
242
|
-
@app.route("/monitoring", methods=["GET"])
|
|
243
|
-
@auth.login_required
|
|
244
|
-
def monitoring():
|
|
245
|
-
"""
|
|
246
|
-
Returns the monitoring data for the ProxyServer in JSON format.
|
|
247
|
-
|
|
248
|
-
Returns:
|
|
249
|
-
Response: A JSON response containing the server's process information.
|
|
250
|
-
"""
|
|
251
|
-
monitor = ProxyMonitor(proxy_server)
|
|
252
|
-
return jsonify(monitor.get_process_info())
|
|
253
|
-
|
|
254
|
-
@app.route("/config", methods=["GET"])
|
|
255
|
-
@auth.login_required
|
|
256
|
-
def config():
|
|
257
|
-
config_data = {
|
|
258
|
-
"host": proxy_server.host_port[0],
|
|
259
|
-
"port": proxy_server.host_port[1],
|
|
260
|
-
"debug": proxy_server.debug,
|
|
261
|
-
"html_403": proxy_server.html_403,
|
|
262
|
-
"logger_config": (
|
|
263
|
-
proxy_server.logger_config.to_dict()
|
|
264
|
-
if proxy_server.logger_config
|
|
265
|
-
else None
|
|
266
|
-
),
|
|
267
|
-
"filter_config": (
|
|
268
|
-
proxy_server.filter_config.to_dict()
|
|
269
|
-
if proxy_server.filter_config
|
|
270
|
-
else None
|
|
271
|
-
),
|
|
272
|
-
"ssl_config": (
|
|
273
|
-
proxy_server.ssl_config.to_dict() if proxy_server.ssl_config else None
|
|
274
|
-
),
|
|
275
|
-
"flask_port": proxy_server.monitoring_config.flask_port,
|
|
276
|
-
}
|
|
277
|
-
return jsonify(config_data)
|
|
278
|
-
|
|
279
|
-
app.run(host="0.0.0.0", port=flask_port) # nosec
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|