lanscape 1.2.7a1__tar.gz → 1.2.7a2__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.
Files changed (77) hide show
  1. {lanscape-1.2.7a1/src/lanscape.egg-info → lanscape-1.2.7a2}/PKG-INFO +1 -1
  2. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/pyproject.toml +1 -1
  3. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/libraries/mac_lookup.py +12 -9
  4. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/libraries/net_tools.py +55 -9
  5. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/libraries/subnet_scan.py +2 -3
  6. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/tests/test_library.py +2 -2
  7. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/ui/webviewer.py +2 -0
  8. {lanscape-1.2.7a1 → lanscape-1.2.7a2/src/lanscape.egg-info}/PKG-INFO +1 -1
  9. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/LICENSE +0 -0
  10. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/MANIFEST.in +0 -0
  11. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/README.md +0 -0
  12. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/setup.cfg +0 -0
  13. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/__init__.py +0 -0
  14. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/__main__.py +0 -0
  15. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/libraries/app_scope.py +0 -0
  16. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/libraries/decorators.py +0 -0
  17. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/libraries/errors.py +0 -0
  18. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/libraries/ip_parser.py +0 -0
  19. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/libraries/logger.py +0 -0
  20. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/libraries/port_manager.py +0 -0
  21. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/libraries/runtime_args.py +0 -0
  22. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/libraries/version_manager.py +0 -0
  23. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/resources/mac_addresses/convert_csv.py +0 -0
  24. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/resources/mac_addresses/mac_db.json +0 -0
  25. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/resources/ports/convert_csv.py +0 -0
  26. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/resources/ports/full.json +0 -0
  27. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/resources/ports/large.json +0 -0
  28. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/resources/ports/medium.json +0 -0
  29. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/resources/ports/small.json +0 -0
  30. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/tests/__init__.py +0 -0
  31. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/tests/_helpers.py +0 -0
  32. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/tests/test_api.py +0 -0
  33. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/tests/test_env.py +0 -0
  34. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/tests/test_webview.py +0 -0
  35. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/ui/app.py +0 -0
  36. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/ui/blueprints/__init__.py +0 -0
  37. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/ui/blueprints/api/__init__.py +0 -0
  38. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/ui/blueprints/api/port.py +0 -0
  39. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/ui/blueprints/api/scan.py +0 -0
  40. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/ui/blueprints/api/tools.py +0 -0
  41. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/ui/blueprints/web/__init__.py +0 -0
  42. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/ui/blueprints/web/routes.py +0 -0
  43. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/ui/main.py +0 -0
  44. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/ui/static/css/style.css +0 -0
  45. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/ui/static/img/ico/android-chrome-192x192.png +0 -0
  46. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/ui/static/img/ico/android-chrome-512x512.png +0 -0
  47. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/ui/static/img/ico/apple-touch-icon.png +0 -0
  48. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/ui/static/img/ico/favicon-16x16.png +0 -0
  49. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/ui/static/img/ico/favicon-32x32.png +0 -0
  50. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/ui/static/img/ico/favicon.ico +0 -0
  51. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/ui/static/img/ico/site.webmanifest +0 -0
  52. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/ui/static/img/readme1.png +0 -0
  53. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/ui/static/js/core.js +0 -0
  54. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/ui/static/js/layout-sizing.js +0 -0
  55. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/ui/static/js/main.js +0 -0
  56. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/ui/static/js/quietReload.js +0 -0
  57. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/ui/static/js/shutdown-server.js +0 -0
  58. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/ui/static/js/subnet-info.js +0 -0
  59. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/ui/static/js/subnet-selector.js +0 -0
  60. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/ui/static/lanscape.webmanifest +0 -0
  61. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/ui/templates/base.html +0 -0
  62. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/ui/templates/core/head.html +0 -0
  63. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/ui/templates/core/scripts.html +0 -0
  64. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/ui/templates/error.html +0 -0
  65. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/ui/templates/info.html +0 -0
  66. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/ui/templates/main.html +0 -0
  67. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/ui/templates/scan/export.html +0 -0
  68. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/ui/templates/scan/ip-table-row.html +0 -0
  69. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/ui/templates/scan/ip-table.html +0 -0
  70. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/ui/templates/scan/overview.html +0 -0
  71. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/ui/templates/scan/scan-error.html +0 -0
  72. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/ui/templates/scan.html +0 -0
  73. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape/ui/templates/shutdown.html +0 -0
  74. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape.egg-info/SOURCES.txt +0 -0
  75. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape.egg-info/dependency_links.txt +0 -0
  76. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/src/lanscape.egg-info/requires.txt +0 -0
  77. {lanscape-1.2.7a1 → lanscape-1.2.7a2}/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.7a1
3
+ Version: 1.2.7a2
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
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "lanscape"
3
- version = "1.2.7a1"
3
+ version = "1.2.7a2"
4
4
  authors = [
5
5
  { name="Michael Dennis", email="michael@dipduo.com" },
6
6
  ]
@@ -3,7 +3,7 @@ import json
3
3
  import logging
4
4
  import platform
5
5
  import subprocess
6
- from typing import Optional
6
+ from typing import List
7
7
 
8
8
  from .app_scope import ResourceManager
9
9
 
@@ -22,7 +22,7 @@ def lookup_mac(mac: str) -> str:
22
22
  return DB[m]
23
23
  return None
24
24
 
25
- def get_mac(ip: str) -> Optional[str]:
25
+ def get_macs(ip: str) -> List[str]:
26
26
  """Try to get the MAC address using Scapy, fallback to ARP if it fails."""
27
27
  if mac := get_mac_by_scapy(ip):
28
28
  log.debug(f"Used Scapy to resolve ip {ip} to mac {mac}")
@@ -31,7 +31,8 @@ def get_mac(ip: str) -> Optional[str]:
31
31
  log.debug(f"Used ARP to resolve ip {ip} to mac {arp}")
32
32
  return arp
33
33
 
34
- def get_mac_by_arp(ip: str) -> Optional[str]:
34
+
35
+ def get_mac_by_arp(ip: str) -> List[str]:
35
36
  """Retrieve the last MAC address instance using the ARP command."""
36
37
  try:
37
38
  # Use the appropriate ARP command based on the platform
@@ -44,11 +45,11 @@ def get_mac_by_arp(ip: str) -> Optional[str]:
44
45
 
45
46
  macs = re.findall(r'..:..:..:..:..:..', output)
46
47
  # found that typically last mac is the correct one
47
- return macs[-1] if macs else None
48
+ return macs
48
49
  except:
49
- return None
50
+ return []
50
51
 
51
- def get_mac_by_scapy(ip: str) -> Optional[str]:
52
+ def get_mac_by_scapy(ip: str) -> List[str]:
52
53
  """Retrieve the MAC address using the Scapy library."""
53
54
  try:
54
55
  from scapy.all import ARP, Ether, srp
@@ -61,7 +62,9 @@ def get_mac_by_scapy(ip: str) -> Optional[str]:
61
62
  # Send the packet and wait for a response
62
63
  result = srp(packet, timeout=1, verbose=0)[0]
63
64
 
64
- # Extract the MAC address from the response
65
- return result[0][1].hwsrc if result else None
65
+ # Extract the MAC addresses from the response
66
+ return [res[1].hwsrc for res in result]
67
+ # return result[0][1].hwsrc if result else None
66
68
  except:
67
- return None
69
+ return None
70
+
@@ -11,7 +11,7 @@ from time import sleep
11
11
  from typing import List
12
12
  from scapy.all import ARP, Ether, srp
13
13
 
14
- from .mac_lookup import lookup_mac, get_mac
14
+ from .mac_lookup import lookup_mac, get_macs
15
15
  from .ip_parser import get_address_count, MAX_IPS_ALLOWED
16
16
 
17
17
  log = logging.getLogger('NetTools')
@@ -61,13 +61,15 @@ class IPAlive:
61
61
  pass # Ping failed
62
62
  sleep(retry_delay)
63
63
  return False
64
+
65
+
64
66
 
65
67
  class Device(IPAlive):
66
68
  def __init__(self,ip:str):
67
69
  self.ip: str = ip
68
70
  self.alive: bool = None
69
71
  self.hostname: str = None
70
- self.mac_addr: str = None
72
+ self.macs: List[str] = []
71
73
  self.manufacturer: str = None
72
74
  self.ports: List[int] = []
73
75
  self.stage: str = 'found'
@@ -76,8 +78,16 @@ class Device(IPAlive):
76
78
  def get_metadata(self):
77
79
  if self.alive:
78
80
  self.hostname = self._get_hostname()
79
- self.mac_addr = self._get_mac_address()
80
- self.manufacturer = self._get_manufacturer()
81
+ self.macs = self._get_mac_addresses()
82
+
83
+ def dict(self) -> dict:
84
+ obj = vars(self).copy()
85
+ obj.pop('log')
86
+ primary_mac = self.get_mac()
87
+ obj['mac_addr'] = primary_mac
88
+ obj['manufacturer'] = self._get_manufacturer(primary_mac)
89
+
90
+ return obj
81
91
 
82
92
 
83
93
  def test_port(self,port:int) -> bool:
@@ -89,12 +99,19 @@ class Device(IPAlive):
89
99
  self.ports.append(port)
90
100
  return True
91
101
  return False
102
+
103
+ def get_mac(self):
104
+ if not self.macs:
105
+ self.macs = self._get_mac_addresses()
106
+ return mac_selector.choose_mac(self.macs)
92
107
 
93
- def _get_mac_address(self):
108
+ def _get_mac_addresses(self):
94
109
  """
95
110
  Get the MAC address of a network device given its IP address.
96
111
  """
97
- return get_mac(self.ip)
112
+ macs = get_macs(self.ip)
113
+ mac_selector.import_macs(macs)
114
+ return macs
98
115
 
99
116
  def _get_hostname(self):
100
117
  """
@@ -106,11 +123,38 @@ class Device(IPAlive):
106
123
  except socket.herror:
107
124
  return None
108
125
 
109
- def _get_manufacturer(self):
126
+ def _get_manufacturer(self,mac_addr=None):
110
127
  """
111
128
  Get the manufacturer of a network device given its MAC address.
112
129
  """
113
- return lookup_mac(self.mac_addr) if self.mac_addr else None
130
+ return lookup_mac(mac_addr) if mac_addr else None
131
+
132
+
133
+ class MacSelector:
134
+ def __init__(self):
135
+ self.macs = {}
136
+
137
+ def choose_mac(self,macs:List[str]) -> str:
138
+ if len(macs) == 1:
139
+ return macs[0]
140
+ lowest = 9999
141
+ lowest_i = -1
142
+
143
+ for mac in macs:
144
+ if self.macs[mac] < lowest:
145
+ lowest = self.macs[mac]
146
+ lowest_i = macs.index(mac)
147
+ return macs[lowest_i] if lowest_i != -1 else None
148
+
149
+
150
+ def import_macs(self,macs:List[str]):
151
+ for mac in macs:
152
+ self.macs[mac] = self.macs.get(mac,0) + 1
153
+
154
+ def clear(self):
155
+ self.macs = {}
156
+
157
+ mac_selector = MacSelector()
114
158
 
115
159
 
116
160
  def get_ip_address(interface: str):
@@ -262,4 +306,6 @@ def smart_select_primary_subnet(subnets: List[dict]=get_all_network_subnets()) -
262
306
  selected = subnet
263
307
  if not selected and len(subnets):
264
308
  selected = subnets[0]
265
- return selected['subnet']
309
+ return selected['subnet']
310
+
311
+
@@ -250,10 +250,9 @@ class ScannerResults:
250
250
  out.pop('scan')
251
251
  out.pop('log')
252
252
 
253
- devices: Device = out.pop('devices')
253
+ devices: List[Device] = out.pop('devices')
254
254
  sortedDevices = sorted(devices, key=lambda obj: ipaddress.IPv4Address(obj.ip))
255
- out['devices'] = [vars(device).copy() for device in sortedDevices]
256
- for device in out['devices']: device.pop('log')
255
+ out['devices'] = [device.dict() for device in sortedDevices]
257
256
 
258
257
  if out_type == str:
259
258
  return json.dumps(out, indent=2)
@@ -30,8 +30,8 @@ class LibraryTestCase(unittest.TestCase):
30
30
  for d in scan.results.devices:
31
31
  if d.hostname: cnt_with_hostname += 1
32
32
  # ensure there arent dupe mac addresses
33
- self.assertNotIn(d.mac_addr, macs)
34
- macs.append(d.mac_addr)
33
+ self.assertNotIn(d.get_mac(), macs)
34
+ macs.append(d.get_mac())
35
35
 
36
36
  # ensure there arent dupe ips
37
37
  self.assertNotIn(d.ip, ips)
@@ -1,6 +1,7 @@
1
1
  import webview
2
2
  from .app import start_webserver_dameon
3
3
  from ..libraries.runtime_args import RuntimeArgs
4
+ from time import sleep
4
5
 
5
6
 
6
7
 
@@ -10,6 +11,7 @@ def start_webview(args: RuntimeArgs) -> None:
10
11
 
11
12
  # Start the Pywebview window
12
13
  webview.create_window('LANscape', f'http://127.0.0.1:{args.port}')
14
+ sleep(1)
13
15
  webview.start()
14
16
 
15
17
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lanscape
3
- Version: 1.2.7a1
3
+ Version: 1.2.7a2
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
File without changes
File without changes
File without changes
File without changes