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.

Files changed (41) hide show
  1. lanscape/__init__.py +4 -1
  2. lanscape/__main__.py +4 -1
  3. lanscape/ui/static/css/style.css +1 -1
  4. lanscape/ui/templates/core/scripts.html +1 -1
  5. lanscape/ui/templates/info.html +1 -1
  6. lanscape/ui/templates/main.html +6 -4
  7. {lanscape-1.3.1a8.dist-info → lanscape-1.3.2a6.dist-info}/METADATA +4 -3
  8. lanscape-1.3.2a6.dist-info/RECORD +43 -0
  9. lanscape/libraries/app_scope.py +0 -70
  10. lanscape/libraries/decorators.py +0 -75
  11. lanscape/libraries/errors.py +0 -29
  12. lanscape/libraries/ip_parser.py +0 -65
  13. lanscape/libraries/logger.py +0 -42
  14. lanscape/libraries/mac_lookup.py +0 -69
  15. lanscape/libraries/net_tools.py +0 -480
  16. lanscape/libraries/port_manager.py +0 -59
  17. lanscape/libraries/runtime_args.py +0 -44
  18. lanscape/libraries/service_scan.py +0 -51
  19. lanscape/libraries/subnet_scan.py +0 -373
  20. lanscape/libraries/version_manager.py +0 -54
  21. lanscape/libraries/web_browser.py +0 -141
  22. lanscape/resources/mac_addresses/convert_csv.py +0 -27
  23. lanscape/resources/ports/convert_csv.py +0 -27
  24. lanscape/tests/__init__.py +0 -3
  25. lanscape/tests/_helpers.py +0 -15
  26. lanscape/tests/test_api.py +0 -194
  27. lanscape/tests/test_env.py +0 -30
  28. lanscape/tests/test_library.py +0 -53
  29. lanscape/ui/app.py +0 -122
  30. lanscape/ui/blueprints/__init__.py +0 -7
  31. lanscape/ui/blueprints/api/__init__.py +0 -5
  32. lanscape/ui/blueprints/api/port.py +0 -27
  33. lanscape/ui/blueprints/api/scan.py +0 -69
  34. lanscape/ui/blueprints/api/tools.py +0 -30
  35. lanscape/ui/blueprints/web/__init__.py +0 -5
  36. lanscape/ui/blueprints/web/routes.py +0 -74
  37. lanscape/ui/main.py +0 -138
  38. lanscape-1.3.1a8.dist-info/RECORD +0 -72
  39. {lanscape-1.3.1a8.dist-info → lanscape-1.3.2a6.dist-info}/WHEEL +0 -0
  40. {lanscape-1.3.1a8.dist-info → lanscape-1.3.2a6.dist-info}/licenses/LICENSE +0 -0
  41. {lanscape-1.3.1a8.dist-info → lanscape-1.3.2a6.dist-info}/top_level.txt +0 -0
@@ -1,373 +0,0 @@
1
- import os
2
- import json
3
- import uuid
4
- import logging
5
- import ipaddress
6
- import traceback
7
- import threading
8
- from time import time
9
- from time import sleep
10
- from typing import List, Union
11
- from tabulate import tabulate
12
- from dataclasses import dataclass
13
- from concurrent.futures import ThreadPoolExecutor, as_completed
14
-
15
- from .net_tools import Device, is_arp_supported
16
- from .ip_parser import parse_ip_input
17
- from .port_manager import PortManager
18
- from.errors import SubnetScanTerminationFailure
19
- from .decorators import job_tracker, JobStats, terminator
20
-
21
-
22
- TCNT_PORT_SCANS = 10
23
- TCNT_PORT_TEST = 128
24
- TCNT_DEVICE_ISALIVE = 256
25
-
26
- @dataclass
27
- class ScanConfig:
28
- subnet: str
29
- port_list: str
30
- t_multiplier: float = 1.0
31
- t_cnt_port_scan: int = 10
32
- t_cnt_port_test: int = 128
33
- t_cnt_isalive: int = 256
34
-
35
- task_scan_ports: bool = True
36
- # below wont run if above false
37
- task_scan_port_services: bool = False # disabling until more stable
38
-
39
- def t_cnt(self, id: str) -> int:
40
- return int(int(getattr(self, f't_cnt_{id}')) * float(self.t_multiplier))
41
-
42
- @staticmethod
43
- def from_dict(data: dict) -> 'ScanConfig':
44
- return ScanConfig(
45
- subnet = data['subnet'],
46
- port_list = data['port_list'],
47
- t_multiplier = data.get('parallelism',1.0),
48
- t_cnt_port_scan = data.get('t_cnt_port_scan',10),
49
- t_cnt_port_test = data.get('t_cnt_port_test',128),
50
- t_cnt_isalive = data.get('t_cnt_isalive',256),
51
- task_scan_ports = data.get('task_scan_ports',True),
52
- task_scan_port_services = data.get('task_scan_port_services',True)
53
- )
54
-
55
- def get_ports(self) -> List[int]:
56
- return PortManager().get_port_list(self.port_list).keys()
57
-
58
- def parse_subnet(self) -> List[ipaddress.IPv4Network]:
59
- return parse_ip_input(self.subnet)
60
-
61
- def __str__(self):
62
- return f'ScanCfg(subnet={self.subnet}, ports={self.port_list}, multiplier={self.t_multiplier})'
63
-
64
-
65
-
66
-
67
- class SubnetScanner:
68
- def __init__(
69
- self,
70
- config: ScanConfig
71
- ):
72
- self.cfg = config
73
- self.subnet = config.parse_subnet()
74
- self.ports: List[int] = config.get_ports()
75
- self.running = False
76
- self.subnet_str = config.subnet
77
-
78
-
79
- self.job_stats = JobStats()
80
- self.uid = str(uuid.uuid4())
81
- self.results = ScannerResults(self)
82
- self.log: logging.Logger = logging.getLogger('SubnetScanner')
83
- if not is_arp_supported():
84
- self.log.warning('ARP is not supported with the active runtime context. Device discovery will be limited to ping responses.')
85
- self.log.debug(f'Instantiated with uid: {self.uid}')
86
- self.log.debug(f'Port Count: {len(self.ports)} | Device Count: {len(self.subnet)}')
87
-
88
-
89
-
90
-
91
- def start(self):
92
- """
93
- Scan the subnet for devices and open ports.
94
- """
95
- self._set_stage('scanning devices')
96
- self.running = True
97
- with ThreadPoolExecutor(max_workers=self.cfg.t_cnt('isalive')) as executor:
98
- futures = {executor.submit(self._get_host_details, str(ip)): str(ip) for ip in self.subnet}
99
- for future in as_completed(futures):
100
- ip = futures[future]
101
- try:
102
- future.result()
103
- except Exception as e:
104
- self.log.error(f'[{ip}] scan failed. details below:\n{traceback.format_exc()}')
105
- self.results.errors.append({
106
- 'basic': f"Error scanning IP {ip}: {e}",
107
- 'traceback': traceback.format_exc(),
108
- })
109
-
110
-
111
- self._set_stage('testing ports')
112
- if self.cfg.task_scan_ports:
113
- self._scan_network_ports()
114
- self.running = False
115
- self._set_stage('complete')
116
-
117
- return self.results
118
-
119
- def terminate(self):
120
- self.running = False
121
- self._set_stage('terminating')
122
- for i in range(20):
123
- if not len(self.job_stats.running.keys()):
124
- self._set_stage('terminated')
125
- return True
126
- sleep(.5)
127
- raise SubnetScanTerminationFailure(self.job_stats.running)
128
-
129
- def calc_percent_complete(self) -> int: # 0 - 100
130
- if not self.running: return 100
131
-
132
- # --- Host discovery (isalive) calculations ---
133
- avg_host_detail_sec = self.job_stats.timing.get('_get_host_details', 4.5)
134
- # assume 10% alive percentage if the scan just started
135
- if len(self.results.devices) and (self.results.devices_scanned):
136
- est_subnet_alive_percent = (len(self.results.devices)) / (self.results.devices_scanned) # avoid div 0
137
- else:
138
- est_subnet_alive_percent = .1
139
- est_subnet_devices = est_subnet_alive_percent * self.results.devices_total
140
-
141
- remaining_isalive_sec = (self.results.devices_total - self.results.devices_scanned) * avg_host_detail_sec
142
- total_isalive_sec = self.results.devices_total * avg_host_detail_sec
143
-
144
- isalive_multiplier = self.cfg.t_cnt('isalive')
145
-
146
- # --- Port scanning calculations ---
147
- device_ports_scanned = self.job_stats.finished.get('_test_port', 0)
148
- # remediate initial inaccurate results because open ports reurn quickly
149
- avg_port_test_sec = self.job_stats.timing.get('_test_port', 1) if device_ports_scanned > 20 else 1
150
-
151
- device_ports_unscanned = max(0, (est_subnet_devices*len(self.ports)) - device_ports_scanned)
152
-
153
- remaining_port_test_sec = device_ports_unscanned * avg_port_test_sec
154
- total_port_test_sec = est_subnet_devices * len(self.ports) * avg_port_test_sec
155
-
156
- port_test_multiplier = self.cfg.t_cnt('port_scan') * self.cfg.t_cnt('port_test')
157
-
158
- # --- Overall progress ---
159
- est_total_time = (total_isalive_sec / isalive_multiplier) + (total_port_test_sec / port_test_multiplier)
160
- est_remaining_time = (remaining_isalive_sec / isalive_multiplier) + (remaining_port_test_sec / port_test_multiplier)
161
-
162
- return int(abs((1 - (est_remaining_time / est_total_time)) * 100))
163
-
164
-
165
-
166
- def debug_active_scan(self,sleep_sec=1):
167
- """
168
- Run this after running scan_subnet_threaded
169
- to see the progress of the scan
170
- """
171
- while self.running:
172
- percent = self.calc_percent_complete()
173
- t_elapsed = time() - self.results.start_time
174
- t_remain = int((100-percent) * (t_elapsed / percent)) if percent else '∞'
175
- buffer = f'{self.uid} - {self.subnet_str}\n'
176
- buffer += f'Elapsed: {int(t_elapsed)} sec - Remain: {t_remain} sec\n'
177
- buffer += f'Scanned: {self.results.devices_scanned}/{self.results.devices_total}'
178
- buffer += f' - {percent}%\n'
179
- buffer += str(self.job_stats)
180
- os.system('cls' if os.name == 'nt' else 'clear')
181
- print(buffer)
182
- sleep(sleep_sec)
183
-
184
- @terminator
185
- @job_tracker
186
- def _get_host_details(self, host: str):
187
- """
188
- Get the MAC address and open ports of the given host.
189
- """
190
- device = Device(host)
191
- device.alive = self._ping(device)
192
- self.results.scanned()
193
- if not device.alive:
194
- return None
195
- self.log.debug(f'[{host}] is alive, getting metadata')
196
- device.get_metadata()
197
- self.results.devices.append(device)
198
- return True
199
-
200
- @terminator
201
- def _scan_network_ports(self):
202
- with ThreadPoolExecutor(max_workers=self.cfg.t_cnt('port_scan')) as executor:
203
- futures = {executor.submit(self._scan_ports, device): device for device in self.results.devices}
204
- for future in futures:
205
- future.result()
206
-
207
- @terminator
208
- @job_tracker
209
- def _scan_ports(self, device: Device):
210
- self.log.debug(f'[{device.ip}] Initiating port scan')
211
- device.stage = 'scanning'
212
- with ThreadPoolExecutor(max_workers=self.cfg.t_cnt('port_test')) as executor:
213
- futures = {executor.submit(self._test_port, device, int(port)): port for port in self.ports}
214
- for future in futures:
215
- future.result()
216
- self.log.debug(f'[{device.ip}] Completed port scan')
217
- device.stage = 'complete'
218
-
219
- @terminator
220
- @job_tracker
221
- def _test_port(self,host: Device, port: int):
222
- """
223
- Test if a port is open on a given host.
224
- If port open, determine service.
225
- Device class handles tracking open ports.
226
- """
227
- is_alive = host.test_port(port)
228
- if is_alive and self.cfg.task_scan_port_services:
229
- host.scan_service(port)
230
- return is_alive
231
-
232
-
233
- @terminator
234
- @job_tracker
235
- def _ping(self, host: Device):
236
- """
237
- Ping the given host and return True if it's reachable, False otherwise.
238
- """
239
- return host.is_alive(host.ip)
240
-
241
- def _set_stage(self,stage):
242
- self.log.debug(f'[{self.uid}] Moving to Stage: {stage}')
243
- self.results.stage = stage
244
- if not self.running:
245
- self.results.end_time = time()
246
-
247
- class ScannerResults:
248
- def __init__(self,scan: SubnetScanner):
249
- self.scan = scan
250
- self.port_list: str = scan.cfg.port_list
251
- self.subnet: str = scan.subnet_str
252
- self.uid = scan.uid
253
-
254
- self.devices_total: int = len(list(scan.subnet))
255
- self.devices_scanned: int = 0
256
- self.devices: List[Device] = []
257
-
258
- self.errors: List[str] = []
259
- self.running: bool = False
260
- self.start_time: float = time()
261
- self.end_time: int = None
262
- self.stage = 'instantiated'
263
-
264
- self.log = logging.getLogger('ScannerResults')
265
- self.log.debug(f'Instantiated Logger For Scan: {self.scan.uid}')
266
-
267
-
268
- def scanned(self):
269
- self.devices_scanned += 1
270
-
271
- def get_runtime(self):
272
- if self.scan.running:
273
- return int(time()-self.start_time)
274
- return int(self.end_time-self.start_time)
275
-
276
-
277
-
278
- def export(self,out_type=dict) -> Union[str, dict]:
279
- """
280
- Returns json representation of the scan
281
- """
282
-
283
- self.running = self.scan.running
284
- self.run_time = int(round(time() - self.start_time,0))
285
- self.devices_alive = len(self.devices)
286
-
287
- out = vars(self).copy()
288
- out.pop('scan')
289
- out.pop('log')
290
- out['cfg'] = vars(self.scan.cfg)
291
-
292
- devices: List[Device] = out.pop('devices')
293
- sortedDevices = sorted(devices, key=lambda obj: ipaddress.IPv4Address(obj.ip))
294
- out['devices'] = [device.dict() for device in sortedDevices]
295
-
296
- if out_type == str:
297
- return json.dumps(out,default=str, indent=2)
298
- # otherwise return dict
299
- return out
300
-
301
- def __str__(self):
302
- # Prepare data for tabulate
303
- data = [
304
- [device.ip, device.hostname, device.get_mac(), ", ".join(map(str, device.ports))]
305
- for device in self.devices
306
- ]
307
-
308
- # Create headers for the table
309
- headers = ["IP", "Host", "MAC", "Ports"]
310
-
311
- # Generate the table using tabulate
312
- table = tabulate(data, headers=headers, tablefmt="grid")
313
-
314
- # Format and return the complete buffer with table output
315
- buffer = f"Scan Results - {self.scan.subnet_str} - {self.uid}\n"
316
- buffer += "---------------------------------------------\n\n"
317
- buffer += table
318
- return buffer
319
-
320
-
321
- class ScanManager:
322
- """
323
- Maintain active and completed scans in memory for
324
- future reference. Singleton implementation.
325
- """
326
- _instance = None
327
-
328
- def __new__(cls, *args, **kwargs):
329
- if not cls._instance:
330
- cls._instance = super(ScanManager, cls).__new__(cls, *args, **kwargs)
331
- return cls._instance
332
-
333
- def __init__(self):
334
- if not hasattr(self, 'scans'): # Prevent reinitialization
335
- self.scans: List[SubnetScanner] = []
336
- self.log = logging.getLogger('ScanManager')
337
-
338
- def new_scan(self, config: ScanConfig) -> SubnetScanner:
339
- scan = SubnetScanner(config)
340
- self._start(scan)
341
- self.log.info(f'Scan started - {config}')
342
- self.scans.append(scan)
343
- return scan
344
-
345
- def get_scan(self, scan_id: str) -> SubnetScanner:
346
- """
347
- Get scan by scan.uid
348
- """
349
- for scan in self.scans:
350
- if scan.uid == scan_id:
351
- return scan
352
-
353
- def terminate_scans(self):
354
- """
355
- Terminate all active scans
356
- """
357
- for scan in self.scans:
358
- if scan.running:
359
- scan.terminate()
360
-
361
- def wait_until_complete(self, scan_id: str) -> SubnetScanner:
362
- scan = self.get_scan(scan_id)
363
- while scan.running:
364
- sleep(.5)
365
- return scan
366
-
367
- def _start(self, scan: SubnetScanner):
368
- t = threading.Thread(target=scan.start)
369
- t.start()
370
- return t
371
-
372
-
373
-
@@ -1,54 +0,0 @@
1
- import logging
2
- import requests
3
- import traceback
4
- from importlib.metadata import version, PackageNotFoundError
5
- from random import randint
6
-
7
- from .app_scope import is_local_run
8
-
9
- log = logging.getLogger('VersionManager')
10
-
11
- PACKAGE='lanscape'
12
- LOCAL_VERSION = '0.0.0'
13
-
14
- latest = None # used to 'remember' pypi version each runtime
15
-
16
- def is_update_available(package=PACKAGE) -> bool:
17
- installed = get_installed_version(package)
18
- available = lookup_latest_version(package)
19
-
20
- is_update_exempt = (
21
- 'a' in installed, 'b' in installed, # pre-release
22
- installed == LOCAL_VERSION
23
- )
24
- if any(is_update_exempt): return False
25
-
26
- log.debug(f'Installed: {installed} | Available: {available}')
27
- return installed != available
28
-
29
- def lookup_latest_version(package=PACKAGE):
30
- # Fetch the latest version from PyPI
31
- global latest
32
- if not latest:
33
- no_cache = f'?cachebust={randint(0,6969)}'
34
- url = f"https://pypi.org/pypi/{package}/json{no_cache}"
35
- try:
36
- response = requests.get(url,timeout=5)
37
- response.raise_for_status() # Raise an exception for HTTP errors
38
- latest = response.json()['info']['version']
39
- log.debug(f'Latest pypi version: {latest}')
40
- except:
41
- log.debug(traceback.format_exc())
42
- log.warning('Unable to fetch package version from PyPi')
43
- return latest
44
-
45
- def get_installed_version(package=PACKAGE):
46
- if not is_local_run():
47
- try:
48
- return version(package)
49
- except PackageNotFoundError:
50
- log.debug(traceback.format_exc())
51
- log.warning(f'Cannot find {package} installation')
52
- return LOCAL_VERSION
53
-
54
-
@@ -1,141 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- Get the executable path of the system’s default web browser.
4
-
5
- Supports:
6
- - Windows (reads from the registry)
7
- - Linux (uses xdg-mime / xdg-settings + .desktop file parsing)
8
- """
9
-
10
- import sys
11
- import os
12
- import subprocess
13
- import webbrowser
14
- import logging
15
- import re
16
- import time
17
- from typing import Optional
18
- from ..ui.app import app
19
-
20
- log = logging.getLogger('WebBrowser')
21
-
22
-
23
- def open_webapp(url: str) -> bool:
24
- """
25
- will try to open the web page as an app
26
- on failure, will open as a tab in default browser
27
-
28
- returns:
29
- """
30
- start = time.time()
31
- try:
32
- exe = get_default_browser_executable()
33
- if not exe:
34
- raise RuntimeError('Unable to find browser binary')
35
- log.debug(f'Opening {url} with {exe}')
36
-
37
- cmd = f'"{exe}" --app="{url}"'
38
- subprocess.run(cmd, check=True, shell=True)
39
-
40
- if time.time() - start < 2:
41
- log.debug(f'Unable to hook into closure of UI, listening for flask shutdown')
42
- return False
43
- return True
44
-
45
- except Exception as e:
46
- log.warning('Failed to open webpage as app, falling back to browser tab')
47
- log.debug(f'As app error: {e}')
48
- try:
49
- success = webbrowser.open(url)
50
- log.debug(f'Opened {url} in browser tab: {success}')
51
- if not success:
52
- raise RuntimeError('Unknown error while opening browser tab')
53
- except Exception as e:
54
- log.warning(f'Exhausted all options to open browser, you need to open manually')
55
- log.debug(f'As tab error: {e}')
56
- log.info(f'LANScape UI is running on {url}')
57
- return False
58
-
59
-
60
- def get_default_browser_executable() -> Optional[str]:
61
- if sys.platform.startswith("win"):
62
- try:
63
- import winreg
64
- # On Windows the HKEY_CLASSES_ROOT\http\shell\open\command key
65
- # holds the command for opening HTTP URLs.
66
- with winreg.OpenKey(winreg.HKEY_CLASSES_ROOT, r"http\shell\open\command") as key:
67
- cmd, _ = winreg.QueryValueEx(key, None)
68
- except Exception:
69
- return None
70
-
71
- # cmd usually looks like: '"C:\\Program Files\\Foo\\foo.exe" %1'
72
- m = re.match(r'\"?(.+?\.exe)\"?', cmd)
73
- return m.group(1) if m else None
74
-
75
- elif sys.platform.startswith("linux"):
76
- # First, find the .desktop file name
77
- desktop_file = None
78
- try:
79
- # Try xdg-mime
80
- p = subprocess.run(
81
- ["xdg-mime", "query", "default", "x-scheme-handler/http"],
82
- capture_output=True, text=True,
83
- check=True
84
- )
85
- desktop_file = p.stdout.strip()
86
- except subprocess.CalledProcessError:
87
- pass
88
-
89
- if not desktop_file:
90
- # Fallback to xdg-settings
91
- try:
92
- p = subprocess.run(
93
- ["xdg-settings", "get", "default-web-browser"],
94
- capture_output=True, text=True,
95
- check=True
96
- )
97
- desktop_file = p.stdout.strip()
98
- except subprocess.CalledProcessError:
99
- pass
100
-
101
- # Final fallback: BROWSER environment variable
102
- if not desktop_file:
103
- return os.environ.get("BROWSER")
104
-
105
- # Look for that .desktop file in standard locations
106
- search_paths = [
107
- os.path.expanduser("~/.local/share/applications"),
108
- "/usr/local/share/applications",
109
- "/usr/share/applications",
110
- ]
111
- for path in search_paths:
112
- full_path = os.path.join(path, desktop_file)
113
- if os.path.isfile(full_path):
114
- with open(full_path, encoding="utf-8", errors="ignore") as f:
115
- for line in f:
116
- if line.startswith("Exec="):
117
- exec_cmd = line[len("Exec="):].strip()
118
- # strip arguments like “%u”, “--flag”, etc.
119
- exec_cmd = exec_cmd.split()[0]
120
- exec_cmd = exec_cmd.split("%")[0]
121
- return exec_cmd
122
- return None
123
-
124
- elif sys.platform.startswith("darwin"):
125
- # macOS: try to find Chrome first for app mode support, fallback to default
126
- try:
127
- p = subprocess.run(
128
- ["mdfind", "kMDItemCFBundleIdentifier == 'com.google.Chrome'"],
129
- capture_output=True, text=True, check=True
130
- )
131
- chrome_paths = p.stdout.strip().split('\n')
132
- if chrome_paths and chrome_paths[0]:
133
- return f"{chrome_paths[0]}/Contents/MacOS/Google Chrome"
134
- except subprocess.CalledProcessError:
135
- pass
136
-
137
- # Fallback to system default
138
- return "/usr/bin/open"
139
-
140
- else:
141
- raise NotImplementedError(f"Unsupported platform: {sys.platform!r}")
@@ -1,27 +0,0 @@
1
- # Only used to import csv data - not during runtime
2
-
3
- import csv, json
4
-
5
- def main():
6
- ans = {}
7
- with open('mac-vendors-export.csv', 'r', encoding='utf-8') as f:
8
- data = csv.reader(f)
9
- services = csv_to_dict(data)
10
- for service in services:
11
- if service['Vendor Name'] and service['Mac Prefix']:
12
- try:
13
- ans[service['Mac Prefix']] = service['Vendor Name']
14
- except:
15
- pass
16
- with open('mac_db.json', 'w') as f:
17
- json.dump(ans, f, indent=2)
18
-
19
-
20
- def csv_to_dict(data):
21
- """
22
- Convert a CSV file to a dictionary.
23
- """
24
- header = next(data)
25
- return [dict(zip(header, row)) for row in data]
26
-
27
- main()
@@ -1,27 +0,0 @@
1
- # Only used to import csv data - not during runtime
2
-
3
- import csv, json
4
-
5
- def main():
6
- ans = {}
7
- with open('service-names-port-numbers.csv', 'r') as f:
8
- data = csv.reader(f)
9
- services = csv_to_dict(data)
10
- for service in services:
11
- if service['Service Name'] and service['Port Number']:
12
- try:
13
- ans[service['Port Number']] = service['Service Name']
14
- except:
15
- pass
16
- with open('valid_ports.json', 'w') as f:
17
- json.dump(ans, f, indent=2)
18
-
19
-
20
- def csv_to_dict(data):
21
- """
22
- Convert a CSV file to a dictionary.
23
- """
24
- header = next(data)
25
- return [dict(zip(header, row)) for row in data]
26
-
27
- main()
@@ -1,3 +0,0 @@
1
- from .test_api import ApiTestCase
2
- from .test_env import EnvTestCase
3
- from .test_library import LibraryTestCase
@@ -1,15 +0,0 @@
1
-
2
- from ..libraries.ip_parser import get_address_count
3
-
4
-
5
- def right_size_subnet(subnet: str):
6
- """
7
- Used to improve speed of test time
8
- """
9
- if get_address_count(subnet) > 500:
10
- parts = subnet.split('/')
11
- ip = parts[0]
12
- mask = int(parts[1])
13
- mask += 1
14
- return right_size_subnet(f"{ip}/{mask}")
15
- return subnet