lanscape 1.3.1a8__tar.gz → 1.3.2a6__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.

Files changed (82) hide show
  1. lanscape-1.3.2a6/MANIFEST.in +4 -0
  2. {lanscape-1.3.1a8/src/lanscape.egg-info → lanscape-1.3.2a6}/PKG-INFO +4 -3
  3. {lanscape-1.3.1a8/src → lanscape-1.3.2a6}/lanscape/__init__.py +4 -1
  4. {lanscape-1.3.1a8/src → lanscape-1.3.2a6}/lanscape/__main__.py +4 -1
  5. {lanscape-1.3.1a8/src → lanscape-1.3.2a6}/lanscape/ui/static/css/style.css +1 -1
  6. {lanscape-1.3.1a8/src → lanscape-1.3.2a6}/lanscape/ui/templates/core/scripts.html +1 -1
  7. {lanscape-1.3.1a8/src → lanscape-1.3.2a6}/lanscape/ui/templates/info.html +1 -1
  8. {lanscape-1.3.1a8/src → lanscape-1.3.2a6}/lanscape/ui/templates/main.html +6 -4
  9. {lanscape-1.3.1a8 → lanscape-1.3.2a6/lanscape.egg-info}/PKG-INFO +4 -3
  10. lanscape-1.3.2a6/lanscape.egg-info/SOURCES.txt +51 -0
  11. {lanscape-1.3.1a8/src → lanscape-1.3.2a6}/lanscape.egg-info/requires.txt +1 -1
  12. {lanscape-1.3.1a8 → lanscape-1.3.2a6}/pyproject.toml +31 -26
  13. {lanscape-1.3.1a8/src/lanscape → lanscape-1.3.2a6}/tests/test_api.py +38 -36
  14. {lanscape-1.3.1a8/src/lanscape → lanscape-1.3.2a6}/tests/test_env.py +8 -11
  15. lanscape-1.3.2a6/tests/test_library.py +84 -0
  16. lanscape-1.3.2a6/tests/test_utils.py +86 -0
  17. lanscape-1.3.1a8/MANIFEST.in +0 -4
  18. lanscape-1.3.1a8/src/lanscape/libraries/app_scope.py +0 -70
  19. lanscape-1.3.1a8/src/lanscape/libraries/decorators.py +0 -75
  20. lanscape-1.3.1a8/src/lanscape/libraries/errors.py +0 -29
  21. lanscape-1.3.1a8/src/lanscape/libraries/ip_parser.py +0 -65
  22. lanscape-1.3.1a8/src/lanscape/libraries/logger.py +0 -42
  23. lanscape-1.3.1a8/src/lanscape/libraries/mac_lookup.py +0 -69
  24. lanscape-1.3.1a8/src/lanscape/libraries/net_tools.py +0 -480
  25. lanscape-1.3.1a8/src/lanscape/libraries/port_manager.py +0 -59
  26. lanscape-1.3.1a8/src/lanscape/libraries/runtime_args.py +0 -44
  27. lanscape-1.3.1a8/src/lanscape/libraries/service_scan.py +0 -51
  28. lanscape-1.3.1a8/src/lanscape/libraries/subnet_scan.py +0 -373
  29. lanscape-1.3.1a8/src/lanscape/libraries/version_manager.py +0 -54
  30. lanscape-1.3.1a8/src/lanscape/libraries/web_browser.py +0 -141
  31. lanscape-1.3.1a8/src/lanscape/resources/mac_addresses/convert_csv.py +0 -27
  32. lanscape-1.3.1a8/src/lanscape/resources/ports/convert_csv.py +0 -27
  33. lanscape-1.3.1a8/src/lanscape/tests/__init__.py +0 -3
  34. lanscape-1.3.1a8/src/lanscape/tests/_helpers.py +0 -15
  35. lanscape-1.3.1a8/src/lanscape/tests/test_library.py +0 -53
  36. lanscape-1.3.1a8/src/lanscape/ui/app.py +0 -122
  37. lanscape-1.3.1a8/src/lanscape/ui/blueprints/__init__.py +0 -7
  38. lanscape-1.3.1a8/src/lanscape/ui/blueprints/api/__init__.py +0 -5
  39. lanscape-1.3.1a8/src/lanscape/ui/blueprints/api/port.py +0 -27
  40. lanscape-1.3.1a8/src/lanscape/ui/blueprints/api/scan.py +0 -69
  41. lanscape-1.3.1a8/src/lanscape/ui/blueprints/api/tools.py +0 -30
  42. lanscape-1.3.1a8/src/lanscape/ui/blueprints/web/__init__.py +0 -5
  43. lanscape-1.3.1a8/src/lanscape/ui/blueprints/web/routes.py +0 -74
  44. lanscape-1.3.1a8/src/lanscape/ui/main.py +0 -138
  45. lanscape-1.3.1a8/src/lanscape.egg-info/SOURCES.txt +0 -76
  46. {lanscape-1.3.1a8 → lanscape-1.3.2a6}/LICENSE +0 -0
  47. {lanscape-1.3.1a8 → lanscape-1.3.2a6}/README.md +0 -0
  48. {lanscape-1.3.1a8/src → lanscape-1.3.2a6}/lanscape/resources/mac_addresses/mac_db.json +0 -0
  49. {lanscape-1.3.1a8/src → lanscape-1.3.2a6}/lanscape/resources/ports/full.json +0 -0
  50. {lanscape-1.3.1a8/src → lanscape-1.3.2a6}/lanscape/resources/ports/large.json +0 -0
  51. {lanscape-1.3.1a8/src → lanscape-1.3.2a6}/lanscape/resources/ports/medium.json +0 -0
  52. {lanscape-1.3.1a8/src → lanscape-1.3.2a6}/lanscape/resources/ports/small.json +0 -0
  53. {lanscape-1.3.1a8/src → lanscape-1.3.2a6}/lanscape/resources/services/definitions.jsonc +0 -0
  54. {lanscape-1.3.1a8/src → lanscape-1.3.2a6}/lanscape/ui/static/img/ico/android-chrome-192x192.png +0 -0
  55. {lanscape-1.3.1a8/src → lanscape-1.3.2a6}/lanscape/ui/static/img/ico/android-chrome-512x512.png +0 -0
  56. {lanscape-1.3.1a8/src → lanscape-1.3.2a6}/lanscape/ui/static/img/ico/apple-touch-icon.png +0 -0
  57. {lanscape-1.3.1a8/src → lanscape-1.3.2a6}/lanscape/ui/static/img/ico/favicon-16x16.png +0 -0
  58. {lanscape-1.3.1a8/src → lanscape-1.3.2a6}/lanscape/ui/static/img/ico/favicon-32x32.png +0 -0
  59. {lanscape-1.3.1a8/src → lanscape-1.3.2a6}/lanscape/ui/static/img/ico/favicon.ico +0 -0
  60. {lanscape-1.3.1a8/src → lanscape-1.3.2a6}/lanscape/ui/static/img/ico/site.webmanifest +0 -0
  61. {lanscape-1.3.1a8/src → lanscape-1.3.2a6}/lanscape/ui/static/js/core.js +0 -0
  62. {lanscape-1.3.1a8/src → lanscape-1.3.2a6}/lanscape/ui/static/js/layout-sizing.js +0 -0
  63. {lanscape-1.3.1a8/src → lanscape-1.3.2a6}/lanscape/ui/static/js/main.js +0 -0
  64. {lanscape-1.3.1a8/src → lanscape-1.3.2a6}/lanscape/ui/static/js/on-tab-close.js +0 -0
  65. {lanscape-1.3.1a8/src → lanscape-1.3.2a6}/lanscape/ui/static/js/quietReload.js +0 -0
  66. {lanscape-1.3.1a8/src → lanscape-1.3.2a6}/lanscape/ui/static/js/shutdown-server.js +0 -0
  67. {lanscape-1.3.1a8/src → lanscape-1.3.2a6}/lanscape/ui/static/js/subnet-info.js +0 -0
  68. {lanscape-1.3.1a8/src → lanscape-1.3.2a6}/lanscape/ui/static/js/subnet-selector.js +0 -0
  69. {lanscape-1.3.1a8/src → lanscape-1.3.2a6}/lanscape/ui/static/lanscape.webmanifest +0 -0
  70. {lanscape-1.3.1a8/src → lanscape-1.3.2a6}/lanscape/ui/templates/base.html +0 -0
  71. {lanscape-1.3.1a8/src → lanscape-1.3.2a6}/lanscape/ui/templates/core/head.html +0 -0
  72. {lanscape-1.3.1a8/src → lanscape-1.3.2a6}/lanscape/ui/templates/error.html +0 -0
  73. {lanscape-1.3.1a8/src → lanscape-1.3.2a6}/lanscape/ui/templates/scan/export.html +0 -0
  74. {lanscape-1.3.1a8/src → lanscape-1.3.2a6}/lanscape/ui/templates/scan/ip-table-row.html +0 -0
  75. {lanscape-1.3.1a8/src → lanscape-1.3.2a6}/lanscape/ui/templates/scan/ip-table.html +0 -0
  76. {lanscape-1.3.1a8/src → lanscape-1.3.2a6}/lanscape/ui/templates/scan/overview.html +0 -0
  77. {lanscape-1.3.1a8/src → lanscape-1.3.2a6}/lanscape/ui/templates/scan/scan-error.html +0 -0
  78. {lanscape-1.3.1a8/src → lanscape-1.3.2a6}/lanscape/ui/templates/scan.html +0 -0
  79. {lanscape-1.3.1a8/src → lanscape-1.3.2a6}/lanscape/ui/templates/shutdown.html +0 -0
  80. {lanscape-1.3.1a8/src → lanscape-1.3.2a6}/lanscape.egg-info/dependency_links.txt +0 -0
  81. {lanscape-1.3.1a8/src → lanscape-1.3.2a6}/lanscape.egg-info/top_level.txt +0 -0
  82. {lanscape-1.3.1a8 → lanscape-1.3.2a6}/setup.cfg +0 -0
@@ -0,0 +1,4 @@
1
+ recursive-include lanscape/resources *.json
2
+ recursive-include lanscape/resources *.jsonc
3
+ recursive-include lanscape/ui/templates *.html
4
+ recursive-include lanscape/ui/static *
@@ -1,12 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lanscape
3
- Version: 1.3.1a8
3
+ Version: 1.3.2a6
4
4
  Summary: A python based local network scanner
5
5
  Author-email: Michael Dennis <michael@dipduo.com>
6
+ License-Expression: MIT
6
7
  Project-URL: Homepage, https://github.com/mdennis281/py-lanscape
7
8
  Project-URL: Issues, https://github.com/mdennis281/py-lanscape/issues
9
+ Keywords: network,scanner,lan,local,python
8
10
  Classifier: Programming Language :: Python :: 3
9
- Classifier: License :: OSI Approved :: MIT License
10
11
  Classifier: Operating System :: OS Independent
11
12
  Requires-Python: >=3.8
12
13
  Description-Content-Type: text/markdown
@@ -17,7 +18,7 @@ Requires-Dist: requests<3.0,>=2.32
17
18
  Requires-Dist: setuptools
18
19
  Requires-Dist: scapy<3.0,>=2.3.2
19
20
  Requires-Dist: tabulate==0.9.0
20
- Requires-Dist: pytest
21
+ Requires-Dist: pydantic
21
22
  Dynamic: license-file
22
23
 
23
24
  # LANscape
@@ -1,3 +1,6 @@
1
+ """
2
+ Local network scanner
3
+ """
1
4
  from .libraries.subnet_scan import (
2
5
  SubnetScanner,
3
6
  ScanConfig,
@@ -6,4 +9,4 @@ from .libraries.subnet_scan import (
6
9
 
7
10
  from .libraries.port_manager import PortManager
8
11
 
9
- from .libraries import net_tools
12
+ from .libraries import net_tools
@@ -1,6 +1,9 @@
1
+ """
2
+ Lanscape module entry point.
3
+ """
1
4
  from .ui.main import main
2
5
 
3
6
  # leveraged when calling as module ie "python -m lanscape"
4
7
 
5
8
  if __name__ == "__main__":
6
- main()
9
+ main()
@@ -56,7 +56,7 @@ body:has(.submodule) footer {
56
56
  background-color: var(--primary-bg);
57
57
  border-radius: 8px;
58
58
  box-shadow: 0 0 10px var(--box-shadow);
59
- width: 90%;
59
+ width: 95%;
60
60
  margin-top: 10px;
61
61
  overflow: hidden;
62
62
  }
@@ -4,6 +4,6 @@
4
4
  <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.9.2/dist/umd/popper.min.js"></script>
5
5
  <script src="{{ url_for('static', filename='js/core.js') }}"></script>
6
6
 
7
- {% if not section is defined %}
7
+ {% if section is not defined %}
8
8
  <script src="{{ url_for('static', filename='js/on-tab-close.js') }}"></script>
9
9
  {% endif %}
@@ -4,7 +4,7 @@
4
4
  <div id="header">
5
5
  <!-- Header and Scan Submission Inline -->
6
6
  <div class="d-flex justify-content-start align-items-center">
7
- <a href="/" class="text-decoration-none">
7
+ <a href="/" class="text-decoration-none" aria-label="Go to homepage">
8
8
  <h1 class="title">
9
9
  <span>LAN</span>scape
10
10
  </h1>
@@ -4,9 +4,11 @@
4
4
  <div id="header">
5
5
  <!-- Header and Scan Submission Inline -->
6
6
  <div class="d-flex justify-content-between align-items-center flex-wrap">
7
- <h1 class="title" onclick="location.reload()">
8
- <span>LAN</span>scape
9
- </h1>
7
+ <a href="/" class="text-decoration-none" aria-label="Go to homepage">
8
+ <h1 class="title">
9
+ <span>LAN</span>scape
10
+ </h1>
11
+ </a>
10
12
  <!-- Form -->
11
13
  <form id="scan-form" class="d-flex align-items-end">
12
14
  <div class="form-group me-2">
@@ -52,7 +54,7 @@
52
54
  <!-- ARP Error -->
53
55
  <div id="arp-error" class="{{ 'div-hide' if is_arp_supported else '' }}">
54
56
  <span>
55
- Unable to discover devices using ARP. Device discovery is degraded.
57
+ Unable to use ARP lookup. Device discovery is degraded.
56
58
  <a target="_blank" href="https://github.com/mdennis281/LANscape/blob/main/support/arp-issues.md">Steps to fix</a>
57
59
  </span>
58
60
  </div>
@@ -1,12 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lanscape
3
- Version: 1.3.1a8
3
+ Version: 1.3.2a6
4
4
  Summary: A python based local network scanner
5
5
  Author-email: Michael Dennis <michael@dipduo.com>
6
+ License-Expression: MIT
6
7
  Project-URL: Homepage, https://github.com/mdennis281/py-lanscape
7
8
  Project-URL: Issues, https://github.com/mdennis281/py-lanscape/issues
9
+ Keywords: network,scanner,lan,local,python
8
10
  Classifier: Programming Language :: Python :: 3
9
- Classifier: License :: OSI Approved :: MIT License
10
11
  Classifier: Operating System :: OS Independent
11
12
  Requires-Python: >=3.8
12
13
  Description-Content-Type: text/markdown
@@ -17,7 +18,7 @@ Requires-Dist: requests<3.0,>=2.32
17
18
  Requires-Dist: setuptools
18
19
  Requires-Dist: scapy<3.0,>=2.3.2
19
20
  Requires-Dist: tabulate==0.9.0
20
- Requires-Dist: pytest
21
+ Requires-Dist: pydantic
21
22
  Dynamic: license-file
22
23
 
23
24
  # LANscape
@@ -0,0 +1,51 @@
1
+ LICENSE
2
+ MANIFEST.in
3
+ README.md
4
+ pyproject.toml
5
+ lanscape/__init__.py
6
+ lanscape/__main__.py
7
+ lanscape.egg-info/PKG-INFO
8
+ lanscape.egg-info/SOURCES.txt
9
+ lanscape.egg-info/dependency_links.txt
10
+ lanscape.egg-info/requires.txt
11
+ lanscape.egg-info/top_level.txt
12
+ lanscape/resources/mac_addresses/mac_db.json
13
+ lanscape/resources/ports/full.json
14
+ lanscape/resources/ports/large.json
15
+ lanscape/resources/ports/medium.json
16
+ lanscape/resources/ports/small.json
17
+ lanscape/resources/services/definitions.jsonc
18
+ lanscape/ui/static/lanscape.webmanifest
19
+ lanscape/ui/static/css/style.css
20
+ lanscape/ui/static/img/ico/android-chrome-192x192.png
21
+ lanscape/ui/static/img/ico/android-chrome-512x512.png
22
+ lanscape/ui/static/img/ico/apple-touch-icon.png
23
+ lanscape/ui/static/img/ico/favicon-16x16.png
24
+ lanscape/ui/static/img/ico/favicon-32x32.png
25
+ lanscape/ui/static/img/ico/favicon.ico
26
+ lanscape/ui/static/img/ico/site.webmanifest
27
+ lanscape/ui/static/js/core.js
28
+ lanscape/ui/static/js/layout-sizing.js
29
+ lanscape/ui/static/js/main.js
30
+ lanscape/ui/static/js/on-tab-close.js
31
+ lanscape/ui/static/js/quietReload.js
32
+ lanscape/ui/static/js/shutdown-server.js
33
+ lanscape/ui/static/js/subnet-info.js
34
+ lanscape/ui/static/js/subnet-selector.js
35
+ lanscape/ui/templates/base.html
36
+ lanscape/ui/templates/error.html
37
+ lanscape/ui/templates/info.html
38
+ lanscape/ui/templates/main.html
39
+ lanscape/ui/templates/scan.html
40
+ lanscape/ui/templates/shutdown.html
41
+ lanscape/ui/templates/core/head.html
42
+ lanscape/ui/templates/core/scripts.html
43
+ lanscape/ui/templates/scan/export.html
44
+ lanscape/ui/templates/scan/ip-table-row.html
45
+ lanscape/ui/templates/scan/ip-table.html
46
+ lanscape/ui/templates/scan/overview.html
47
+ lanscape/ui/templates/scan/scan-error.html
48
+ tests/test_api.py
49
+ tests/test_env.py
50
+ tests/test_library.py
51
+ tests/test_utils.py
@@ -4,4 +4,4 @@ requests<3.0,>=2.32
4
4
  setuptools
5
5
  scapy<3.0,>=2.3.2
6
6
  tabulate==0.9.0
7
- pytest
7
+ pydantic
@@ -1,26 +1,31 @@
1
- [project]
2
- name = "lanscape"
3
- version = "1.3.1a8"
4
- authors = [
5
- { name="Michael Dennis", email="michael@dipduo.com" },
6
- ]
7
- description = "A python based local network scanner"
8
- readme = "README.md"
9
- requires-python = ">=3.8"
10
- classifiers = [
11
- "Programming Language :: Python :: 3",
12
- "License :: OSI Approved :: MIT License",
13
- "Operating System :: OS Independent",
14
- ]
15
- dependencies = [
16
- "Flask>=3.0,<5.0",
17
- "psutil>=6.0,<7.0",
18
- "requests>=2.32,<3.0",
19
- "setuptools",
20
- "scapy>=2.3.2,<3.0",
21
- "tabulate==0.9.0",
22
- "pytest"
23
- ]
24
- [project.urls]
25
- Homepage = "https://github.com/mdennis281/py-lanscape"
26
- Issues = "https://github.com/mdennis281/py-lanscape/issues"
1
+ [project]
2
+ name = "lanscape"
3
+ version = "1.3.2a6"
4
+ authors = [
5
+ { name="Michael Dennis", email="michael@dipduo.com" },
6
+ ]
7
+ description = "A python based local network scanner"
8
+ readme = "README.md"
9
+ requires-python = ">=3.8"
10
+ license = "MIT"
11
+ license-files = ["LICENSE"]
12
+ keywords = ["network", "scanner", "lan", "local", "python"]
13
+ classifiers = [
14
+ "Programming Language :: Python :: 3",
15
+ "Operating System :: OS Independent",
16
+ ]
17
+ dependencies = [
18
+ "Flask>=3.0,<5.0",
19
+ "psutil>=6.0,<7.0",
20
+ "requests>=2.32,<3.0",
21
+ "setuptools",
22
+ "scapy>=2.3.2,<3.0",
23
+ "tabulate==0.9.0",
24
+ "pydantic"
25
+ ]
26
+ [project.urls]
27
+ Homepage = "https://github.com/mdennis281/py-lanscape"
28
+ Issues = "https://github.com/mdennis281/py-lanscape/issues"
29
+
30
+ [tool.setuptools]
31
+ packages = ["lanscape"] # Explicitly list your packages
@@ -1,12 +1,11 @@
1
1
  import unittest
2
2
  import json
3
- from ..ui.app import app
4
- from ..libraries.net_tools import get_network_subnet
3
+ from lanscape.ui.app import app
4
+ from lanscape.libraries.net_tools import get_network_subnet
5
5
  from ._helpers import right_size_subnet
6
6
  import time
7
7
 
8
8
 
9
-
10
9
  class ApiTestCase(unittest.TestCase):
11
10
  app = app.test_client()
12
11
 
@@ -21,10 +20,10 @@ class ApiTestCase(unittest.TestCase):
21
20
 
22
21
  # Create a new port list
23
22
  new_port_list = {'80': 'http', '443': 'https'}
24
- response = self.app.post('/api/port/list/test_port_list_lifecycle', json=new_port_list)
23
+ response = self.app.post(
24
+ '/api/port/list/test_port_list_lifecycle', json=new_port_list)
25
25
  self.assertEqual(response.status_code, 200)
26
26
 
27
-
28
27
  # Get the list of port lists again
29
28
  response = self.app.get('/api/port/list')
30
29
  self.assertEqual(response.status_code, 200)
@@ -40,7 +39,8 @@ class ApiTestCase(unittest.TestCase):
40
39
 
41
40
  # Update the new port list
42
41
  updated_port_list = {'22': 'ssh', '8080': 'http-alt'}
43
- response = self.app.put('/api/port/list/test_port_list_lifecycle', json=updated_port_list)
42
+ response = self.app.put(
43
+ '/api/port/list/test_port_list_lifecycle', json=updated_port_list)
44
44
  self.assertEqual(response.status_code, 200)
45
45
 
46
46
  # Get the new port list again
@@ -61,11 +61,13 @@ class ApiTestCase(unittest.TestCase):
61
61
 
62
62
  # Create a new port list
63
63
  new_port_list = {'80': 'http', '443': 'https'}
64
- response = self.app.post('/api/port/list/test_port_list_scan', json=new_port_list)
64
+ response = self.app.post(
65
+ '/api/port/list/test_port_list_scan', json=new_port_list)
65
66
  self.assertEqual(response.status_code, 200)
66
67
 
67
68
  # Create a new scan, wait for completion
68
- new_scan = {'subnet': right_size_subnet(get_network_subnet()), 'port_list': 'test_port_list_scan'}
69
+ new_scan = {'subnet': right_size_subnet(
70
+ get_network_subnet()), 'port_list': 'test_port_list_scan'}
69
71
  response = self.app.post('/api/scan/async', json=new_scan)
70
72
  self.assertEqual(response.status_code, 200)
71
73
  scan_info = json.loads(response.data)
@@ -78,26 +80,14 @@ class ApiTestCase(unittest.TestCase):
78
80
  self.assertEqual(response.status_code, 200)
79
81
  scan_data = json.loads(response.data)
80
82
  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)
83
+ self.assertEqual(scan_data['stage'], 'complete')
94
84
 
85
+ self._render_scan_ui(scanid)
95
86
 
96
87
  # Delete the new port list
97
88
  response = self.app.delete('/api/port/list/test_port_list_scan')
98
89
  self.assertEqual(response.status_code, 200)
99
90
 
100
-
101
91
  def test_subnet_ports(self):
102
92
  """
103
93
  Test to ensure multi-subnet dectection is working
@@ -108,8 +98,8 @@ class ApiTestCase(unittest.TestCase):
108
98
 
109
99
  subnets = json.loads(response.data)
110
100
  self.assertIsNot(len(subnets), 0)
111
- self.assertIsInstance(subnets[0],dict)
112
- subnet:dict = subnets[0]
101
+ self.assertIsInstance(subnets[0], dict)
102
+ subnet: dict = subnets[0]
113
103
  self.assertIsNotNone(subnet.get('address_cnt'))
114
104
 
115
105
  def test_subnet_validation(self):
@@ -125,9 +115,9 @@ class ApiTestCase(unittest.TestCase):
125
115
  '10.0.0.1/24, 192.168.1.1-100': 354,
126
116
  '10.0.0.1/20': 4094,
127
117
  '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
118
+ '': -1, # blank
119
+ '10.0.1/24': -1, # invalid
120
+ '10.0.0.1/2': -1, # too big
131
121
  '10.0.0.1/19, 192.168.1.1/20': 12284,
132
122
  '10.0.0.1/17, 192.168.0.1/16': 98300,
133
123
  '10.0.0.1/20, 192.168.0.1/20, 10.100.0.1/20': 12282,
@@ -139,12 +129,24 @@ class ApiTestCase(unittest.TestCase):
139
129
  response = self.app.get(uri)
140
130
  self.assertEqual(response.status_code, 200)
141
131
 
142
- data:dict = json.loads(response.data)
143
- self.assertEqual(data.get('count'),count)
132
+ data: dict = json.loads(response.data)
133
+ self.assertEqual(data.get('count'), count)
144
134
  self.assertIsNotNone(data.get('msg'))
145
135
  if count == -1:
146
136
  self.assertFalse(data.get('valid'))
147
-
137
+
138
+ def _render_scan_ui(self, scanid):
139
+ uris = [
140
+ '/info',
141
+ f'/?scan_id={scanid}',
142
+ f'/scan/{scanid}/overview',
143
+ f'/scan/{scanid}/table',
144
+ f'/export/{scanid}'
145
+ ]
146
+ for uri in uris:
147
+ response = self.app.get(uri)
148
+ self.assertEqual(response.status_code, 200)
149
+
148
150
  def test_scan_api(self):
149
151
  """
150
152
  Test the scan API endpoints
@@ -168,13 +170,16 @@ class ApiTestCase(unittest.TestCase):
168
170
  response = self.app.get(f'/api/scan/{scan_id}/summary')
169
171
  self.assertEqual(response.status_code, 200)
170
172
  summary = json.loads(response.data)
171
- self.assertTrue(summary['running'] or summary['stage'] == 'complete')
173
+ self.assertTrue(summary['running']
174
+ or summary['stage'] == 'complete')
172
175
  percent_complete = summary['percent_complete']
173
176
  self.assertGreaterEqual(percent_complete, 0)
174
177
  self.assertLessEqual(percent_complete, 100)
175
178
  # Wait for a bit before checking again
179
+
180
+ self._render_scan_ui(scan_id)
176
181
  time.sleep(2)
177
-
182
+
178
183
  self.assertEqual(summary['running'], False)
179
184
  self.assertEqual(summary['stage'], 'complete')
180
185
  self.assertGreater(summary['runtime'], 0)
@@ -187,8 +192,5 @@ class ApiTestCase(unittest.TestCase):
187
192
  self.assertGreater(devices_alive, 0)
188
193
 
189
194
 
190
-
191
-
192
-
193
195
  if __name__ == '__main__':
194
- unittest.main()
196
+ unittest.main()
@@ -1,9 +1,8 @@
1
1
  import unittest
2
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
-
3
+ from lanscape.libraries.version_manager import lookup_latest_version
4
+ from lanscape.libraries.app_scope import ResourceManager, is_local_run
5
+ from lanscape.libraries.net_tools import is_arp_supported
7
6
 
8
7
 
9
8
  class EnvTestCase(unittest.TestCase):
@@ -13,18 +12,16 @@ class EnvTestCase(unittest.TestCase):
13
12
 
14
13
  def test_resource_manager(self):
15
14
  ports = ResourceManager('ports')
16
- self.assertGreater(len(ports.list()),0)
15
+ self.assertGreater(len(ports.list()), 0)
17
16
  mac = ResourceManager('mac_addresses')
18
17
  mac_list = mac.get('mac_db.json')
19
18
  self.assertIsNotNone(mac_list)
20
-
19
+
21
20
  def test_local_version(self):
22
21
  self.assertTrue(is_local_run())
23
-
22
+
24
23
  def test_arp_support(self):
25
24
  arp_supported = is_arp_supported()
26
25
  self.assertIn(arp_supported, [True, False],
27
- f"ARP support should be either True or False, not {arp_supported}"
28
- )
29
-
30
-
26
+ f"ARP support should be either True or False, not {arp_supported}"
27
+ )
@@ -0,0 +1,84 @@
1
+ import unittest
2
+ from lanscape.libraries.net_tools import smart_select_primary_subnet
3
+ from ._helpers import right_size_subnet
4
+ from lanscape.libraries.subnet_scan import ScanManager
5
+ from lanscape.libraries.scan_config import ScanConfig, PingConfig, ArpConfig, ScanType
6
+
7
+ sm = ScanManager()
8
+
9
+
10
+ class LibraryTestCase(unittest.TestCase):
11
+ def test_scan_config(self):
12
+
13
+ subnet_val = '192.168.1.1/24'
14
+ do_port_scan = False
15
+ ping_attempts = 3
16
+ arp_timeout = 2.0
17
+
18
+ cfg = ScanConfig(
19
+ subnet=subnet_val,
20
+ port_list='small'
21
+ )
22
+ self.assertEqual(len(cfg.parse_subnet()), 254)
23
+
24
+ cfg.task_scan_ports = do_port_scan
25
+ cfg.ping_config.attempts = ping_attempts
26
+ cfg.arp_config.timeout = arp_timeout
27
+ cfg.lookup_type = ScanType.PING
28
+
29
+ data = cfg.to_dict()
30
+ self.assertTrue(isinstance(data['ping_config'], dict))
31
+ self.assertTrue(isinstance(data['arp_config'], dict))
32
+
33
+ cfg2 = ScanConfig.from_dict(data)
34
+
35
+ # ensure the config was properly converted back
36
+ self.assertEqual(cfg2.subnet, subnet_val)
37
+ self.assertEqual(cfg2.port_list, 'small')
38
+ self.assertEqual(cfg2.task_scan_ports, do_port_scan)
39
+ self.assertEqual(cfg2.ping_config.attempts, ping_attempts)
40
+ self.assertEqual(cfg2.arp_config.timeout, arp_timeout)
41
+ self.assertEqual(cfg2.lookup_type, ScanType.PING)
42
+
43
+ def test_scan(self):
44
+ subnet = smart_select_primary_subnet()
45
+ self.assertIsNotNone(subnet)
46
+ cfg = ScanConfig(
47
+ subnet=right_size_subnet(subnet),
48
+ t_multiplier=1.0,
49
+ port_list='small'
50
+ )
51
+ scan = sm.new_scan(cfg)
52
+ self.assertTrue(scan.running)
53
+ sm.wait_until_complete(scan.uid)
54
+
55
+ self.assertFalse(scan.running)
56
+
57
+ # ensure there are not any remaining running threads
58
+ self.assertDictEqual(scan.job_stats.running, {})
59
+
60
+ cnt_with_hostname = 0
61
+ ips = []
62
+ macs = []
63
+ for d in scan.results.devices:
64
+ if d.hostname:
65
+ cnt_with_hostname += 1
66
+ # ensure there arent dupe mac addresses
67
+
68
+ if d.get_mac() in macs:
69
+ print(f"Warning: Duplicate MAC address found: {d.get_mac()}")
70
+ macs.append(d.get_mac())
71
+
72
+ # ensure there arent dupe ips
73
+ self.assertNotIn(d.ip, ips)
74
+ ips.append(d.ip)
75
+
76
+ # device must be alive to be in this list
77
+ self.assertTrue(d.alive)
78
+
79
+ # find at least one device
80
+ self.assertGreater(len(scan.results.devices), 0)
81
+
82
+ # ensure everything got scanned
83
+ self.assertEqual(scan.results.devices_scanned,
84
+ scan.results.devices_total)
@@ -0,0 +1,86 @@
1
+ import unittest
2
+ from lanscape.libraries.ip_parser import parse_ip_input
3
+ from lanscape.libraries.errors import SubnetTooLargeError
4
+ import ipaddress
5
+ from lanscape.libraries import ip_parser
6
+ from lanscape.libraries.errors import SubnetTooLargeError
7
+ from lanscape.libraries.port_manager import PortManager
8
+ from lanscape.libraries.decorators import timeout_enforcer
9
+ import time
10
+
11
+
12
+ class IPParserTests(unittest.TestCase):
13
+ def test_parse_cidr(self):
14
+ ips = parse_ip_input('192.168.0.0/30')
15
+ self.assertEqual([str(ip) for ip in ips], [
16
+ '192.168.0.1', '192.168.0.2'])
17
+
18
+ def test_parse_range(self):
19
+ ips = parse_ip_input('10.0.0.1-10.0.0.3')
20
+ self.assertEqual(len(ips), 3)
21
+ self.assertEqual(str(ips[0]), '10.0.0.1')
22
+ self.assertEqual(str(ips[-1]), '10.0.0.3')
23
+
24
+ def test_parse_shorthand_range(self):
25
+ ips = parse_ip_input('10.0.0.1-3')
26
+ self.assertEqual([str(ip) for ip in ips], [
27
+ '10.0.0.1', '10.0.0.2', '10.0.0.3'])
28
+
29
+ def test_parse_too_large_subnet(self):
30
+ with self.assertRaises(SubnetTooLargeError):
31
+ parse_ip_input('10.0.0.0/8')
32
+
33
+ def test_parse_ip_input_mixed(self):
34
+ ip_input = "10.0.0.1/30, 10.0.0.10-10.0.0.12, 10.0.0.20-22, 10.0.0.50"
35
+ result = ip_parser.parse_ip_input(ip_input)
36
+ expected = [
37
+ ipaddress.IPv4Address("10.0.0.1"),
38
+ ipaddress.IPv4Address("10.0.0.2"),
39
+ ipaddress.IPv4Address("10.0.0.10"),
40
+ ipaddress.IPv4Address("10.0.0.11"),
41
+ ipaddress.IPv4Address("10.0.0.12"),
42
+ ipaddress.IPv4Address("10.0.0.20"),
43
+ ipaddress.IPv4Address("10.0.0.21"),
44
+ ipaddress.IPv4Address("10.0.0.22"),
45
+ ipaddress.IPv4Address("10.0.0.50"),
46
+ ]
47
+ self.assertEqual(result, expected)
48
+
49
+
50
+ class PortManagerValidateTests(unittest.TestCase):
51
+ def setUp(self):
52
+ # Avoid running __init__ which touches the filesystem
53
+ self.pm = PortManager.__new__(PortManager)
54
+
55
+ def test_validate_port_data_valid(self):
56
+ valid = {"80": "http", "443": "https"}
57
+ self.assertTrue(PortManager.validate_port_data(self.pm, valid))
58
+
59
+ def test_validate_port_data_invalid(self):
60
+ invalid_cases = [
61
+ {"-1": "neg"}, # negative port
62
+ {"70000": "too_high"}, # port out of range
63
+ {"abc": "not_int"}, # non-integer port
64
+ {"80": 123}, # service not a string
65
+ ]
66
+ for case in invalid_cases:
67
+ with self.subTest(case=case):
68
+ self.assertFalse(PortManager.validate_port_data(self.pm, case))
69
+
70
+
71
+ class DecoratorTimeoutTests(unittest.TestCase):
72
+ def test_timeout_enforcer(self):
73
+ @timeout_enforcer(0.1, raise_on_timeout=False)
74
+ def slow_return():
75
+ time.sleep(0.2)
76
+ return "done"
77
+
78
+ self.assertIsNone(slow_return())
79
+
80
+ @timeout_enforcer(0.1, raise_on_timeout=True)
81
+ def slow_raise():
82
+ time.sleep(0.2)
83
+ return "done"
84
+
85
+ with self.assertRaises(TimeoutError):
86
+ slow_raise()
@@ -1,4 +0,0 @@
1
- recursive-include src/lanscape/resources *.json
2
- recursive-include src/lanscape/resources *.jsonc
3
- recursive-include src/lanscape/ui/templates *.html
4
- recursive-include src/lanscape/ui/static *