lanscape 1.3.1a8__py3-none-any.whl → 1.3.2a6__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.
Potentially problematic release.
This version of lanscape might be problematic. Click here for more details.
- lanscape/__init__.py +4 -1
- lanscape/__main__.py +4 -1
- lanscape/ui/static/css/style.css +1 -1
- lanscape/ui/templates/core/scripts.html +1 -1
- lanscape/ui/templates/info.html +1 -1
- lanscape/ui/templates/main.html +6 -4
- {lanscape-1.3.1a8.dist-info → lanscape-1.3.2a6.dist-info}/METADATA +4 -3
- lanscape-1.3.2a6.dist-info/RECORD +43 -0
- lanscape/libraries/app_scope.py +0 -70
- lanscape/libraries/decorators.py +0 -75
- lanscape/libraries/errors.py +0 -29
- lanscape/libraries/ip_parser.py +0 -65
- lanscape/libraries/logger.py +0 -42
- lanscape/libraries/mac_lookup.py +0 -69
- lanscape/libraries/net_tools.py +0 -480
- lanscape/libraries/port_manager.py +0 -59
- lanscape/libraries/runtime_args.py +0 -44
- lanscape/libraries/service_scan.py +0 -51
- lanscape/libraries/subnet_scan.py +0 -373
- lanscape/libraries/version_manager.py +0 -54
- lanscape/libraries/web_browser.py +0 -141
- lanscape/resources/mac_addresses/convert_csv.py +0 -27
- lanscape/resources/ports/convert_csv.py +0 -27
- lanscape/tests/__init__.py +0 -3
- lanscape/tests/_helpers.py +0 -15
- lanscape/tests/test_api.py +0 -194
- lanscape/tests/test_env.py +0 -30
- lanscape/tests/test_library.py +0 -53
- lanscape/ui/app.py +0 -122
- lanscape/ui/blueprints/__init__.py +0 -7
- lanscape/ui/blueprints/api/__init__.py +0 -5
- lanscape/ui/blueprints/api/port.py +0 -27
- lanscape/ui/blueprints/api/scan.py +0 -69
- lanscape/ui/blueprints/api/tools.py +0 -30
- lanscape/ui/blueprints/web/__init__.py +0 -5
- lanscape/ui/blueprints/web/routes.py +0 -74
- lanscape/ui/main.py +0 -138
- lanscape-1.3.1a8.dist-info/RECORD +0 -72
- {lanscape-1.3.1a8.dist-info → lanscape-1.3.2a6.dist-info}/WHEEL +0 -0
- {lanscape-1.3.1a8.dist-info → lanscape-1.3.2a6.dist-info}/licenses/LICENSE +0 -0
- {lanscape-1.3.1a8.dist-info → lanscape-1.3.2a6.dist-info}/top_level.txt +0 -0
lanscape/tests/test_api.py
DELETED
|
@@ -1,194 +0,0 @@
|
|
|
1
|
-
import unittest
|
|
2
|
-
import json
|
|
3
|
-
from ..ui.app import app
|
|
4
|
-
from ..libraries.net_tools import get_network_subnet
|
|
5
|
-
from ._helpers import right_size_subnet
|
|
6
|
-
import time
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
class ApiTestCase(unittest.TestCase):
|
|
11
|
-
app = app.test_client()
|
|
12
|
-
|
|
13
|
-
def test_port_lifecycle(self):
|
|
14
|
-
# Delete the new port list if it exists
|
|
15
|
-
self.app.delete('/api/port/list/test_port_list_lifecycle')
|
|
16
|
-
|
|
17
|
-
# Get the list of port lists
|
|
18
|
-
response = self.app.get('/api/port/list')
|
|
19
|
-
self.assertEqual(response.status_code, 200)
|
|
20
|
-
port_list_start = json.loads(response.data)
|
|
21
|
-
|
|
22
|
-
# Create a new port list
|
|
23
|
-
new_port_list = {'80': 'http', '443': 'https'}
|
|
24
|
-
response = self.app.post('/api/port/list/test_port_list_lifecycle', json=new_port_list)
|
|
25
|
-
self.assertEqual(response.status_code, 200)
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
# Get the list of port lists again
|
|
29
|
-
response = self.app.get('/api/port/list')
|
|
30
|
-
self.assertEqual(response.status_code, 200)
|
|
31
|
-
port_list_new = json.loads(response.data)
|
|
32
|
-
# Verify that the new port list is in the list of port lists
|
|
33
|
-
self.assertEqual(len(port_list_new), len(port_list_start) + 1)
|
|
34
|
-
|
|
35
|
-
# Get the new port list
|
|
36
|
-
response = self.app.get('/api/port/list/test_port_list_lifecycle')
|
|
37
|
-
self.assertEqual(response.status_code, 200)
|
|
38
|
-
port_list = json.loads(response.data)
|
|
39
|
-
self.assertEqual(port_list, new_port_list)
|
|
40
|
-
|
|
41
|
-
# Update the new port list
|
|
42
|
-
updated_port_list = {'22': 'ssh', '8080': 'http-alt'}
|
|
43
|
-
response = self.app.put('/api/port/list/test_port_list_lifecycle', json=updated_port_list)
|
|
44
|
-
self.assertEqual(response.status_code, 200)
|
|
45
|
-
|
|
46
|
-
# Get the new port list again
|
|
47
|
-
response = self.app.get('/api/port/list/test_port_list_lifecycle')
|
|
48
|
-
self.assertEqual(response.status_code, 200)
|
|
49
|
-
port_list = json.loads(response.data)
|
|
50
|
-
|
|
51
|
-
# Verify that the new port list has been updated
|
|
52
|
-
self.assertEqual(port_list, updated_port_list)
|
|
53
|
-
|
|
54
|
-
# Delete the new port list
|
|
55
|
-
response = self.app.delete('/api/port/list/test_port_list_lifecycle')
|
|
56
|
-
self.assertEqual(response.status_code, 200)
|
|
57
|
-
|
|
58
|
-
def test_scan(self):
|
|
59
|
-
# Delete the new port list if it exists
|
|
60
|
-
self.app.delete('/api/port/list/test_port_list_scan')
|
|
61
|
-
|
|
62
|
-
# Create a new port list
|
|
63
|
-
new_port_list = {'80': 'http', '443': 'https'}
|
|
64
|
-
response = self.app.post('/api/port/list/test_port_list_scan', json=new_port_list)
|
|
65
|
-
self.assertEqual(response.status_code, 200)
|
|
66
|
-
|
|
67
|
-
# Create a new scan, wait for completion
|
|
68
|
-
new_scan = {'subnet': right_size_subnet(get_network_subnet()), 'port_list': 'test_port_list_scan'}
|
|
69
|
-
response = self.app.post('/api/scan/async', json=new_scan)
|
|
70
|
-
self.assertEqual(response.status_code, 200)
|
|
71
|
-
scan_info = json.loads(response.data)
|
|
72
|
-
self.assertEqual(scan_info['status'], 'complete')
|
|
73
|
-
scanid = scan_info['scan_id']
|
|
74
|
-
self.assertIsNotNone(scanid)
|
|
75
|
-
|
|
76
|
-
# Validate the scan worked without error
|
|
77
|
-
response = self.app.get(f"/api/scan/{scanid}")
|
|
78
|
-
self.assertEqual(response.status_code, 200)
|
|
79
|
-
scan_data = json.loads(response.data)
|
|
80
|
-
self.assertEqual(scan_data['errors'], [])
|
|
81
|
-
self.assertEqual(scan_data['stage'],'complete')
|
|
82
|
-
|
|
83
|
-
# Render UI
|
|
84
|
-
uris = [
|
|
85
|
-
'/info',
|
|
86
|
-
f'/?scan_id={scanid}',
|
|
87
|
-
f'/scan/{scanid}/overview',
|
|
88
|
-
f'/scan/{scanid}/table',
|
|
89
|
-
f'/export/{scanid}'
|
|
90
|
-
]
|
|
91
|
-
for uri in uris:
|
|
92
|
-
response = self.app.get(uri)
|
|
93
|
-
self.assertEqual(response.status_code,200)
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
# Delete the new port list
|
|
97
|
-
response = self.app.delete('/api/port/list/test_port_list_scan')
|
|
98
|
-
self.assertEqual(response.status_code, 200)
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
def test_subnet_ports(self):
|
|
102
|
-
"""
|
|
103
|
-
Test to ensure multi-subnet dectection is working
|
|
104
|
-
"""
|
|
105
|
-
|
|
106
|
-
response = self.app.get('/api/tools/subnet/list')
|
|
107
|
-
self.assertEqual(response.status_code, 200)
|
|
108
|
-
|
|
109
|
-
subnets = json.loads(response.data)
|
|
110
|
-
self.assertIsNot(len(subnets), 0)
|
|
111
|
-
self.assertIsInstance(subnets[0],dict)
|
|
112
|
-
subnet:dict = subnets[0]
|
|
113
|
-
self.assertIsNotNone(subnet.get('address_cnt'))
|
|
114
|
-
|
|
115
|
-
def test_subnet_validation(self):
|
|
116
|
-
"""
|
|
117
|
-
test subnet validation and parsing is working as expected
|
|
118
|
-
"""
|
|
119
|
-
subnet_tests = {
|
|
120
|
-
# subnet : count (-1 == invalid)
|
|
121
|
-
'10.0.0.0/24': 254,
|
|
122
|
-
'10.0.0.2/24': 254,
|
|
123
|
-
'10.0.0.1-100': 100,
|
|
124
|
-
'192.168.1.1/25': 126,
|
|
125
|
-
'10.0.0.1/24, 192.168.1.1-100': 354,
|
|
126
|
-
'10.0.0.1/20': 4094,
|
|
127
|
-
'10.0.0.1/19': 8190,
|
|
128
|
-
'': -1, # blank
|
|
129
|
-
'10.0.1/24': -1, # invalid
|
|
130
|
-
'10.0.0.1/2': -1, # too big
|
|
131
|
-
'10.0.0.1/19, 192.168.1.1/20': 12284,
|
|
132
|
-
'10.0.0.1/17, 192.168.0.1/16': 98300,
|
|
133
|
-
'10.0.0.1/20, 192.168.0.1/20, 10.100.0.1/20': 12282,
|
|
134
|
-
'10.0.0.1/17, 192.168.0.1/16, 10.100.0.1/20': -1
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
for subnet, count in subnet_tests.items():
|
|
138
|
-
uri = f'/api/tools/subnet/test?subnet={subnet}'
|
|
139
|
-
response = self.app.get(uri)
|
|
140
|
-
self.assertEqual(response.status_code, 200)
|
|
141
|
-
|
|
142
|
-
data:dict = json.loads(response.data)
|
|
143
|
-
self.assertEqual(data.get('count'),count)
|
|
144
|
-
self.assertIsNotNone(data.get('msg'))
|
|
145
|
-
if count == -1:
|
|
146
|
-
self.assertFalse(data.get('valid'))
|
|
147
|
-
|
|
148
|
-
def test_scan_api(self):
|
|
149
|
-
"""
|
|
150
|
-
Test the scan API endpoints
|
|
151
|
-
"""
|
|
152
|
-
# Create a new scan
|
|
153
|
-
new_scan = {
|
|
154
|
-
'subnet': right_size_subnet(get_network_subnet()),
|
|
155
|
-
'port_list': 'small',
|
|
156
|
-
'parallelism': 1
|
|
157
|
-
}
|
|
158
|
-
response = self.app.post('/api/scan', json=new_scan)
|
|
159
|
-
self.assertEqual(response.status_code, 200)
|
|
160
|
-
scan_info = json.loads(response.data)
|
|
161
|
-
self.assertEqual(scan_info['status'], 'running')
|
|
162
|
-
scan_id = scan_info['scan_id']
|
|
163
|
-
self.assertIsNotNone(scan_id)
|
|
164
|
-
|
|
165
|
-
percent_complete = 0
|
|
166
|
-
while percent_complete < 100:
|
|
167
|
-
# Get scan summary
|
|
168
|
-
response = self.app.get(f'/api/scan/{scan_id}/summary')
|
|
169
|
-
self.assertEqual(response.status_code, 200)
|
|
170
|
-
summary = json.loads(response.data)
|
|
171
|
-
self.assertTrue(summary['running'] or summary['stage'] == 'complete')
|
|
172
|
-
percent_complete = summary['percent_complete']
|
|
173
|
-
self.assertGreaterEqual(percent_complete, 0)
|
|
174
|
-
self.assertLessEqual(percent_complete, 100)
|
|
175
|
-
# Wait for a bit before checking again
|
|
176
|
-
time.sleep(2)
|
|
177
|
-
|
|
178
|
-
self.assertEqual(summary['running'], False)
|
|
179
|
-
self.assertEqual(summary['stage'], 'complete')
|
|
180
|
-
self.assertGreater(summary['runtime'], 0)
|
|
181
|
-
|
|
182
|
-
devices_alive = summary['devices']['alive']
|
|
183
|
-
devices_scanned = summary['devices']['scanned']
|
|
184
|
-
devices_total = summary['devices']['total']
|
|
185
|
-
|
|
186
|
-
self.assertEqual(devices_scanned, devices_total)
|
|
187
|
-
self.assertGreater(devices_alive, 0)
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
if __name__ == '__main__':
|
|
194
|
-
unittest.main()
|
lanscape/tests/test_env.py
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import unittest
|
|
2
|
-
|
|
3
|
-
from ..libraries.version_manager import lookup_latest_version
|
|
4
|
-
from ..libraries.app_scope import ResourceManager, is_local_run
|
|
5
|
-
from ..libraries.net_tools import is_arp_supported
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
class EnvTestCase(unittest.TestCase):
|
|
10
|
-
def test_versioning(self):
|
|
11
|
-
version = lookup_latest_version()
|
|
12
|
-
self.assertIsNotNone(version)
|
|
13
|
-
|
|
14
|
-
def test_resource_manager(self):
|
|
15
|
-
ports = ResourceManager('ports')
|
|
16
|
-
self.assertGreater(len(ports.list()),0)
|
|
17
|
-
mac = ResourceManager('mac_addresses')
|
|
18
|
-
mac_list = mac.get('mac_db.json')
|
|
19
|
-
self.assertIsNotNone(mac_list)
|
|
20
|
-
|
|
21
|
-
def test_local_version(self):
|
|
22
|
-
self.assertTrue(is_local_run())
|
|
23
|
-
|
|
24
|
-
def test_arp_support(self):
|
|
25
|
-
arp_supported = is_arp_supported()
|
|
26
|
-
self.assertIn(arp_supported, [True, False],
|
|
27
|
-
f"ARP support should be either True or False, not {arp_supported}"
|
|
28
|
-
)
|
|
29
|
-
|
|
30
|
-
|
lanscape/tests/test_library.py
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import unittest
|
|
2
|
-
from ..libraries.net_tools import smart_select_primary_subnet
|
|
3
|
-
from ._helpers import right_size_subnet
|
|
4
|
-
from ..libraries.subnet_scan import ScanManager, ScanConfig
|
|
5
|
-
|
|
6
|
-
sm = ScanManager()
|
|
7
|
-
|
|
8
|
-
class LibraryTestCase(unittest.TestCase):
|
|
9
|
-
def test_scan(self):
|
|
10
|
-
subnet = smart_select_primary_subnet()
|
|
11
|
-
self.assertIsNotNone(subnet)
|
|
12
|
-
cfg = ScanConfig(
|
|
13
|
-
subnet = right_size_subnet(subnet),
|
|
14
|
-
t_multiplier=1.0,
|
|
15
|
-
port_list='small'
|
|
16
|
-
)
|
|
17
|
-
scan = sm.new_scan(cfg)
|
|
18
|
-
self.assertTrue(scan.running)
|
|
19
|
-
sm.wait_until_complete(scan.uid)
|
|
20
|
-
|
|
21
|
-
self.assertFalse(scan.running)
|
|
22
|
-
|
|
23
|
-
# ensure there are not any remaining running threads
|
|
24
|
-
self.assertDictEqual(scan.job_stats.running,{})
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
cnt_with_hostname = 0
|
|
28
|
-
ips = []
|
|
29
|
-
macs = []
|
|
30
|
-
for d in scan.results.devices:
|
|
31
|
-
if d.hostname: cnt_with_hostname += 1
|
|
32
|
-
# ensure there arent dupe mac addresses
|
|
33
|
-
self.assertNotIn(d.get_mac(), macs)
|
|
34
|
-
macs.append(d.get_mac())
|
|
35
|
-
|
|
36
|
-
# ensure there arent dupe ips
|
|
37
|
-
self.assertNotIn(d.ip, ips)
|
|
38
|
-
ips.append(d.ip)
|
|
39
|
-
|
|
40
|
-
# device must be alive to be in this list
|
|
41
|
-
self.assertTrue(d.alive)
|
|
42
|
-
|
|
43
|
-
# find at least one device
|
|
44
|
-
self.assertGreater(len(scan.results.devices),0)
|
|
45
|
-
|
|
46
|
-
# ensure everything got scanned
|
|
47
|
-
self.assertEqual(scan.results.devices_scanned, scan.results.devices_total)
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
lanscape/ui/app.py
DELETED
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
from flask import Flask, render_template, request
|
|
2
|
-
from time import sleep
|
|
3
|
-
import multiprocessing
|
|
4
|
-
import traceback
|
|
5
|
-
import threading
|
|
6
|
-
import logging
|
|
7
|
-
import os
|
|
8
|
-
|
|
9
|
-
from ..libraries.runtime_args import RuntimeArgs, parse_args
|
|
10
|
-
from ..libraries.version_manager import is_update_available, get_installed_version, lookup_latest_version
|
|
11
|
-
from ..libraries.app_scope import is_local_run
|
|
12
|
-
from ..libraries.net_tools import is_arp_supported
|
|
13
|
-
|
|
14
|
-
app = Flask(
|
|
15
|
-
__name__
|
|
16
|
-
)
|
|
17
|
-
log = logging.getLogger('flask')
|
|
18
|
-
|
|
19
|
-
## Import and register BPs
|
|
20
|
-
################################
|
|
21
|
-
|
|
22
|
-
from .blueprints.api import api_bp
|
|
23
|
-
from .blueprints.web import web_bp
|
|
24
|
-
|
|
25
|
-
app.register_blueprint(api_bp)
|
|
26
|
-
app.register_blueprint(web_bp)
|
|
27
|
-
|
|
28
|
-
## Define global jinja filters
|
|
29
|
-
################################
|
|
30
|
-
|
|
31
|
-
def is_substring_in_values(results: dict, substring: str) -> bool:
|
|
32
|
-
return any(substring.lower() in str(v).lower() for v in results.values()) if substring else True
|
|
33
|
-
|
|
34
|
-
app.jinja_env.filters['is_substring_in_values'] = is_substring_in_values
|
|
35
|
-
|
|
36
|
-
## Define global jinja vars
|
|
37
|
-
################################
|
|
38
|
-
|
|
39
|
-
def set_global_safe(key: str, value):
|
|
40
|
-
""" Safely set global vars without worrying about an exception """
|
|
41
|
-
app_globals = app.jinja_env.globals
|
|
42
|
-
try:
|
|
43
|
-
if callable(value): value = value()
|
|
44
|
-
|
|
45
|
-
app_globals[key] = value
|
|
46
|
-
log.debug(f'jinja_globals[{key}] = {value}')
|
|
47
|
-
except:
|
|
48
|
-
default = app_globals.get(key)
|
|
49
|
-
log.debug(traceback.format_exc())
|
|
50
|
-
log.info(
|
|
51
|
-
f"Unable to set app global var '{key}'"+
|
|
52
|
-
f"defaulting to '{default}'"
|
|
53
|
-
)
|
|
54
|
-
app_globals[key] = default
|
|
55
|
-
|
|
56
|
-
set_global_safe('app_version',get_installed_version)
|
|
57
|
-
set_global_safe('update_available', is_update_available)
|
|
58
|
-
set_global_safe('latest_version',lookup_latest_version)
|
|
59
|
-
set_global_safe('runtime_args', vars(parse_args()))
|
|
60
|
-
set_global_safe('is_local',is_local_run)
|
|
61
|
-
set_global_safe('is_arp_supported', is_arp_supported)
|
|
62
|
-
|
|
63
|
-
## External hook to kill flask server
|
|
64
|
-
################################
|
|
65
|
-
|
|
66
|
-
exiting = False
|
|
67
|
-
@app.route("/shutdown", methods=['GET', 'POST'])
|
|
68
|
-
def exit_app():
|
|
69
|
-
|
|
70
|
-
req_type = request.args.get('type')
|
|
71
|
-
if req_type == 'browser-close':
|
|
72
|
-
args = parse_args()
|
|
73
|
-
if args.persistent:
|
|
74
|
-
log.info('Dectected browser close, not exiting flask.')
|
|
75
|
-
return "Ignored"
|
|
76
|
-
log.info('Web browser closed, terminating flask. (disable with --peristent)')
|
|
77
|
-
elif req_type == 'core':
|
|
78
|
-
log.info('Core requested exit, terminating flask.')
|
|
79
|
-
else:
|
|
80
|
-
log.info('Received external exit request. Terminating flask.')
|
|
81
|
-
global exiting
|
|
82
|
-
exiting = True
|
|
83
|
-
return "Done"
|
|
84
|
-
|
|
85
|
-
@app.teardown_request
|
|
86
|
-
def teardown(exception):
|
|
87
|
-
if exiting:
|
|
88
|
-
os._exit(0)
|
|
89
|
-
|
|
90
|
-
## Generalized error handling
|
|
91
|
-
################################
|
|
92
|
-
@app.errorhandler(500)
|
|
93
|
-
def internal_error(e):
|
|
94
|
-
"""
|
|
95
|
-
handle internal errors nicely
|
|
96
|
-
"""
|
|
97
|
-
tb = traceback.format_exc()
|
|
98
|
-
return render_template('error.html',
|
|
99
|
-
error=None,
|
|
100
|
-
traceback=tb), 500
|
|
101
|
-
|
|
102
|
-
## Webserver creation functions
|
|
103
|
-
################################
|
|
104
|
-
|
|
105
|
-
def start_webserver_daemon(args: RuntimeArgs) -> threading.Thread:
|
|
106
|
-
proc = threading.Thread(target=start_webserver, args=(args,))
|
|
107
|
-
proc.daemon = True # Kill thread when main thread exits
|
|
108
|
-
proc.start()
|
|
109
|
-
log.info('Flask server initializing as dameon')
|
|
110
|
-
return proc
|
|
111
|
-
|
|
112
|
-
def start_webserver(args: RuntimeArgs) -> int:
|
|
113
|
-
run_args = {
|
|
114
|
-
'host':'0.0.0.0',
|
|
115
|
-
'port':args.port,
|
|
116
|
-
'debug':args.reloader,
|
|
117
|
-
'use_reloader':args.reloader
|
|
118
|
-
}
|
|
119
|
-
app.run(**run_args)
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
from flask import request, jsonify
|
|
2
|
-
from . import api_bp
|
|
3
|
-
from ....libraries.port_manager import PortManager
|
|
4
|
-
|
|
5
|
-
# Port Manager API
|
|
6
|
-
############################################
|
|
7
|
-
@api_bp.route('/api/port/list', methods=['GET'])
|
|
8
|
-
def get_port_lists():
|
|
9
|
-
return jsonify(PortManager().get_port_lists())
|
|
10
|
-
|
|
11
|
-
@api_bp.route('/api/port/list/<port_list>', methods=['GET'])
|
|
12
|
-
def get_port_list(port_list):
|
|
13
|
-
return jsonify(PortManager().get_port_list(port_list))
|
|
14
|
-
|
|
15
|
-
@api_bp.route('/api/port/list/<port_list>', methods=['POST'])
|
|
16
|
-
def create_port_list(port_list):
|
|
17
|
-
data = request.get_json()
|
|
18
|
-
return jsonify(PortManager().create_port_list(port_list, data))
|
|
19
|
-
|
|
20
|
-
@api_bp.route('/api/port/list/<port_list>', methods=['PUT'])
|
|
21
|
-
def update_port_list(port_list):
|
|
22
|
-
data = request.get_json()
|
|
23
|
-
return jsonify(PortManager().update_port_list(port_list, data))
|
|
24
|
-
|
|
25
|
-
@api_bp.route('/api/port/list/<port_list>', methods=['DELETE'])
|
|
26
|
-
def delete_port_list(port_list):
|
|
27
|
-
return jsonify(PortManager().delete_port_list(port_list))
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
from . import api_bp
|
|
2
|
-
from ....libraries.subnet_scan import ScanConfig
|
|
3
|
-
from .. import scan_manager
|
|
4
|
-
|
|
5
|
-
from flask import request, jsonify
|
|
6
|
-
import json
|
|
7
|
-
import traceback
|
|
8
|
-
|
|
9
|
-
# Subnet Scanner API
|
|
10
|
-
############################################
|
|
11
|
-
@api_bp.route('/api/scan', methods=['POST'])
|
|
12
|
-
@api_bp.route('/api/scan/threaded', methods=['POST'])
|
|
13
|
-
def scan_subnet_threaded():
|
|
14
|
-
try:
|
|
15
|
-
config = get_scan_config()
|
|
16
|
-
scan = scan_manager.new_scan(config)
|
|
17
|
-
|
|
18
|
-
return jsonify({'status': 'running', 'scan_id': scan.uid})
|
|
19
|
-
except:
|
|
20
|
-
return jsonify({'status': 'error', 'traceback': traceback.format_exc()}), 500
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
@api_bp.route('/api/scan/async', methods=['POST'])
|
|
24
|
-
def scan_subnet_async():
|
|
25
|
-
config = get_scan_config()
|
|
26
|
-
scan = scan_manager.new_scan(config)
|
|
27
|
-
scan_manager.wait_until_complete(scan.uid)
|
|
28
|
-
|
|
29
|
-
return jsonify({'status': 'complete', 'scan_id': scan.uid})
|
|
30
|
-
|
|
31
|
-
@api_bp.route('/api/scan/<scan_id>', methods=['GET'])
|
|
32
|
-
def get_scan(scan_id):
|
|
33
|
-
scan = scan_manager.get_scan(scan_id)
|
|
34
|
-
# cast to str and back to handle custom JSON serialization
|
|
35
|
-
return jsonify(json.loads(scan.results.export(str)))
|
|
36
|
-
|
|
37
|
-
@api_bp.route('/api/scan/<scan_id>/summary',methods=['GET'])
|
|
38
|
-
def get_scan_summary(scan_id):
|
|
39
|
-
scan = scan_manager.get_scan(scan_id)
|
|
40
|
-
if not scan:
|
|
41
|
-
return jsonify({'error':'scan not found'}), 404
|
|
42
|
-
return jsonify({
|
|
43
|
-
'running': scan.running,
|
|
44
|
-
'percent_complete': scan.calc_percent_complete(),
|
|
45
|
-
'stage': scan.results.stage,
|
|
46
|
-
'runtime': scan.results.get_runtime(),
|
|
47
|
-
'devices': {
|
|
48
|
-
'scanned': scan.results.devices_scanned,
|
|
49
|
-
'alive': len(scan.results.devices),
|
|
50
|
-
'total': scan.results.devices_total
|
|
51
|
-
}
|
|
52
|
-
})
|
|
53
|
-
|
|
54
|
-
@api_bp.route('/api/scan/<scan_id>/terminate', methods=['GET'])
|
|
55
|
-
def terminate_scan(scan_id):
|
|
56
|
-
scan = scan_manager.get_scan(scan_id)
|
|
57
|
-
scan.terminate()
|
|
58
|
-
return jsonify({'success': True})
|
|
59
|
-
|
|
60
|
-
def get_scan_config():
|
|
61
|
-
"""
|
|
62
|
-
pulls config from the request body
|
|
63
|
-
"""
|
|
64
|
-
data = request.get_json()
|
|
65
|
-
return ScanConfig(
|
|
66
|
-
subnet = data['subnet'],
|
|
67
|
-
port_list= data['port_list'],
|
|
68
|
-
t_multiplier=data.get('parallelism',1.0)
|
|
69
|
-
)
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
from flask import request, jsonify
|
|
2
|
-
from . import api_bp
|
|
3
|
-
from ....libraries.net_tools import get_all_network_subnets
|
|
4
|
-
from ....libraries.ip_parser import parse_ip_input
|
|
5
|
-
from ....libraries.errors import SubnetTooLargeError
|
|
6
|
-
import traceback
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
@api_bp.route('/api/tools/subnet/test')
|
|
10
|
-
def test_subnet():
|
|
11
|
-
subnet = request.args.get('subnet')
|
|
12
|
-
if not subnet: return jsonify({'valid': False, 'msg': 'Subnet cannot be blank', 'count': -1})
|
|
13
|
-
try:
|
|
14
|
-
ips = parse_ip_input(subnet)
|
|
15
|
-
length = len(ips)
|
|
16
|
-
return jsonify({'valid': True, 'msg': f"{length} IP{'s' if length > 1 else ''}", 'count': length})
|
|
17
|
-
except SubnetTooLargeError:
|
|
18
|
-
return jsonify({'valid': False, 'msg': 'subnet too large', 'error': traceback.format_exc(), 'count': -1})
|
|
19
|
-
except:
|
|
20
|
-
return jsonify({'valid': False, 'msg': 'invalid subnet', 'error': traceback.format_exc(), 'count': -1})
|
|
21
|
-
|
|
22
|
-
@api_bp.route('/api/tools/subnet/list')
|
|
23
|
-
def list_subnet():
|
|
24
|
-
"""
|
|
25
|
-
list all interface subets
|
|
26
|
-
"""
|
|
27
|
-
try:
|
|
28
|
-
return jsonify(get_all_network_subnets())
|
|
29
|
-
except:
|
|
30
|
-
return jsonify({'error': traceback.format_exc()})
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
from flask import render_template, request, redirect
|
|
2
|
-
from . import web_bp
|
|
3
|
-
from ....libraries.subnet_scan import SubnetScanner
|
|
4
|
-
from ....libraries.net_tools import (
|
|
5
|
-
get_all_network_subnets,
|
|
6
|
-
smart_select_primary_subnet
|
|
7
|
-
)
|
|
8
|
-
from .. import scan_manager, log
|
|
9
|
-
import os
|
|
10
|
-
|
|
11
|
-
# Template Renderer
|
|
12
|
-
############################################
|
|
13
|
-
@web_bp.route('/', methods=['GET'])
|
|
14
|
-
def index():
|
|
15
|
-
subnets = get_all_network_subnets()
|
|
16
|
-
subnet = smart_select_primary_subnet(subnets)
|
|
17
|
-
|
|
18
|
-
port_list = 'medium'
|
|
19
|
-
parallelism = 1
|
|
20
|
-
if scan_id := request.args.get('scan_id'):
|
|
21
|
-
if scan := scan_manager.get_scan(scan_id):
|
|
22
|
-
subnet = scan.cfg.subnet
|
|
23
|
-
port_list = scan.cfg.port_list
|
|
24
|
-
parallelism = scan.cfg.t_multiplier
|
|
25
|
-
|
|
26
|
-
else:
|
|
27
|
-
log.debug(f'Redirecting, scan {scan_id} doesnt exist in memory')
|
|
28
|
-
return redirect('/')
|
|
29
|
-
return render_template(
|
|
30
|
-
'main.html',
|
|
31
|
-
subnet=subnet,
|
|
32
|
-
port_list=port_list,
|
|
33
|
-
parallelism=parallelism,
|
|
34
|
-
alternate_subnets=subnets
|
|
35
|
-
)
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
@web_bp.route('/scan/<scan_id>', methods=['GET'])
|
|
39
|
-
@web_bp.route('/scan/<scan_id>/<section>', methods=['GET'])
|
|
40
|
-
def render_scan(scan_id, section='all'):
|
|
41
|
-
if scanner := scan_manager.get_scan(scan_id):
|
|
42
|
-
data = scanner.results.export()
|
|
43
|
-
filter = request.args.get('filter')
|
|
44
|
-
return render_template('scan.html', data=data, section=section, filter=filter)
|
|
45
|
-
log.debug(f'Redirecting, scan {scan_id} doesnt exist in memory')
|
|
46
|
-
return redirect('/')
|
|
47
|
-
|
|
48
|
-
@web_bp.route('/errors/<scan_id>')
|
|
49
|
-
def view_errors(scan_id):
|
|
50
|
-
if scanner := scan_manager.get_scan(scan_id):
|
|
51
|
-
data = scanner.results.export()
|
|
52
|
-
return render_template('scan/scan-error.html',data=data)
|
|
53
|
-
log.debug(f'Redirecting, scan {scan_id} doesnt exist in memory')
|
|
54
|
-
return redirect('/')
|
|
55
|
-
|
|
56
|
-
@web_bp.route('/export/<scan_id>')
|
|
57
|
-
def export_scan(scan_id):
|
|
58
|
-
if scanner := scan_manager.get_scan(scan_id):
|
|
59
|
-
export_json = scanner.results.export(str)
|
|
60
|
-
return render_template(
|
|
61
|
-
'scan/export.html',
|
|
62
|
-
scan=scanner,
|
|
63
|
-
export_json=export_json
|
|
64
|
-
)
|
|
65
|
-
log.debug(f'Redirecting, scan {scan_id} doesnt exist in memory')
|
|
66
|
-
return redirect('/')
|
|
67
|
-
|
|
68
|
-
@web_bp.route('/shutdown-ui')
|
|
69
|
-
def shutdown_ui():
|
|
70
|
-
return render_template('shutdown.html')
|
|
71
|
-
|
|
72
|
-
@web_bp.route('/info')
|
|
73
|
-
def app_info():
|
|
74
|
-
return render_template('info.html')
|