lanscape 1.3.4__py3-none-any.whl → 1.3.5a2__py3-none-any.whl
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.
- lanscape/libraries/app_scope.py +0 -1
- lanscape/libraries/decorators.py +10 -5
- lanscape/libraries/errors.py +10 -0
- lanscape/libraries/ip_parser.py +73 -1
- lanscape/libraries/logger.py +29 -1
- lanscape/libraries/mac_lookup.py +5 -0
- lanscape/libraries/net_tools.py +139 -68
- lanscape/libraries/port_manager.py +83 -0
- lanscape/libraries/runtime_args.py +12 -0
- lanscape/libraries/scan_config.py +148 -5
- lanscape/libraries/service_scan.py +3 -3
- lanscape/libraries/subnet_scan.py +104 -16
- lanscape/libraries/version_manager.py +50 -7
- lanscape/libraries/web_browser.py +136 -68
- lanscape/resources/mac_addresses/convert_csv.py +13 -2
- lanscape/resources/ports/convert_csv.py +13 -3
- lanscape/ui/__init__.py +0 -0
- lanscape/ui/app.py +32 -36
- lanscape/ui/blueprints/__init__.py +4 -1
- lanscape/ui/blueprints/api/__init__.py +2 -0
- lanscape/ui/blueprints/api/port.py +46 -0
- lanscape/ui/blueprints/api/scan.py +58 -10
- lanscape/ui/blueprints/api/tools.py +17 -1
- lanscape/ui/blueprints/web/__init__.py +4 -0
- lanscape/ui/blueprints/web/routes.py +52 -5
- lanscape/ui/main.py +17 -7
- lanscape/ui/shutdown_handler.py +57 -0
- lanscape/ui/static/css/style.css +94 -20
- lanscape/ui/static/js/main.js +25 -48
- lanscape/ui/static/js/scan-config.js +107 -0
- lanscape/ui/static/lanscape.webmanifest +4 -3
- lanscape/ui/templates/main.html +39 -36
- lanscape/ui/templates/scan/config.html +168 -0
- {lanscape-1.3.4.dist-info → lanscape-1.3.5a2.dist-info}/METADATA +1 -1
- lanscape-1.3.5a2.dist-info/RECORD +73 -0
- lanscape-1.3.4.dist-info/RECORD +0 -69
- {lanscape-1.3.4.dist-info → lanscape-1.3.5a2.dist-info}/WHEEL +0 -0
- {lanscape-1.3.4.dist-info → lanscape-1.3.5a2.dist-info}/licenses/LICENSE +0 -0
- {lanscape-1.3.4.dist-info → lanscape-1.3.5a2.dist-info}/top_level.txt +0 -0
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Web blueprint routes for the LANscape application.
|
|
3
|
+
Handles UI views including the main dashboard, scan results, error display, and exports.
|
|
4
|
+
"""
|
|
1
5
|
from flask import render_template, request, redirect
|
|
2
6
|
from lanscape.ui.blueprints.web import web_bp
|
|
3
7
|
from lanscape.libraries.net_tools import (
|
|
@@ -12,16 +16,20 @@ from lanscape.ui.blueprints import scan_manager, log
|
|
|
12
16
|
|
|
13
17
|
@web_bp.route('/', methods=['GET'])
|
|
14
18
|
def index():
|
|
19
|
+
"""
|
|
20
|
+
Render the main application interface.
|
|
21
|
+
|
|
22
|
+
Displays the primary network subnet selection interface and existing scan results.
|
|
23
|
+
If a scan_id is provided, it loads the configuration from that scan.
|
|
24
|
+
"""
|
|
15
25
|
subnets = get_all_network_subnets()
|
|
16
26
|
subnet = smart_select_primary_subnet(subnets)
|
|
17
27
|
|
|
18
28
|
port_list = 'medium'
|
|
19
|
-
parallelism = 1
|
|
20
29
|
if scan_id := request.args.get('scan_id'):
|
|
21
30
|
if scan := scan_manager.get_scan(scan_id):
|
|
22
31
|
subnet = scan.cfg.subnet
|
|
23
32
|
port_list = scan.cfg.port_list
|
|
24
|
-
parallelism = scan.cfg.t_multiplier
|
|
25
33
|
|
|
26
34
|
else:
|
|
27
35
|
log.debug(f'Redirecting, scan {scan_id} doesnt exist in memory')
|
|
@@ -30,7 +38,6 @@ def index():
|
|
|
30
38
|
'main.html',
|
|
31
39
|
subnet=subnet,
|
|
32
40
|
port_list=port_list,
|
|
33
|
-
parallelism=parallelism,
|
|
34
41
|
alternate_subnets=subnets
|
|
35
42
|
)
|
|
36
43
|
|
|
@@ -38,16 +45,35 @@ def index():
|
|
|
38
45
|
@web_bp.route('/scan/<scan_id>', methods=['GET'])
|
|
39
46
|
@web_bp.route('/scan/<scan_id>/<section>', methods=['GET'])
|
|
40
47
|
def render_scan(scan_id, section='all'):
|
|
48
|
+
"""
|
|
49
|
+
Render a specific scan result.
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
scan_id: Unique identifier for the scan
|
|
53
|
+
section: Section of the scan results to display (default: 'all')
|
|
54
|
+
|
|
55
|
+
Returns:
|
|
56
|
+
Rendered scan template or redirect to home if scan not found
|
|
57
|
+
"""
|
|
41
58
|
if scanner := scan_manager.get_scan(scan_id):
|
|
42
59
|
data = scanner.results.export()
|
|
43
|
-
|
|
44
|
-
return render_template('scan.html', data=data, section=section, filter=
|
|
60
|
+
filter_text = request.args.get('filter')
|
|
61
|
+
return render_template('scan.html', data=data, section=section, filter=filter_text)
|
|
45
62
|
log.debug(f'Redirecting, scan {scan_id} doesnt exist in memory')
|
|
46
63
|
return redirect('/')
|
|
47
64
|
|
|
48
65
|
|
|
49
66
|
@web_bp.route('/errors/<scan_id>')
|
|
50
67
|
def view_errors(scan_id):
|
|
68
|
+
"""
|
|
69
|
+
Display errors that occurred during a scan.
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
scan_id: Unique identifier for the scan
|
|
73
|
+
|
|
74
|
+
Returns:
|
|
75
|
+
Rendered error template or redirect to home if scan not found
|
|
76
|
+
"""
|
|
51
77
|
if scanner := scan_manager.get_scan(scan_id):
|
|
52
78
|
data = scanner.results.export()
|
|
53
79
|
return render_template('scan/scan-error.html', data=data)
|
|
@@ -57,6 +83,15 @@ def view_errors(scan_id):
|
|
|
57
83
|
|
|
58
84
|
@web_bp.route('/export/<scan_id>')
|
|
59
85
|
def export_scan(scan_id):
|
|
86
|
+
"""
|
|
87
|
+
Provide an exportable view of scan results.
|
|
88
|
+
|
|
89
|
+
Args:
|
|
90
|
+
scan_id: Unique identifier for the scan
|
|
91
|
+
|
|
92
|
+
Returns:
|
|
93
|
+
Rendered export template or redirect to home if scan not found
|
|
94
|
+
"""
|
|
60
95
|
if scanner := scan_manager.get_scan(scan_id):
|
|
61
96
|
export_json = scanner.results.export(str)
|
|
62
97
|
return render_template(
|
|
@@ -70,9 +105,21 @@ def export_scan(scan_id):
|
|
|
70
105
|
|
|
71
106
|
@web_bp.route('/shutdown-ui')
|
|
72
107
|
def shutdown_ui():
|
|
108
|
+
"""
|
|
109
|
+
Display the shutdown confirmation page.
|
|
110
|
+
|
|
111
|
+
Returns:
|
|
112
|
+
Rendered shutdown template
|
|
113
|
+
"""
|
|
73
114
|
return render_template('shutdown.html')
|
|
74
115
|
|
|
75
116
|
|
|
76
117
|
@web_bp.route('/info')
|
|
77
118
|
def app_info():
|
|
119
|
+
"""
|
|
120
|
+
Display application information and version details.
|
|
121
|
+
|
|
122
|
+
Returns:
|
|
123
|
+
Rendered info template
|
|
124
|
+
"""
|
|
78
125
|
return render_template('info.html')
|
lanscape/ui/main.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
"""Main entry point for the LANscape application when running as a module."""
|
|
2
2
|
import socket
|
|
3
3
|
|
|
4
4
|
|
|
@@ -7,8 +7,10 @@ import time
|
|
|
7
7
|
import logging
|
|
8
8
|
import traceback
|
|
9
9
|
import os
|
|
10
|
+
import requests
|
|
11
|
+
|
|
10
12
|
from lanscape.libraries.logger import configure_logging
|
|
11
|
-
from lanscape.libraries.runtime_args import parse_args
|
|
13
|
+
from lanscape.libraries.runtime_args import parse_args
|
|
12
14
|
from lanscape.libraries.web_browser import open_webapp
|
|
13
15
|
from lanscape.libraries.net_tools import is_arp_supported
|
|
14
16
|
from lanscape.libraries.version_manager import get_installed_version, is_update_available
|
|
@@ -25,6 +27,7 @@ IS_FLASK_RELOAD = os.environ.get("WERKZEUG_RUN_MAIN")
|
|
|
25
27
|
|
|
26
28
|
|
|
27
29
|
def main():
|
|
30
|
+
"""core entry point for running lanscape as a module."""
|
|
28
31
|
try:
|
|
29
32
|
_main()
|
|
30
33
|
except KeyboardInterrupt:
|
|
@@ -47,10 +50,15 @@ def _main():
|
|
|
47
50
|
args.port = get_valid_port(args.port)
|
|
48
51
|
|
|
49
52
|
if not is_arp_supported():
|
|
50
|
-
|
|
53
|
+
warn = (
|
|
54
|
+
'ARP is not supported, device discovery is degraded. ',
|
|
55
|
+
'For more information, see the help guide: ',
|
|
56
|
+
'https://github.com/mdennis281/LANscape/blob/main/support/arp-issues.md'
|
|
57
|
+
)
|
|
58
|
+
log.warning(''.join(warn))
|
|
51
59
|
|
|
52
60
|
try:
|
|
53
|
-
start_webserver_ui(
|
|
61
|
+
start_webserver_ui()
|
|
54
62
|
log.info('Exiting...')
|
|
55
63
|
except Exception as e:
|
|
56
64
|
# showing error in debug only because this is handled gracefully
|
|
@@ -60,6 +68,7 @@ def _main():
|
|
|
60
68
|
|
|
61
69
|
|
|
62
70
|
def try_check_update():
|
|
71
|
+
"""Check for updates and log if available."""
|
|
63
72
|
try:
|
|
64
73
|
if is_update_available():
|
|
65
74
|
log.info('An update is available!')
|
|
@@ -86,7 +95,8 @@ def open_browser(url: str, wait=2) -> bool:
|
|
|
86
95
|
return False
|
|
87
96
|
|
|
88
97
|
|
|
89
|
-
def start_webserver_ui(
|
|
98
|
+
def start_webserver_ui():
|
|
99
|
+
"""Start the web server and open the UI in a browser."""
|
|
90
100
|
uri = f'http://127.0.0.1:{args.port}'
|
|
91
101
|
|
|
92
102
|
# running reloader requires flask to run in main thread
|
|
@@ -128,9 +138,9 @@ def get_valid_port(port: int):
|
|
|
128
138
|
|
|
129
139
|
|
|
130
140
|
def terminate():
|
|
131
|
-
|
|
141
|
+
"""send a request to the shutdown flask"""
|
|
132
142
|
log.info('Attempting flask shutdown')
|
|
133
|
-
requests.get(f'http://127.0.0.1:{args.port}/shutdown?type=core')
|
|
143
|
+
requests.get(f'http://127.0.0.1:{args.port}/shutdown?type=core', timeout=2)
|
|
134
144
|
|
|
135
145
|
|
|
136
146
|
if __name__ == "__main__":
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"""Logic for handling shutdown requests in a Flask application."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
import os
|
|
5
|
+
from flask import request
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
from lanscape.libraries.runtime_args import parse_args
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
log = logging.getLogger('shutdown_handler')
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class FlaskShutdownHandler:
|
|
15
|
+
"""Handles shutdown requests for the Flask application.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
def __init__(self, app):
|
|
19
|
+
self.app = app
|
|
20
|
+
self._exiting = False
|
|
21
|
+
|
|
22
|
+
def register_endpoints(self):
|
|
23
|
+
"""Register shutdown endpoints to the Flask app."""
|
|
24
|
+
|
|
25
|
+
@self.app.route('/shutdown', methods=['POST', 'GET'])
|
|
26
|
+
def shutdown():
|
|
27
|
+
req_type = request.args.get('type')
|
|
28
|
+
self.shutdown_request(req_type)
|
|
29
|
+
return "Done"
|
|
30
|
+
|
|
31
|
+
@self.app.teardown_request
|
|
32
|
+
def teardown(_):
|
|
33
|
+
self.exit_if_requested()
|
|
34
|
+
|
|
35
|
+
def shutdown_request(self, req_type: str):
|
|
36
|
+
"""Handles shutdown requests based on the type of request.
|
|
37
|
+
Args:
|
|
38
|
+
req_type (str): The type of shutdown request.
|
|
39
|
+
"""
|
|
40
|
+
if req_type == 'browser-close':
|
|
41
|
+
args = parse_args()
|
|
42
|
+
if args.persistent:
|
|
43
|
+
log.info('Detected browser close, not exiting flask.')
|
|
44
|
+
return "Ignored"
|
|
45
|
+
log.info(
|
|
46
|
+
'Web browser closed, terminating flask. (disable with --persistent)')
|
|
47
|
+
elif req_type == 'core':
|
|
48
|
+
log.info('Core requested exit, terminating flask.')
|
|
49
|
+
else:
|
|
50
|
+
log.info('Received external exit request. Terminating flask.')
|
|
51
|
+
self._exiting = True
|
|
52
|
+
return "Done"
|
|
53
|
+
|
|
54
|
+
def exit_if_requested(self):
|
|
55
|
+
"""Exits the application if a shutdown request has been made."""
|
|
56
|
+
if self._exiting:
|
|
57
|
+
os._exit(0)
|
lanscape/ui/static/css/style.css
CHANGED
|
@@ -117,6 +117,7 @@ hr {
|
|
|
117
117
|
}
|
|
118
118
|
h1.title{
|
|
119
119
|
cursor: pointer;
|
|
120
|
+
margin: 0;
|
|
120
121
|
}
|
|
121
122
|
.title span {
|
|
122
123
|
color: var(--text-accent-color);
|
|
@@ -163,18 +164,21 @@ details {
|
|
|
163
164
|
border-radius: 5px !important; /* override bootstrap stuff */
|
|
164
165
|
padding-right: 34px;
|
|
165
166
|
margin-right: -34px;
|
|
167
|
+
margin-left: -41px;
|
|
168
|
+
padding-left: calc(41px + 5px);
|
|
166
169
|
}
|
|
167
170
|
|
|
168
171
|
|
|
169
172
|
#scan-form .input-group button {
|
|
170
173
|
background-color: var(--primary-bg-accent);
|
|
171
174
|
border: 0;
|
|
172
|
-
|
|
175
|
+
|
|
173
176
|
transition: all .2s ease-in-out;
|
|
174
177
|
height: 40px;
|
|
175
|
-
border-radius: 0 5px 5px 0;
|
|
176
178
|
margin-top: 1px;
|
|
177
179
|
transform: translateX(.5px);
|
|
180
|
+
z-index: 3;
|
|
181
|
+
margin-left: 0;
|
|
178
182
|
}
|
|
179
183
|
#scan-form .input-group button:hover {
|
|
180
184
|
background-color: var(--primary-bg-accent-hover);
|
|
@@ -182,6 +186,15 @@ details {
|
|
|
182
186
|
#scan-form .input-group button:active {
|
|
183
187
|
background-color: var(--primary-accent);
|
|
184
188
|
}
|
|
189
|
+
#scan-form .input-group button.start {
|
|
190
|
+
border-radius: 5px 0 0 5px;
|
|
191
|
+
border-right: 1px var(--border-color) solid;
|
|
192
|
+
width: 40px; /* added because it looks gross on icon load */
|
|
193
|
+
}
|
|
194
|
+
#scan-form .input-group button.end {
|
|
195
|
+
border-radius: 0 5px 5px 0;
|
|
196
|
+
border-left: 1px var(--border-color) solid;
|
|
197
|
+
}
|
|
185
198
|
|
|
186
199
|
.label-container {
|
|
187
200
|
display: flex;
|
|
@@ -256,8 +269,69 @@ details {
|
|
|
256
269
|
}
|
|
257
270
|
}
|
|
258
271
|
|
|
272
|
+
#advanced-modal {
|
|
273
|
+
--bs-modal-width: 750px;
|
|
274
|
+
}
|
|
275
|
+
#advanced-modal .modal-content {
|
|
276
|
+
background-color: var(--primary-bg);
|
|
277
|
+
}
|
|
278
|
+
#advanced-modal .descriptor {
|
|
279
|
+
align-content: end;
|
|
280
|
+
text-align: center;
|
|
281
|
+
color: var(--text-placeholder);
|
|
282
|
+
padding-bottom: 10px;
|
|
283
|
+
}
|
|
284
|
+
#advanced-modal .col-2-percent {
|
|
285
|
+
flex: 0 0 auto;
|
|
286
|
+
width: 2%;
|
|
287
|
+
}
|
|
288
|
+
#advanced-modal label {
|
|
289
|
+
font-size: 12px;
|
|
290
|
+
}
|
|
291
|
+
#advanced-modal .form-check {
|
|
292
|
+
width: fit-content;
|
|
293
|
+
}
|
|
294
|
+
#advanced-modal h6 {
|
|
295
|
+
color: var(--primary-accent);
|
|
296
|
+
}
|
|
297
|
+
#advanced-modal .config-option {
|
|
298
|
+
background-color: var(--primary-bg-accent);
|
|
299
|
+
border: 1px solid var(--border-color);
|
|
300
|
+
border-radius: 5px;
|
|
301
|
+
cursor: pointer;
|
|
302
|
+
text-align: center;
|
|
303
|
+
margin: 0 5px;
|
|
304
|
+
transition: all .2s ease-in-out;
|
|
305
|
+
}
|
|
259
306
|
|
|
260
|
-
|
|
307
|
+
#advanced-modal .config-option.active {
|
|
308
|
+
border-color: var(--primary-accent);
|
|
309
|
+
box-shadow: 0 0 5px var(--primary-accent);
|
|
310
|
+
background-color: var(--primary-bg);
|
|
311
|
+
}
|
|
312
|
+
#advanced-modal .config-option:hover {
|
|
313
|
+
background-color: var(--primary-bg);
|
|
314
|
+
box-shadow: 0 0 5px var(--primary-accent);
|
|
315
|
+
}
|
|
316
|
+
#advanced-modal .config-option.active:hover {
|
|
317
|
+
background-color: var(--primary-bg-accent);
|
|
318
|
+
box-shadow: 0 0 5px var(--primary-accent);
|
|
319
|
+
}
|
|
320
|
+
#advanced-modal .config-option h5 {
|
|
321
|
+
flex-wrap: wrap;
|
|
322
|
+
}
|
|
323
|
+
#advanced-modal .config-option h5 span {
|
|
324
|
+
display: block; /* "waaaah span shouldnt be block" bite me. */
|
|
325
|
+
width: 100%;
|
|
326
|
+
padding: 5px;
|
|
327
|
+
font-size: 2em;
|
|
328
|
+
}
|
|
329
|
+
#advanced-modal .config-option p {
|
|
330
|
+
font-size: 0.8em;
|
|
331
|
+
color: var(--text-placeholder);
|
|
332
|
+
margin: 0;
|
|
333
|
+
padding: 5px;
|
|
334
|
+
}
|
|
261
335
|
|
|
262
336
|
|
|
263
337
|
/* Card Styles */
|
|
@@ -286,7 +360,7 @@ form {
|
|
|
286
360
|
flex-grow: 1;
|
|
287
361
|
display: flex;
|
|
288
362
|
flex-direction: column;
|
|
289
|
-
margin-bottom:
|
|
363
|
+
margin-bottom: 5px;
|
|
290
364
|
}
|
|
291
365
|
|
|
292
366
|
label {
|
|
@@ -310,6 +384,12 @@ input[type="text"]:focus, select:focus, .form-control:focus {
|
|
|
310
384
|
border-color: var(--primary-accent);
|
|
311
385
|
outline: none;
|
|
312
386
|
}
|
|
387
|
+
input[type="text"]:read-only, .form-control:read-only {
|
|
388
|
+
background-color: var(--secondary-bg);
|
|
389
|
+
color: var(--text-placeholder);
|
|
390
|
+
border-color: var(--secondary-accent);
|
|
391
|
+
outline: none;
|
|
392
|
+
}
|
|
313
393
|
|
|
314
394
|
input::placeholder {
|
|
315
395
|
color: var(--text-placeholder) !important;
|
|
@@ -326,6 +406,7 @@ button {
|
|
|
326
406
|
#scan-form #scan-submit {
|
|
327
407
|
border: none;
|
|
328
408
|
padding: 10px 20px;
|
|
409
|
+
margin-top: 15px;
|
|
329
410
|
}
|
|
330
411
|
|
|
331
412
|
/* Button Styling */
|
|
@@ -378,20 +459,6 @@ input[type="range"] {
|
|
|
378
459
|
margin: 5px 0;
|
|
379
460
|
}
|
|
380
461
|
|
|
381
|
-
input[type="range"]::-webkit-slider-thumb,
|
|
382
|
-
input[type="range"]::-moz-range-thumb {
|
|
383
|
-
-webkit-appearance: none;
|
|
384
|
-
appearance: none;
|
|
385
|
-
width: 16px;
|
|
386
|
-
height: 16px;
|
|
387
|
-
border-radius: 50%;
|
|
388
|
-
background: var(--primary-accent);
|
|
389
|
-
cursor: pointer;
|
|
390
|
-
}
|
|
391
|
-
#parallelism-value span {
|
|
392
|
-
color: var(--text-danger-color);
|
|
393
|
-
font-weight: 500;
|
|
394
|
-
}
|
|
395
462
|
.port-list-wrapper {
|
|
396
463
|
position: relative;
|
|
397
464
|
display: inline-block;
|
|
@@ -400,12 +467,13 @@ input[type="range"]::-moz-range-thumb {
|
|
|
400
467
|
|
|
401
468
|
.port-list {
|
|
402
469
|
position: relative;
|
|
403
|
-
background-color: var(--
|
|
470
|
+
background-color: var(--secondary-bg);
|
|
404
471
|
border: 1px solid var(--border-color);
|
|
405
472
|
color: var(--text-color);
|
|
406
473
|
padding: 10px;
|
|
407
474
|
cursor: pointer;
|
|
408
475
|
width: 100%;
|
|
476
|
+
height: 42px;
|
|
409
477
|
user-select: none;
|
|
410
478
|
appearance: none; /* Hide default arrow */
|
|
411
479
|
transition: all .2s ease-in-out;
|
|
@@ -419,7 +487,7 @@ input[type="range"]::-moz-range-thumb {
|
|
|
419
487
|
.port-list-wrapper::after {
|
|
420
488
|
content: '▼';
|
|
421
489
|
position: absolute;
|
|
422
|
-
top:
|
|
490
|
+
top: 10px;
|
|
423
491
|
right: 10px;
|
|
424
492
|
pointer-events: none;
|
|
425
493
|
color: var(--text-color);
|
|
@@ -451,6 +519,12 @@ input[type="range"]::-moz-range-thumb {
|
|
|
451
519
|
color: var(--text-color);
|
|
452
520
|
}
|
|
453
521
|
|
|
522
|
+
|
|
523
|
+
|
|
524
|
+
.text-color {
|
|
525
|
+
color: var(--text-color) !important;
|
|
526
|
+
}
|
|
527
|
+
|
|
454
528
|
.text-secondary {
|
|
455
529
|
color: var(--secondary-accent) !important;
|
|
456
530
|
}
|
lanscape/ui/static/js/main.js
CHANGED
|
@@ -2,21 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
$(document).ready(function() {
|
|
4
4
|
// Load port lists into the dropdown
|
|
5
|
-
getPortLists();
|
|
6
|
-
|
|
7
|
-
$('#parallelism').on('input', function() {
|
|
8
|
-
const val = $('#parallelism').val();
|
|
9
|
-
let ans = val;
|
|
10
|
-
|
|
11
|
-
if (parseFloat(val) > 1) {
|
|
12
|
-
ans += ' <span>Warning: Increased parallelism may have inaccurate results<span>'
|
|
13
|
-
}
|
|
14
|
-
$('#parallelism-value').html(ans);
|
|
15
|
-
});
|
|
16
5
|
const scanId = getActiveScanId();
|
|
17
6
|
if (scanId) {
|
|
18
7
|
showScan(scanId);
|
|
19
8
|
}
|
|
9
|
+
|
|
10
|
+
// this prevents the browser from
|
|
11
|
+
// triggering the shutdown beacon
|
|
12
|
+
// when user clicks the logo
|
|
13
|
+
setUrlParam('loaded', 'true')
|
|
20
14
|
|
|
21
15
|
|
|
22
16
|
// Handle form submission
|
|
@@ -39,18 +33,19 @@ $(document).ready(function() {
|
|
|
39
33
|
$('#ip-table-frame').attr('src', newSrc);
|
|
40
34
|
});
|
|
41
35
|
|
|
36
|
+
$('#settings-btn').on('click', function() {
|
|
37
|
+
$('#advanced-modal').modal('show');
|
|
38
|
+
});
|
|
39
|
+
|
|
42
40
|
});
|
|
43
41
|
|
|
44
42
|
function submitNewScan() {
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
port_list: $('#port-list').text(),
|
|
48
|
-
parallelism: $('#parallelism').val()
|
|
49
|
-
};
|
|
43
|
+
const config = getScanConfig();
|
|
44
|
+
config.subnet = $('#subnet').val();
|
|
50
45
|
$.ajax('/api/scan', {
|
|
51
|
-
data
|
|
52
|
-
contentType
|
|
53
|
-
type
|
|
46
|
+
data: JSON.stringify(config),
|
|
47
|
+
contentType: 'application/json',
|
|
48
|
+
type: 'POST',
|
|
54
49
|
success: function(response) {
|
|
55
50
|
if (response.status === 'running') {
|
|
56
51
|
showScan(response.scan_id);
|
|
@@ -75,37 +70,9 @@ function showScan(scanId) {
|
|
|
75
70
|
//$('#overview-frame').attr('src', '/scan/' + scanId + '/overview');
|
|
76
71
|
$('#ip-table-frame').attr('src', '/scan/' + scanId + '/table');
|
|
77
72
|
|
|
78
|
-
|
|
79
|
-
const url = new URL(window.location.href);
|
|
80
|
-
url.searchParams.set('scan_id', scanId);
|
|
81
|
-
// set url to the new url
|
|
82
|
-
window.history.pushState({}, '', url);
|
|
73
|
+
setUrlParam('scan_id', scanId);
|
|
83
74
|
}
|
|
84
75
|
|
|
85
|
-
function getPortLists() {
|
|
86
|
-
$.get('/api/port/list', function(data) {
|
|
87
|
-
const customSelect = $('#port-list');
|
|
88
|
-
const customSelectDropdown = $('#port-list-dropdown');
|
|
89
|
-
customSelectDropdown.empty();
|
|
90
|
-
|
|
91
|
-
// Populate the dropdown with the options
|
|
92
|
-
data.forEach(function(portList) {
|
|
93
|
-
customSelectDropdown.append('<div>' + portList + '</div>');
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
// Handle dropdown click
|
|
97
|
-
customSelect.on('click', function() {
|
|
98
|
-
customSelectDropdown.toggleClass('open');
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
// Handle option selection
|
|
102
|
-
customSelectDropdown.on('click', 'div', function() {
|
|
103
|
-
const selectedOption = $(this).text();
|
|
104
|
-
customSelect.text(selectedOption);
|
|
105
|
-
customSelectDropdown.removeClass('open');
|
|
106
|
-
});
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
76
|
|
|
110
77
|
$(document).on('click', function(event) {
|
|
111
78
|
if (!$(event.target).closest('.port-list-wrapper').length) {
|
|
@@ -234,6 +201,16 @@ $('#ip-table-frame').on('load', function() {
|
|
|
234
201
|
observeIframeContent(this); // Start observing for dynamic changes
|
|
235
202
|
});
|
|
236
203
|
|
|
204
|
+
function setUrlParam(param, value) {
|
|
205
|
+
const url = new URL(window.location.href);
|
|
206
|
+
if (value === null || value === undefined) {
|
|
207
|
+
url.searchParams.delete(param);
|
|
208
|
+
} else {
|
|
209
|
+
url.searchParams.set(param, value);
|
|
210
|
+
}
|
|
211
|
+
window.history.pushState({}, '', url);
|
|
212
|
+
}
|
|
213
|
+
|
|
237
214
|
|
|
238
215
|
|
|
239
216
|
$(window).on('resize', function() {
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
let defaultScanConfigs = {};
|
|
2
|
+
let activeConfigName = 'balanced';
|
|
3
|
+
|
|
4
|
+
$(document).ready(function() {
|
|
5
|
+
// load port lists
|
|
6
|
+
getPortLists(function() {
|
|
7
|
+
// THEN get scan config defaults
|
|
8
|
+
getScanDefaults(function() {
|
|
9
|
+
// THEN set the default scan config
|
|
10
|
+
setScanConfig('balanced');
|
|
11
|
+
})
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
$('#t_cnt_port_scan, #t_cnt_port_test').on('input', updatePortTotals);
|
|
15
|
+
$('#ping_attempts, #ping_ping_count').on('input', updatePingTotals);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
function getScanDefaults(callback=null) {
|
|
19
|
+
$.getJSON('/api/tools/config/defaults', (data) => {
|
|
20
|
+
defaultScanConfigs = data;
|
|
21
|
+
if (callback) callback();
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function setScanConfig(configName) {
|
|
26
|
+
const config = defaultScanConfigs[configName];
|
|
27
|
+
if (!config) return;
|
|
28
|
+
activeConfigName = configName;
|
|
29
|
+
|
|
30
|
+
// highlight selected preset
|
|
31
|
+
$('.config-option').removeClass('active');
|
|
32
|
+
$(`#config-${configName}`).addClass('active');
|
|
33
|
+
|
|
34
|
+
// basic settings
|
|
35
|
+
$('#port_list').val(config.port_list);
|
|
36
|
+
$('#t_multiplier').val(config.t_multiplier);
|
|
37
|
+
$('#t_cnt_port_scan').val(config.t_cnt_port_scan);
|
|
38
|
+
$('#t_cnt_port_test').val(config.t_cnt_port_test);
|
|
39
|
+
$('#t_cnt_isalive').val(config.t_cnt_isalive);
|
|
40
|
+
$('#task_scan_ports').prop('checked', config.task_scan_ports);
|
|
41
|
+
$('#task_scan_port_services').prop('checked', config.task_scan_port_services);
|
|
42
|
+
$('#lookup_type').val(config.lookup_type);
|
|
43
|
+
|
|
44
|
+
// ping config
|
|
45
|
+
$('#ping_attempts').val(config.ping_config.attempts);
|
|
46
|
+
$('#ping_ping_count').val(config.ping_config.ping_count);
|
|
47
|
+
$('#ping_retry_delay').val(config.ping_config.retry_delay);
|
|
48
|
+
$('#ping_timeout').val(config.ping_config.timeout);
|
|
49
|
+
|
|
50
|
+
// arp config
|
|
51
|
+
$('#arp_attempts').val(config.arp_config.attempts);
|
|
52
|
+
$('#arp_timeout').val(config.arp_config.timeout);
|
|
53
|
+
|
|
54
|
+
updatePortTotals();
|
|
55
|
+
updatePingTotals();
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function getScanConfig() {
|
|
59
|
+
return {
|
|
60
|
+
port_list: $('#port_list').val(),
|
|
61
|
+
t_cnt_port_scan: parseInt($('#t_cnt_port_scan').val()),
|
|
62
|
+
t_cnt_port_test: parseInt($('#t_cnt_port_test').val()),
|
|
63
|
+
t_cnt_isalive: parseInt($('#t_cnt_isalive').val()),
|
|
64
|
+
task_scan_ports: $('#task_scan_ports').is(':checked'),
|
|
65
|
+
task_scan_port_services: $('#task_scan_port_services').is(':checked'),
|
|
66
|
+
lookup_type: $('#lookup_type').val(),
|
|
67
|
+
ping_config: {
|
|
68
|
+
attempts: parseInt($('#ping_attempts').val()),
|
|
69
|
+
ping_count: parseInt($('#ping_ping_count').val()),
|
|
70
|
+
retry_delay: parseFloat($('#ping_retry_delay').val()),
|
|
71
|
+
timeout: parseFloat($('#ping_timeout').val())
|
|
72
|
+
},
|
|
73
|
+
arp_config: {
|
|
74
|
+
attempts: parseInt($('#arp_attempts').val()),
|
|
75
|
+
timeout: parseFloat($('#arp_timeout').val())
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function getPortLists(callback=null) {
|
|
81
|
+
$.get('/api/port/list', function(data) {
|
|
82
|
+
const customSelectDropdown = $('#port_list');
|
|
83
|
+
customSelectDropdown.empty();
|
|
84
|
+
|
|
85
|
+
// Populate the dropdown with the options
|
|
86
|
+
data.forEach(function(portList) {
|
|
87
|
+
customSelectDropdown.append('<option>' + portList + '</option>');
|
|
88
|
+
});
|
|
89
|
+
if (callback) callback();
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function updatePortTotals() {
|
|
94
|
+
const scan = parseInt($('#t_cnt_port_scan').val()) || 0;
|
|
95
|
+
const test = parseInt($('#t_cnt_port_test').val()) || 0;
|
|
96
|
+
$('#total-port-tests').val(scan * test);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function updatePingTotals() {
|
|
100
|
+
const attempts = parseInt($('#ping_attempts').val()) || 0;
|
|
101
|
+
const count = parseInt($('#ping_ping_count').val()) || 0;
|
|
102
|
+
$('#total-ping-attempts').val(attempts * count);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// expose functions globally
|
|
106
|
+
window.setScanConfig = setScanConfig;
|
|
107
|
+
window.getScanConfig = getScanConfig;
|