lanscape 1.2.7a2__tar.gz → 1.2.8__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.
- {lanscape-1.2.7a2/src/lanscape.egg-info → lanscape-1.2.8}/PKG-INFO +3 -6
- {lanscape-1.2.7a2 → lanscape-1.2.8}/README.md +2 -4
- {lanscape-1.2.7a2 → lanscape-1.2.8}/pyproject.toml +1 -2
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/libraries/net_tools.py +8 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/libraries/runtime_args.py +8 -5
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/libraries/version_manager.py +3 -1
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/tests/__init__.py +0 -2
- lanscape-1.2.8/src/lanscape/tests/_helpers.py +15 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/ui/app.py +11 -7
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/ui/main.py +24 -16
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/ui/static/css/style.css +8 -1
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/ui/templates/base.html +7 -4
- {lanscape-1.2.7a2 → lanscape-1.2.8/src/lanscape.egg-info}/PKG-INFO +3 -6
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape.egg-info/SOURCES.txt +0 -3
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape.egg-info/requires.txt +0 -1
- lanscape-1.2.7a2/src/lanscape/tests/_helpers.py +0 -60
- lanscape-1.2.7a2/src/lanscape/tests/test_webview.py +0 -16
- lanscape-1.2.7a2/src/lanscape/ui/static/img/readme1.png +0 -0
- lanscape-1.2.7a2/src/lanscape/ui/webviewer.py +0 -22
- {lanscape-1.2.7a2 → lanscape-1.2.8}/LICENSE +0 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/MANIFEST.in +0 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/setup.cfg +0 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/__init__.py +0 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/__main__.py +0 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/libraries/app_scope.py +0 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/libraries/decorators.py +0 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/libraries/errors.py +0 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/libraries/ip_parser.py +0 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/libraries/logger.py +0 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/libraries/mac_lookup.py +0 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/libraries/port_manager.py +0 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/libraries/subnet_scan.py +0 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/resources/mac_addresses/convert_csv.py +0 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/resources/mac_addresses/mac_db.json +0 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/resources/ports/convert_csv.py +0 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/resources/ports/full.json +0 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/resources/ports/large.json +0 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/resources/ports/medium.json +0 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/resources/ports/small.json +0 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/tests/test_api.py +0 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/tests/test_env.py +0 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/tests/test_library.py +0 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/ui/blueprints/__init__.py +0 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/ui/blueprints/api/__init__.py +0 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/ui/blueprints/api/port.py +0 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/ui/blueprints/api/scan.py +0 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/ui/blueprints/api/tools.py +0 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/ui/blueprints/web/__init__.py +0 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/ui/blueprints/web/routes.py +0 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/ui/static/img/ico/android-chrome-192x192.png +0 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/ui/static/img/ico/android-chrome-512x512.png +0 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/ui/static/img/ico/apple-touch-icon.png +0 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/ui/static/img/ico/favicon-16x16.png +0 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/ui/static/img/ico/favicon-32x32.png +0 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/ui/static/img/ico/favicon.ico +0 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/ui/static/img/ico/site.webmanifest +0 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/ui/static/js/core.js +0 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/ui/static/js/layout-sizing.js +0 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/ui/static/js/main.js +0 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/ui/static/js/quietReload.js +0 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/ui/static/js/shutdown-server.js +0 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/ui/static/js/subnet-info.js +0 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/ui/static/js/subnet-selector.js +0 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/ui/static/lanscape.webmanifest +0 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/ui/templates/core/head.html +0 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/ui/templates/core/scripts.html +0 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/ui/templates/error.html +0 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/ui/templates/info.html +0 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/ui/templates/main.html +0 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/ui/templates/scan/export.html +0 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/ui/templates/scan/ip-table-row.html +0 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/ui/templates/scan/ip-table.html +0 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/ui/templates/scan/overview.html +0 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/ui/templates/scan/scan-error.html +0 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/ui/templates/scan.html +0 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/ui/templates/shutdown.html +0 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape.egg-info/dependency_links.txt +0 -0
- {lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: lanscape
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.8
|
|
4
4
|
Summary: A python based local network scanner
|
|
5
5
|
Author-email: Michael Dennis <michael@dipduo.com>
|
|
6
6
|
Project-URL: Homepage, https://github.com/mdennis281/py-lanscape
|
|
@@ -15,7 +15,6 @@ Requires-Dist: Flask<5.0,>=3.0
|
|
|
15
15
|
Requires-Dist: psutil<7.0,>=6.0
|
|
16
16
|
Requires-Dist: requests<3.0,>=2.32
|
|
17
17
|
Requires-Dist: setuptools
|
|
18
|
-
Requires-Dist: pywebview<6.0,>=4.2
|
|
19
18
|
Requires-Dist: scapy<3.0,>=2.3.2
|
|
20
19
|
Requires-Dist: tabulate==0.9.0
|
|
21
20
|
Requires-Dist: pytest
|
|
@@ -23,7 +22,7 @@ Requires-Dist: pytest
|
|
|
23
22
|
# LANscape
|
|
24
23
|
A python based local network scanner.
|
|
25
24
|
|
|
26
|
-

|
|
27
26
|
|
|
28
27
|
## Local Run
|
|
29
28
|
```sh
|
|
@@ -33,17 +32,15 @@ python -m lanscape
|
|
|
33
32
|
|
|
34
33
|
## Flags
|
|
35
34
|
- `--port <port number>` port of the flask app (default: 5001)
|
|
36
|
-
- `--nogui` run in web mode (default: false)
|
|
37
35
|
- `--reloader` essentially flask debug mode- good for local development (default: false)
|
|
38
36
|
- `--logfile` save log output to lanscape.log
|
|
39
37
|
- `--loglevel <level>` set the logger's log level (default: INFO)
|
|
40
|
-
- `--headless` similar to nogui but doesnt try to open a browser (default: false)
|
|
41
38
|
|
|
42
39
|
|
|
43
40
|
Examples:
|
|
44
41
|
```shell
|
|
45
42
|
python -m lanscape --reloader
|
|
46
|
-
python -m lanscape --
|
|
43
|
+
python -m lanscape --port 5002
|
|
47
44
|
python -m lanscape --logfile --loglevel DEBUG
|
|
48
45
|
```
|
|
49
46
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# LANscape
|
|
2
2
|
A python based local network scanner.
|
|
3
3
|
|
|
4
|
-

|
|
5
5
|
|
|
6
6
|
## Local Run
|
|
7
7
|
```sh
|
|
@@ -11,17 +11,15 @@ python -m lanscape
|
|
|
11
11
|
|
|
12
12
|
## Flags
|
|
13
13
|
- `--port <port number>` port of the flask app (default: 5001)
|
|
14
|
-
- `--nogui` run in web mode (default: false)
|
|
15
14
|
- `--reloader` essentially flask debug mode- good for local development (default: false)
|
|
16
15
|
- `--logfile` save log output to lanscape.log
|
|
17
16
|
- `--loglevel <level>` set the logger's log level (default: INFO)
|
|
18
|
-
- `--headless` similar to nogui but doesnt try to open a browser (default: false)
|
|
19
17
|
|
|
20
18
|
|
|
21
19
|
Examples:
|
|
22
20
|
```shell
|
|
23
21
|
python -m lanscape --reloader
|
|
24
|
-
python -m lanscape --
|
|
22
|
+
python -m lanscape --port 5002
|
|
25
23
|
python -m lanscape --logfile --loglevel DEBUG
|
|
26
24
|
```
|
|
27
25
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "lanscape"
|
|
3
|
-
version = "1.2.
|
|
3
|
+
version = "1.2.8"
|
|
4
4
|
authors = [
|
|
5
5
|
{ name="Michael Dennis", email="michael@dipduo.com" },
|
|
6
6
|
]
|
|
@@ -17,7 +17,6 @@ dependencies = [
|
|
|
17
17
|
"psutil>=6.0,<7.0",
|
|
18
18
|
"requests>=2.32,<3.0",
|
|
19
19
|
"setuptools",
|
|
20
|
-
"pywebview>=4.2,<6.0",
|
|
21
20
|
"scapy>=2.3.2,<3.0",
|
|
22
21
|
"tabulate==0.9.0",
|
|
23
22
|
"pytest"
|
|
@@ -131,6 +131,14 @@ class Device(IPAlive):
|
|
|
131
131
|
|
|
132
132
|
|
|
133
133
|
class MacSelector:
|
|
134
|
+
"""
|
|
135
|
+
Essentially filters out bad mac addresses
|
|
136
|
+
you send in a list of macs,
|
|
137
|
+
it will return the one that has been seen the least
|
|
138
|
+
(ideally meaning it is the most likely to be the correct one)
|
|
139
|
+
this was added because some lookups return multiple macs,
|
|
140
|
+
usually the hwid of a vpn tunnel etc
|
|
141
|
+
"""
|
|
134
142
|
def __init__(self):
|
|
135
143
|
self.macs = {}
|
|
136
144
|
|
|
@@ -7,20 +7,16 @@ from typing import Any, Dict
|
|
|
7
7
|
class RuntimeArgs:
|
|
8
8
|
reloader: bool = False
|
|
9
9
|
port: int = 5001
|
|
10
|
-
nogui: bool = False
|
|
11
10
|
logfile: bool = False
|
|
12
11
|
loglevel: str = 'INFO'
|
|
13
|
-
headless: bool = False
|
|
14
12
|
|
|
15
13
|
def parse_args() -> RuntimeArgs:
|
|
16
14
|
parser = argparse.ArgumentParser(description='LANscape')
|
|
17
15
|
|
|
18
16
|
parser.add_argument('--reloader', action='store_true', help='Use flask\'s reloader (helpful for local development)')
|
|
19
17
|
parser.add_argument('--port', type=int, default=5001, help='Port to run the webserver on')
|
|
20
|
-
parser.add_argument('--nogui', action='store_true', help='Run in standalone mode')
|
|
21
18
|
parser.add_argument('--logfile', action='store_true', help='Log output to lanscape.log')
|
|
22
|
-
parser.add_argument('--loglevel', default='INFO',
|
|
23
|
-
parser.add_argument('--headless', action="store_true",help="Similar to nogui, but doesnt try to open a browser. Good for running in a container.")
|
|
19
|
+
parser.add_argument('--loglevel', default='INFO', help='Set the log level')
|
|
24
20
|
|
|
25
21
|
# Parse the arguments
|
|
26
22
|
args = parser.parse_args()
|
|
@@ -33,5 +29,12 @@ def parse_args() -> RuntimeArgs:
|
|
|
33
29
|
# Only pass arguments that exist in the Args dataclass
|
|
34
30
|
filtered_args = {name: args_dict[name] for name in field_names if name in args_dict}
|
|
35
31
|
|
|
32
|
+
# Deal with loglevel formatting
|
|
33
|
+
filtered_args['loglevel'] = filtered_args['loglevel'].upper()
|
|
34
|
+
|
|
35
|
+
valid_levels = ['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL']
|
|
36
|
+
if filtered_args['loglevel'] not in valid_levels:
|
|
37
|
+
raise ValueError(f"Invalid log level: {filtered_args['loglevel']}. Must be one of: {valid_levels}")
|
|
38
|
+
|
|
36
39
|
# Return the dataclass instance with the dynamically assigned values
|
|
37
40
|
return RuntimeArgs(**filtered_args)
|
|
@@ -16,7 +16,9 @@ latest = None # used to 'remember' pypi version each runtime
|
|
|
16
16
|
def is_update_available(package=PACKAGE) -> bool:
|
|
17
17
|
installed = get_installed_version(package)
|
|
18
18
|
available = lookup_latest_version(package)
|
|
19
|
-
if installed == LOCAL_VERSION: return False #local
|
|
19
|
+
if installed == LOCAL_VERSION: return False # local
|
|
20
|
+
if 'a' in installed: return False # alpha
|
|
21
|
+
if 'b' in installed: return False # beta
|
|
20
22
|
|
|
21
23
|
return installed != available
|
|
22
24
|
|
|
@@ -0,0 +1,15 @@
|
|
|
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
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
from flask import Flask, render_template
|
|
2
|
+
from time import sleep
|
|
2
3
|
import multiprocessing
|
|
3
4
|
import traceback
|
|
4
5
|
import threading
|
|
@@ -92,15 +93,18 @@ def start_webserver_dameon(args: RuntimeArgs) -> multiprocessing.Process:
|
|
|
92
93
|
proc = threading.Thread(target=start_webserver, args=(args,))
|
|
93
94
|
proc.daemon = True # Kill thread when main thread exits
|
|
94
95
|
proc.start()
|
|
96
|
+
log.info('Flask server initializing as dameon')
|
|
97
|
+
sleep(2)
|
|
95
98
|
|
|
96
99
|
def start_webserver(args: RuntimeArgs) -> int:
|
|
97
|
-
|
|
98
|
-
host
|
|
99
|
-
port
|
|
100
|
-
debug
|
|
101
|
-
use_reloader
|
|
102
|
-
|
|
103
|
-
|
|
100
|
+
run_args = {
|
|
101
|
+
'host':'0.0.0.0',
|
|
102
|
+
'port':args.port,
|
|
103
|
+
'debug':args.reloader,
|
|
104
|
+
'use_reloader':args.reloader
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
app.run(**run_args)
|
|
104
108
|
|
|
105
109
|
if __name__ == "__main__":
|
|
106
110
|
start_webserver(True)
|
|
@@ -12,8 +12,8 @@ args = parse_args()
|
|
|
12
12
|
configure_logging(args.loglevel, args.logfile)
|
|
13
13
|
|
|
14
14
|
from ..libraries.version_manager import get_installed_version, is_update_available
|
|
15
|
-
from .webviewer import start_webview
|
|
16
15
|
from .app import start_webserver
|
|
16
|
+
import socket
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
log = logging.getLogger('core')
|
|
@@ -28,23 +28,23 @@ def main():
|
|
|
28
28
|
if not IS_FLASK_RELOAD:
|
|
29
29
|
log.info(f'LANscape v{get_installed_version()}')
|
|
30
30
|
try_check_update()
|
|
31
|
-
|
|
31
|
+
|
|
32
|
+
else:
|
|
32
33
|
log.info('Flask reloaded app.')
|
|
33
34
|
|
|
35
|
+
args.port = get_valid_port(args.port)
|
|
36
|
+
|
|
34
37
|
|
|
35
38
|
try:
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
args
|
|
41
|
-
)
|
|
39
|
+
|
|
40
|
+
no_gui(args)
|
|
41
|
+
|
|
42
|
+
log.info('Exiting...')
|
|
42
43
|
except Exception:
|
|
43
44
|
# showing error in debug only because this is handled gracefully
|
|
44
|
-
log.debug('Failed to start
|
|
45
|
+
log.debug('Failed to start. Traceback below')
|
|
45
46
|
log.debug(traceback.format_exc())
|
|
46
|
-
|
|
47
|
-
log.error('Unable to start webview client. Try running with flag --nogui')
|
|
47
|
+
|
|
48
48
|
|
|
49
49
|
|
|
50
50
|
def try_check_update():
|
|
@@ -67,23 +67,31 @@ def open_browser(url: str,wait=2):
|
|
|
67
67
|
time.sleep(wait)
|
|
68
68
|
webbrowser.open(url, new=2)
|
|
69
69
|
except:
|
|
70
|
-
srv_url = f"0.0.0.0:{url.split(':')[1]}"
|
|
71
70
|
log.debug(traceback.format_exc())
|
|
72
|
-
log.info(f'
|
|
71
|
+
log.info(f'Unable to open web browser, server running on {url}')
|
|
73
72
|
|
|
74
73
|
threading.Thread(target=do_open).start()
|
|
75
74
|
|
|
76
75
|
def no_gui(args: RuntimeArgs):
|
|
77
76
|
# determine if it was reloaded by flask debug reloader
|
|
78
77
|
# if it was, dont open the browser again
|
|
79
|
-
if not IS_FLASK_RELOAD
|
|
78
|
+
if not IS_FLASK_RELOAD:
|
|
80
79
|
open_browser(f'http://127.0.0.1:{args.port}')
|
|
81
|
-
|
|
82
|
-
|
|
80
|
+
log.info(f'Flask started: http://127.0.0.1:{args.port}')
|
|
81
|
+
|
|
83
82
|
start_webserver(
|
|
84
83
|
args
|
|
85
84
|
)
|
|
86
85
|
|
|
86
|
+
def get_valid_port(port: int):
|
|
87
|
+
"""
|
|
88
|
+
Get the first available port starting from the specified port
|
|
89
|
+
"""
|
|
90
|
+
while True:
|
|
91
|
+
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
|
92
|
+
if s.connect_ex(('localhost', port)) != 0:
|
|
93
|
+
return port
|
|
94
|
+
port += 1
|
|
87
95
|
|
|
88
96
|
if __name__ == "__main__":
|
|
89
97
|
main()
|
|
@@ -460,8 +460,15 @@ input[type="range"]::-moz-range-thumb {
|
|
|
460
460
|
}
|
|
461
461
|
|
|
462
462
|
.text-secondary {
|
|
463
|
-
color: var(--secondary-accent)
|
|
463
|
+
color: var(--secondary-accent) !important;
|
|
464
464
|
}
|
|
465
|
+
.text-danger {
|
|
466
|
+
color: var(--text-danger-color) !important;
|
|
467
|
+
}
|
|
468
|
+
.text-info {
|
|
469
|
+
color: var(--text-accent-color) !important;
|
|
470
|
+
}
|
|
471
|
+
|
|
465
472
|
.secondary-icon-btn {
|
|
466
473
|
color: var(--secondary-accent);
|
|
467
474
|
transition: .2s all ease-in-out;
|
|
@@ -11,10 +11,15 @@
|
|
|
11
11
|
<div class="version">
|
|
12
12
|
v{{app_version}}
|
|
13
13
|
{% if is_local %}
|
|
14
|
-
<span>(Local
|
|
14
|
+
<span class="text-info">(Local)</span>
|
|
15
15
|
{% elif update_available %}
|
|
16
16
|
<span>(Update Available)</span>
|
|
17
|
-
{% endif %}
|
|
17
|
+
{% endif %}
|
|
18
|
+
{% if 'a' in app_version %}
|
|
19
|
+
<span class="text-danger">(Alpha)</span>
|
|
20
|
+
{% elif 'b' in app_version %}
|
|
21
|
+
<span class="text-info">(Beta)</span>
|
|
22
|
+
{% endif %}
|
|
18
23
|
</div>
|
|
19
24
|
|
|
20
25
|
<div id="app-actions">
|
|
@@ -28,7 +33,6 @@
|
|
|
28
33
|
</span>
|
|
29
34
|
</a>
|
|
30
35
|
|
|
31
|
-
{% if runtime_args.get('nogui') or runtime_args.get('headless') %}
|
|
32
36
|
<a href="/shutdown-ui">
|
|
33
37
|
<span
|
|
34
38
|
id="power-button"
|
|
@@ -39,7 +43,6 @@
|
|
|
39
43
|
power_settings_new
|
|
40
44
|
</span>
|
|
41
45
|
</a>
|
|
42
|
-
{% endif %}
|
|
43
46
|
</div>
|
|
44
47
|
|
|
45
48
|
</footer>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: lanscape
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.8
|
|
4
4
|
Summary: A python based local network scanner
|
|
5
5
|
Author-email: Michael Dennis <michael@dipduo.com>
|
|
6
6
|
Project-URL: Homepage, https://github.com/mdennis281/py-lanscape
|
|
@@ -15,7 +15,6 @@ Requires-Dist: Flask<5.0,>=3.0
|
|
|
15
15
|
Requires-Dist: psutil<7.0,>=6.0
|
|
16
16
|
Requires-Dist: requests<3.0,>=2.32
|
|
17
17
|
Requires-Dist: setuptools
|
|
18
|
-
Requires-Dist: pywebview<6.0,>=4.2
|
|
19
18
|
Requires-Dist: scapy<3.0,>=2.3.2
|
|
20
19
|
Requires-Dist: tabulate==0.9.0
|
|
21
20
|
Requires-Dist: pytest
|
|
@@ -23,7 +22,7 @@ Requires-Dist: pytest
|
|
|
23
22
|
# LANscape
|
|
24
23
|
A python based local network scanner.
|
|
25
24
|
|
|
26
|
-

|
|
27
26
|
|
|
28
27
|
## Local Run
|
|
29
28
|
```sh
|
|
@@ -33,17 +32,15 @@ python -m lanscape
|
|
|
33
32
|
|
|
34
33
|
## Flags
|
|
35
34
|
- `--port <port number>` port of the flask app (default: 5001)
|
|
36
|
-
- `--nogui` run in web mode (default: false)
|
|
37
35
|
- `--reloader` essentially flask debug mode- good for local development (default: false)
|
|
38
36
|
- `--logfile` save log output to lanscape.log
|
|
39
37
|
- `--loglevel <level>` set the logger's log level (default: INFO)
|
|
40
|
-
- `--headless` similar to nogui but doesnt try to open a browser (default: false)
|
|
41
38
|
|
|
42
39
|
|
|
43
40
|
Examples:
|
|
44
41
|
```shell
|
|
45
42
|
python -m lanscape --reloader
|
|
46
|
-
python -m lanscape --
|
|
43
|
+
python -m lanscape --port 5002
|
|
47
44
|
python -m lanscape --logfile --loglevel DEBUG
|
|
48
45
|
```
|
|
49
46
|
|
|
@@ -32,10 +32,8 @@ src/lanscape/tests/_helpers.py
|
|
|
32
32
|
src/lanscape/tests/test_api.py
|
|
33
33
|
src/lanscape/tests/test_env.py
|
|
34
34
|
src/lanscape/tests/test_library.py
|
|
35
|
-
src/lanscape/tests/test_webview.py
|
|
36
35
|
src/lanscape/ui/app.py
|
|
37
36
|
src/lanscape/ui/main.py
|
|
38
|
-
src/lanscape/ui/webviewer.py
|
|
39
37
|
src/lanscape/ui/blueprints/__init__.py
|
|
40
38
|
src/lanscape/ui/blueprints/api/__init__.py
|
|
41
39
|
src/lanscape/ui/blueprints/api/port.py
|
|
@@ -45,7 +43,6 @@ src/lanscape/ui/blueprints/web/__init__.py
|
|
|
45
43
|
src/lanscape/ui/blueprints/web/routes.py
|
|
46
44
|
src/lanscape/ui/static/lanscape.webmanifest
|
|
47
45
|
src/lanscape/ui/static/css/style.css
|
|
48
|
-
src/lanscape/ui/static/img/readme1.png
|
|
49
46
|
src/lanscape/ui/static/img/ico/android-chrome-192x192.png
|
|
50
47
|
src/lanscape/ui/static/img/ico/android-chrome-512x512.png
|
|
51
48
|
src/lanscape/ui/static/img/ico/apple-touch-icon.png
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
from ..libraries.ip_parser import get_address_count
|
|
3
|
-
import webview, time
|
|
4
|
-
|
|
5
|
-
import warnings
|
|
6
|
-
|
|
7
|
-
from concurrent.futures import ThreadPoolExecutor, Future
|
|
8
|
-
def right_size_subnet(subnet: str):
|
|
9
|
-
"""
|
|
10
|
-
Used to improve speed of test time
|
|
11
|
-
"""
|
|
12
|
-
if get_address_count(subnet) > 500:
|
|
13
|
-
parts = subnet.split('/')
|
|
14
|
-
ip = parts[0]
|
|
15
|
-
mask = int(parts[1])
|
|
16
|
-
mask += 1
|
|
17
|
-
return right_size_subnet(f"{ip}/{mask}")
|
|
18
|
-
return subnet
|
|
19
|
-
|
|
20
|
-
def webview_client(title, url):
|
|
21
|
-
def decorator(func):
|
|
22
|
-
def wrapper(*args, **kwargs):
|
|
23
|
-
baseclass = args[0]
|
|
24
|
-
|
|
25
|
-
window = webview.create_window(title, url)
|
|
26
|
-
|
|
27
|
-
# Create a Future object to communicate results/exceptions
|
|
28
|
-
future = Future()
|
|
29
|
-
|
|
30
|
-
# Define the function to run in the secondary thread
|
|
31
|
-
def test_function():
|
|
32
|
-
# disable resource warning occuring in py >=3.13
|
|
33
|
-
warnings.filterwarnings("ignore", category=ResourceWarning)
|
|
34
|
-
|
|
35
|
-
try:
|
|
36
|
-
# Call the decorated function
|
|
37
|
-
func(baseclass, window, **kwargs)
|
|
38
|
-
future.set_result("Completed Successfully")
|
|
39
|
-
except Exception as e:
|
|
40
|
-
# Set the exception in the Future
|
|
41
|
-
future.set_exception(e)
|
|
42
|
-
finally:
|
|
43
|
-
# Close the WebView window
|
|
44
|
-
if window is not None:
|
|
45
|
-
window.destroy()
|
|
46
|
-
|
|
47
|
-
# Define a function to start the thread
|
|
48
|
-
def start_test_function():
|
|
49
|
-
# Run the function in a secondary thread
|
|
50
|
-
with ThreadPoolExecutor() as executor:
|
|
51
|
-
executor.submit(test_function)
|
|
52
|
-
|
|
53
|
-
# Start the WebView and execute the thread alongside it
|
|
54
|
-
webview.start(start_test_function)
|
|
55
|
-
|
|
56
|
-
# Retrieve the result or exception from the Future
|
|
57
|
-
future.result()
|
|
58
|
-
|
|
59
|
-
return wrapper
|
|
60
|
-
return decorator
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import webview
|
|
2
|
-
from ._helpers import webview_client
|
|
3
|
-
import unittest
|
|
4
|
-
from time import sleep
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class WebViewTestCase(unittest.TestCase):
|
|
9
|
-
|
|
10
|
-
@webview_client('Test Window','https://google.com')
|
|
11
|
-
def test_webview_launch(self, client: webview.Window):
|
|
12
|
-
# This test checks that the window has been created successfully
|
|
13
|
-
sleep(2)
|
|
14
|
-
self.assertIsNotNone(client,msg="WebView window failed to create.")
|
|
15
|
-
self.assertEqual(client.title,'Test Window',msg='WebView window title did not match.')
|
|
16
|
-
self.assertIn('google.com',client.real_url,msg=f'URL mismatch')
|
|
Binary file
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import webview
|
|
2
|
-
from .app import start_webserver_dameon
|
|
3
|
-
from ..libraries.runtime_args import RuntimeArgs
|
|
4
|
-
from time import sleep
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
def start_webview(args: RuntimeArgs) -> None:
|
|
9
|
-
# Start Flask server in a separate thread
|
|
10
|
-
start_webserver_dameon(args)
|
|
11
|
-
|
|
12
|
-
# Start the Pywebview window
|
|
13
|
-
webview.create_window('LANscape', f'http://127.0.0.1:{args.port}')
|
|
14
|
-
sleep(1)
|
|
15
|
-
webview.start()
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
if __name__ == "__main__":
|
|
20
|
-
# Start Flask server in a separate thread
|
|
21
|
-
start_webview(True)
|
|
22
|
-
|
|
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
|
{lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/ui/static/img/ico/android-chrome-192x192.png
RENAMED
|
File without changes
|
{lanscape-1.2.7a2 → lanscape-1.2.8}/src/lanscape/ui/static/img/ico/android-chrome-512x512.png
RENAMED
|
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
|