lanscape 1.3.9__tar.gz → 1.4.0__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.
Potentially problematic release.
This version of lanscape might be problematic. Click here for more details.
- {lanscape-1.3.9/lanscape.egg-info → lanscape-1.4.0}/PKG-INFO +1 -1
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/libraries/decorators.py +29 -3
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/libraries/net_tools.py +10 -25
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/libraries/version_manager.py +15 -18
- {lanscape-1.3.9 → lanscape-1.4.0/lanscape.egg-info}/PKG-INFO +1 -1
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape.egg-info/SOURCES.txt +1 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/pyproject.toml +1 -1
- lanscape-1.4.0/tests/test_decorators.py +29 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/LICENSE +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/MANIFEST.in +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/README.md +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/__init__.py +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/__main__.py +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/libraries/__init__.py +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/libraries/app_scope.py +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/libraries/device_alive.py +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/libraries/errors.py +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/libraries/ip_parser.py +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/libraries/logger.py +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/libraries/mac_lookup.py +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/libraries/port_manager.py +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/libraries/runtime_args.py +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/libraries/scan_config.py +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/libraries/service_scan.py +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/libraries/subnet_scan.py +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/libraries/web_browser.py +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/resources/mac_addresses/convert_csv.py +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/resources/mac_addresses/mac_db.json +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/resources/ports/convert_csv.py +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/resources/ports/full.json +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/resources/ports/large.json +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/resources/ports/medium.json +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/resources/ports/small.json +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/resources/services/definitions.jsonc +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/ui/__init__.py +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/ui/app.py +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/ui/blueprints/__init__.py +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/ui/blueprints/api/__init__.py +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/ui/blueprints/api/port.py +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/ui/blueprints/api/scan.py +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/ui/blueprints/api/tools.py +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/ui/blueprints/web/__init__.py +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/ui/blueprints/web/routes.py +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/ui/main.py +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/ui/shutdown_handler.py +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/ui/static/css/style.css +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/ui/static/img/ico/android-chrome-192x192.png +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/ui/static/img/ico/android-chrome-512x512.png +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/ui/static/img/ico/apple-touch-icon.png +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/ui/static/img/ico/favicon-16x16.png +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/ui/static/img/ico/favicon-32x32.png +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/ui/static/img/ico/favicon.ico +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/ui/static/img/ico/site.webmanifest +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/ui/static/js/core.js +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/ui/static/js/layout-sizing.js +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/ui/static/js/main.js +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/ui/static/js/on-tab-close.js +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/ui/static/js/quietReload.js +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/ui/static/js/scan-config.js +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/ui/static/js/shutdown-server.js +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/ui/static/js/subnet-info.js +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/ui/static/js/subnet-selector.js +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/ui/static/lanscape.webmanifest +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/ui/templates/base.html +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/ui/templates/core/head.html +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/ui/templates/core/scripts.html +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/ui/templates/error.html +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/ui/templates/info.html +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/ui/templates/main.html +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/ui/templates/scan/config.html +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/ui/templates/scan/export.html +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/ui/templates/scan/ip-table-row.html +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/ui/templates/scan/ip-table.html +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/ui/templates/scan/overview.html +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/ui/templates/scan/scan-error.html +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/ui/templates/scan.html +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape/ui/templates/shutdown.html +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape.egg-info/dependency_links.txt +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape.egg-info/requires.txt +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/lanscape.egg-info/top_level.txt +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/setup.cfg +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/tests/test_api.py +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/tests/test_env.py +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/tests/test_library.py +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/tests/test_logging.py +0 -0
- {lanscape-1.3.9 → lanscape-1.4.0}/tests/test_utils.py +0 -0
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
"""
|
|
3
|
-
Decorators and job tracking utilities for Lanscape.
|
|
4
|
-
"""
|
|
2
|
+
"""Decorators and job tracking utilities for Lanscape."""
|
|
5
3
|
|
|
6
4
|
from time import time
|
|
7
5
|
from dataclasses import dataclass, field
|
|
@@ -10,9 +8,37 @@ from collections import defaultdict
|
|
|
10
8
|
import inspect
|
|
11
9
|
import functools
|
|
12
10
|
import concurrent.futures
|
|
11
|
+
import logging
|
|
13
12
|
from tabulate import tabulate
|
|
14
13
|
|
|
15
14
|
|
|
15
|
+
log = logging.getLogger(__name__)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def run_once(func):
|
|
19
|
+
"""Ensure a function executes only once and cache the result."""
|
|
20
|
+
|
|
21
|
+
cache_attr = "_run_once_cache"
|
|
22
|
+
ran_attr = "_run_once_ran"
|
|
23
|
+
|
|
24
|
+
@functools.wraps(func)
|
|
25
|
+
def wrapper(*args, **kwargs):
|
|
26
|
+
if getattr(wrapper, ran_attr, False):
|
|
27
|
+
return getattr(wrapper, cache_attr)
|
|
28
|
+
|
|
29
|
+
start = time()
|
|
30
|
+
result = func(*args, **kwargs)
|
|
31
|
+
elapsed = time() - start
|
|
32
|
+
|
|
33
|
+
setattr(wrapper, cache_attr, result)
|
|
34
|
+
setattr(wrapper, ran_attr, True)
|
|
35
|
+
|
|
36
|
+
log.debug("run_once executed %s in %.4fs", func.__qualname__, elapsed)
|
|
37
|
+
return result
|
|
38
|
+
|
|
39
|
+
return wrapper
|
|
40
|
+
|
|
41
|
+
|
|
16
42
|
@dataclass
|
|
17
43
|
class JobStats:
|
|
18
44
|
"""
|
|
@@ -18,7 +18,7 @@ from lanscape.libraries.service_scan import scan_service
|
|
|
18
18
|
from lanscape.libraries.mac_lookup import MacLookup, get_macs
|
|
19
19
|
from lanscape.libraries.ip_parser import get_address_count, MAX_IPS_ALLOWED
|
|
20
20
|
from lanscape.libraries.errors import DeviceError
|
|
21
|
-
from lanscape.libraries.decorators import job_tracker
|
|
21
|
+
from lanscape.libraries.decorators import job_tracker, run_once
|
|
22
22
|
|
|
23
23
|
log = logging.getLogger('NetTools')
|
|
24
24
|
mac_lookup = MacLookup()
|
|
@@ -459,32 +459,17 @@ def smart_select_primary_subnet(subnets: List[dict] = None) -> str:
|
|
|
459
459
|
return selected.get("subnet", "")
|
|
460
460
|
|
|
461
461
|
|
|
462
|
-
|
|
463
|
-
"""
|
|
464
|
-
Singleton class to check if ARP requests are supported on the current system.
|
|
465
|
-
The check is only performed once.
|
|
466
|
-
"""
|
|
467
|
-
_supported = None
|
|
468
|
-
|
|
469
|
-
@classmethod
|
|
470
|
-
def is_supported(cls):
|
|
471
|
-
"""one time check if ARP requests are supported on this system"""
|
|
472
|
-
if cls._supported is not None:
|
|
473
|
-
return cls._supported
|
|
474
|
-
try:
|
|
475
|
-
arp_request = ARP(pdst='0.0.0.0')
|
|
476
|
-
broadcast = Ether(dst="ff:ff:ff:ff:ff:ff")
|
|
477
|
-
packet = broadcast / arp_request
|
|
478
|
-
srp(packet, timeout=0, verbose=False)
|
|
479
|
-
cls._supported = True
|
|
480
|
-
except (Scapy_Exception, PermissionError, RuntimeError):
|
|
481
|
-
cls._supported = False
|
|
482
|
-
return cls._supported
|
|
483
|
-
|
|
484
|
-
|
|
462
|
+
@run_once
|
|
485
463
|
def is_arp_supported():
|
|
486
464
|
"""
|
|
487
465
|
Check if ARP requests are supported on the current system.
|
|
488
466
|
Only runs the check once.
|
|
489
467
|
"""
|
|
490
|
-
|
|
468
|
+
try:
|
|
469
|
+
arp_request = ARP(pdst='0.0.0.0')
|
|
470
|
+
broadcast = Ether(dst="ff:ff:ff:ff:ff:ff")
|
|
471
|
+
packet = broadcast / arp_request
|
|
472
|
+
srp(packet, timeout=0, verbose=False)
|
|
473
|
+
return True
|
|
474
|
+
except (Scapy_Exception, PermissionError, RuntimeError):
|
|
475
|
+
return False
|
|
@@ -11,17 +11,14 @@ from random import randint
|
|
|
11
11
|
|
|
12
12
|
import requests
|
|
13
13
|
|
|
14
|
-
from .app_scope import is_local_run
|
|
14
|
+
from lanscape.libraries.app_scope import is_local_run
|
|
15
|
+
from lanscape.libraries.decorators import run_once
|
|
15
16
|
|
|
16
17
|
log = logging.getLogger('VersionManager')
|
|
17
18
|
|
|
18
19
|
PACKAGE = 'lanscape'
|
|
19
20
|
LOCAL_VERSION = '0.0.0'
|
|
20
21
|
|
|
21
|
-
# Used to cache PyPI version during runtime
|
|
22
|
-
LATEST_VERSION = None
|
|
23
|
-
|
|
24
|
-
|
|
25
22
|
def is_update_available(package=PACKAGE) -> bool:
|
|
26
23
|
"""
|
|
27
24
|
Check if an update is available for the package.
|
|
@@ -49,6 +46,7 @@ def is_update_available(package=PACKAGE) -> bool:
|
|
|
49
46
|
return installed != available
|
|
50
47
|
|
|
51
48
|
|
|
49
|
+
@run_once
|
|
52
50
|
def lookup_latest_version(package=PACKAGE):
|
|
53
51
|
"""
|
|
54
52
|
Retrieve the latest version of the package from PyPI.
|
|
@@ -62,19 +60,18 @@ def lookup_latest_version(package=PACKAGE):
|
|
|
62
60
|
The latest version string from PyPI or None if retrieval fails
|
|
63
61
|
"""
|
|
64
62
|
# Fetch the latest version from PyPI
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
return LATEST_VERSION
|
|
63
|
+
no_cache = f'?cachebust={randint(0, 6969)}'
|
|
64
|
+
url = f"https://pypi.org/pypi/{package}/json{no_cache}"
|
|
65
|
+
try:
|
|
66
|
+
response = requests.get(url, timeout=3)
|
|
67
|
+
response.raise_for_status() # Raise an exception for HTTP errors
|
|
68
|
+
latest_version = response.json()['info']['version']
|
|
69
|
+
log.debug(f'Latest pypi version: {latest_version}')
|
|
70
|
+
return latest_version
|
|
71
|
+
except BaseException:
|
|
72
|
+
log.debug(traceback.format_exc())
|
|
73
|
+
log.warning('Unable to fetch package version from PyPi')
|
|
74
|
+
return None
|
|
78
75
|
|
|
79
76
|
|
|
80
77
|
def get_installed_version(package=PACKAGE):
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""Tests for helper decorators used throughout the project."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
|
|
5
|
+
from lanscape.libraries.decorators import run_once
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def test_run_once_caches_result_and_logs_once(caplog):
|
|
9
|
+
"""run_once should execute only one time and cache the return value."""
|
|
10
|
+
|
|
11
|
+
caplog.set_level(logging.DEBUG)
|
|
12
|
+
|
|
13
|
+
call_count = {"count": 0}
|
|
14
|
+
|
|
15
|
+
@run_once
|
|
16
|
+
def sample_function(value):
|
|
17
|
+
call_count["count"] += 1
|
|
18
|
+
return value * 2
|
|
19
|
+
|
|
20
|
+
first = sample_function(3)
|
|
21
|
+
second = sample_function(5)
|
|
22
|
+
|
|
23
|
+
assert first == 6
|
|
24
|
+
assert second == 6
|
|
25
|
+
assert call_count["count"] == 1
|
|
26
|
+
|
|
27
|
+
messages = [record.message for record in caplog.records]
|
|
28
|
+
assert any("run_once executed" in record and "sample_function" in record for record in messages)
|
|
29
|
+
assert sum("run_once executed" in record for record in messages) == 1
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|