iotsploit-core 0.0.6__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.
- iotsploit_core/__init__.py +7 -0
- iotsploit_core/context.py +27 -0
- iotsploit_core/core/__init__.py +0 -0
- iotsploit_core/core/base_plugin.py +290 -0
- iotsploit_core/core/device_config.py +105 -0
- iotsploit_core/core/device_manager.py +942 -0
- iotsploit_core/core/device_registry.py +118 -0
- iotsploit_core/core/device_scanner.py +74 -0
- iotsploit_core/core/device_spec.py +105 -0
- iotsploit_core/core/device_store.py +86 -0
- iotsploit_core/core/execution_backend.py +464 -0
- iotsploit_core/core/execution_queue.py +456 -0
- iotsploit_core/core/exploit_manager.py +728 -0
- iotsploit_core/core/exploit_spec.py +73 -0
- iotsploit_core/core/stream_manager.py +157 -0
- iotsploit_core/core/tool_config.py +430 -0
- iotsploit_core/core/tool_manager.py +1166 -0
- iotsploit_core/core/tool_service.py +936 -0
- iotsploit_core/domain/__init__.py +3 -0
- iotsploit_core/domain/device.py +70 -0
- iotsploit_core/domain/execution_plan.py +29 -0
- iotsploit_core/domain/plugin.py +17 -0
- iotsploit_core/domain/stream.py +63 -0
- iotsploit_core/domain/target.py +243 -0
- iotsploit_core/platforms/__init__.py +19 -0
- iotsploit_core/platforms/consts.py +25 -0
- iotsploit_core/ports/__init__.py +6 -0
- iotsploit_core/ports/driver_state_repo.py +15 -0
- iotsploit_core/ports/plugin_repo.py +26 -0
- iotsploit_core/ports/stream_backend.py +28 -0
- iotsploit_core/ports/task_runner.py +22 -0
- iotsploit_core/ports/wifi_backend.py +148 -0
- iotsploit_core/py.typed +2 -0
- iotsploit_core/utils/__init__.py +53 -0
- iotsploit_core/utils/exceptions.py +152 -0
- iotsploit_core/utils/helpers.py +65 -0
- iotsploit_core/utils/iots_logger.py +164 -0
- iotsploit_core/utils/result.py +41 -0
- iotsploit_core-0.0.6.dist-info/METADATA +117 -0
- iotsploit_core-0.0.6.dist-info/RECORD +41 -0
- iotsploit_core-0.0.6.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from typing import Dict, List, Optional
|
|
5
|
+
|
|
6
|
+
from iotsploit_core.core.device_config import DeviceConfigManager
|
|
7
|
+
from iotsploit_core.core.device_scanner import CompositeDeviceScanner, PluginDeviceScanner
|
|
8
|
+
from iotsploit_core.core.device_store import DeviceStore
|
|
9
|
+
from iotsploit_core.domain.device import Device
|
|
10
|
+
|
|
11
|
+
logger = logging.getLogger(__name__)
|
|
12
|
+
|
|
13
|
+
class DeviceRegistry:
|
|
14
|
+
_instance = None
|
|
15
|
+
|
|
16
|
+
def __new__(cls, *args, **kwargs):
|
|
17
|
+
if cls._instance is None:
|
|
18
|
+
cls._instance = super(DeviceRegistry, cls).__new__(cls)
|
|
19
|
+
cls._instance._initialized = False
|
|
20
|
+
return cls._instance
|
|
21
|
+
|
|
22
|
+
def __init__(
|
|
23
|
+
self,
|
|
24
|
+
*,
|
|
25
|
+
driver_manager,
|
|
26
|
+
device_store: DeviceStore | None = None,
|
|
27
|
+
config_manager: DeviceConfigManager | None = None,
|
|
28
|
+
scanner: CompositeDeviceScanner | None = None,
|
|
29
|
+
):
|
|
30
|
+
if not self._initialized:
|
|
31
|
+
if driver_manager is None:
|
|
32
|
+
raise TypeError("DeviceRegistry requires 'driver_manager' (inject via adapter factory).")
|
|
33
|
+
self.device_store = device_store or DeviceStore()
|
|
34
|
+
self.config_manager = config_manager or DeviceConfigManager()
|
|
35
|
+
self.driver_manager = driver_manager
|
|
36
|
+
self.scanner = scanner or CompositeDeviceScanner(self.device_store)
|
|
37
|
+
self._initialized = True
|
|
38
|
+
|
|
39
|
+
@classmethod
|
|
40
|
+
def get_instance(
|
|
41
|
+
cls,
|
|
42
|
+
*,
|
|
43
|
+
driver_manager,
|
|
44
|
+
device_store: DeviceStore | None = None,
|
|
45
|
+
config_manager: DeviceConfigManager | None = None,
|
|
46
|
+
scanner: CompositeDeviceScanner | None = None,
|
|
47
|
+
) -> "DeviceRegistry":
|
|
48
|
+
"""Get singleton instance (requires injection on first initialization)."""
|
|
49
|
+
|
|
50
|
+
inst = cls(
|
|
51
|
+
driver_manager=driver_manager,
|
|
52
|
+
device_store=device_store,
|
|
53
|
+
config_manager=config_manager,
|
|
54
|
+
scanner=scanner,
|
|
55
|
+
)
|
|
56
|
+
return inst
|
|
57
|
+
|
|
58
|
+
def initialize(self):
|
|
59
|
+
"""初始化设备注册表"""
|
|
60
|
+
logger.debug("Initializing device registry...")
|
|
61
|
+
|
|
62
|
+
# 清理现有的扫描器
|
|
63
|
+
self.scanner.clear_scanners()
|
|
64
|
+
|
|
65
|
+
# 为每个驱动创建扫描器
|
|
66
|
+
for driver_name, driver in self.driver_manager.drivers.items():
|
|
67
|
+
scanner = PluginDeviceScanner(self.device_store, driver)
|
|
68
|
+
self.scanner.add_scanner(scanner)
|
|
69
|
+
logger.debug(f"Added scanner for driver: {driver_name}")
|
|
70
|
+
|
|
71
|
+
# 加载配置的设备
|
|
72
|
+
try:
|
|
73
|
+
stored_configs = self.config_manager.load_configs()
|
|
74
|
+
if stored_configs.get('devices'):
|
|
75
|
+
for device_config in stored_configs['devices']:
|
|
76
|
+
try:
|
|
77
|
+
device = self.device_store._dict_to_device(device_config)
|
|
78
|
+
self.device_store.register_device(device, source="static")
|
|
79
|
+
logger.debug(f"Loaded static device: {device.device_id}")
|
|
80
|
+
except Exception as e:
|
|
81
|
+
logger.error(f"Error loading device from config: {e}")
|
|
82
|
+
except Exception as e:
|
|
83
|
+
logger.error(f"Error loading stored configurations: {e}")
|
|
84
|
+
|
|
85
|
+
def scan_devices(self) -> List[Device]:
|
|
86
|
+
"""扫描所有可用设备"""
|
|
87
|
+
try:
|
|
88
|
+
discovered_devices = self.scanner.scan()
|
|
89
|
+
# 注册发现的设备
|
|
90
|
+
for device in discovered_devices:
|
|
91
|
+
try:
|
|
92
|
+
self.device_store.register_device(device, source="dynamic")
|
|
93
|
+
except Exception as e:
|
|
94
|
+
logger.error(f"Error registering discovered device: {e}")
|
|
95
|
+
return discovered_devices
|
|
96
|
+
except Exception as e:
|
|
97
|
+
logger.error(f"Error during device scan: {e}")
|
|
98
|
+
return []
|
|
99
|
+
|
|
100
|
+
def merge_devices(self, stored_configs: Dict, discovered_devices: List[Device]):
|
|
101
|
+
"""合并存储的配置和发现的设备"""
|
|
102
|
+
# 处理发现的设备
|
|
103
|
+
for device in discovered_devices:
|
|
104
|
+
try:
|
|
105
|
+
self.device_store.register_device(device, source="dynamic")
|
|
106
|
+
except Exception as e:
|
|
107
|
+
logger.error(f"Error registering dynamic device: {e}")
|
|
108
|
+
|
|
109
|
+
# 处理存储的配置
|
|
110
|
+
if stored_configs.get('devices'):
|
|
111
|
+
for device_config in stored_configs['devices']:
|
|
112
|
+
try:
|
|
113
|
+
device_id = device_config.get('device_id')
|
|
114
|
+
if device_id and device_id not in self.device_store.devices:
|
|
115
|
+
device = self.device_store._dict_to_device(device_config)
|
|
116
|
+
self.device_store.register_device(device, source="static")
|
|
117
|
+
except Exception as e:
|
|
118
|
+
logger.error(f"Error registering static device: {e}")
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
from typing import List, Dict, Type
|
|
2
|
+
import logging
|
|
3
|
+
from iotsploit_core.domain.device import Device
|
|
4
|
+
from iotsploit_core.core.device_store import DeviceStore
|
|
5
|
+
from iotsploit_core.core.base_plugin import BaseDeviceDriver
|
|
6
|
+
|
|
7
|
+
logger = logging.getLogger(__name__)
|
|
8
|
+
|
|
9
|
+
class DeviceScanner:
|
|
10
|
+
"""设备扫描器基类"""
|
|
11
|
+
def __init__(self, device_store: DeviceStore):
|
|
12
|
+
self.device_store = device_store
|
|
13
|
+
|
|
14
|
+
def scan(self) -> List[Device]:
|
|
15
|
+
"""执行设备扫描"""
|
|
16
|
+
return self._perform_scan()
|
|
17
|
+
|
|
18
|
+
def _perform_scan(self) -> List[Device]:
|
|
19
|
+
"""实际的扫描实现"""
|
|
20
|
+
raise NotImplementedError("Subclasses must implement _perform_scan()")
|
|
21
|
+
|
|
22
|
+
class PluginDeviceScanner(DeviceScanner):
|
|
23
|
+
"""使用插件系统的设备扫描器"""
|
|
24
|
+
def __init__(self, device_store: DeviceStore, driver: BaseDeviceDriver):
|
|
25
|
+
super().__init__(device_store)
|
|
26
|
+
self.driver = driver
|
|
27
|
+
|
|
28
|
+
def _perform_scan(self) -> List[Device]:
|
|
29
|
+
"""使用驱动执行扫描"""
|
|
30
|
+
try:
|
|
31
|
+
logger.info(f"Scanning devices using driver: {self.driver.__class__.__name__}")
|
|
32
|
+
result = self.driver.scan()
|
|
33
|
+
|
|
34
|
+
if not result:
|
|
35
|
+
logger.info("No devices found")
|
|
36
|
+
return []
|
|
37
|
+
|
|
38
|
+
devices = result if isinstance(result, list) else [result]
|
|
39
|
+
for device in devices:
|
|
40
|
+
self.device_store.register_device(device, source="dynamic")
|
|
41
|
+
|
|
42
|
+
return devices
|
|
43
|
+
|
|
44
|
+
except Exception as e:
|
|
45
|
+
logger.error(f"Error scanning devices: {str(e)}")
|
|
46
|
+
return []
|
|
47
|
+
|
|
48
|
+
class CompositeDeviceScanner(DeviceScanner):
|
|
49
|
+
"""组合多个扫描器的复合扫描器"""
|
|
50
|
+
def __init__(self, device_store: DeviceStore):
|
|
51
|
+
super().__init__(device_store)
|
|
52
|
+
self.scanners: List[DeviceScanner] = []
|
|
53
|
+
|
|
54
|
+
def clear_scanners(self):
|
|
55
|
+
"""清理所有已注册的扫描器"""
|
|
56
|
+
self.scanners = []
|
|
57
|
+
|
|
58
|
+
def add_scanner(self, scanner: DeviceScanner):
|
|
59
|
+
"""添加一个扫描器"""
|
|
60
|
+
self.scanners.append(scanner)
|
|
61
|
+
|
|
62
|
+
def _perform_scan(self) -> List[Device]:
|
|
63
|
+
"""执行所有注册的扫描器"""
|
|
64
|
+
all_devices = []
|
|
65
|
+
for scanner in self.scanners:
|
|
66
|
+
try:
|
|
67
|
+
# 直接调用 _perform_scan 避免重复注册
|
|
68
|
+
devices = scanner._perform_scan()
|
|
69
|
+
all_devices.extend(devices)
|
|
70
|
+
except Exception as e:
|
|
71
|
+
logger.error(f"Error in scanner {scanner.__class__.__name__}: {str(e)}")
|
|
72
|
+
continue
|
|
73
|
+
|
|
74
|
+
return all_devices
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import pluggy
|
|
2
|
+
import warnings
|
|
3
|
+
from iotsploit_core.domain.device import Device
|
|
4
|
+
from typing import List, Optional
|
|
5
|
+
from enum import Enum
|
|
6
|
+
|
|
7
|
+
hookspec = pluggy.HookspecMarker("device_mgr")
|
|
8
|
+
|
|
9
|
+
"""
|
|
10
|
+
Scan -> Init -> Connect -> Commands -> Close
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class DeviceState(Enum):
|
|
15
|
+
"""Device lifecycle states"""
|
|
16
|
+
UNKNOWN = "unknown"
|
|
17
|
+
DISCOVERED = "discovered" # After scan
|
|
18
|
+
INITIALIZED = "initialized" # After init
|
|
19
|
+
CONNECTED = "connected" # After connect
|
|
20
|
+
ACTIVE = "active" # During command execution
|
|
21
|
+
DISCONNECTED = "disconnected" # After close
|
|
22
|
+
ERROR = "error" # Error state
|
|
23
|
+
|
|
24
|
+
class DevicePluginSpec:
|
|
25
|
+
"""Specification for device plugin lifecycle management"""
|
|
26
|
+
|
|
27
|
+
@hookspec
|
|
28
|
+
def scan(self) -> List[Device]:
|
|
29
|
+
"""Scan for available devices.
|
|
30
|
+
First step in device lifecycle.
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
list[Device]: A list of discovered devices matching the configuration.
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
@hookspec
|
|
37
|
+
def initialize(self, device: Device) -> bool:
|
|
38
|
+
"""Initialize the plugin for a specific device.
|
|
39
|
+
Second step in device lifecycle.
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
device: Device to initialize
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
bool: True if initialization successful
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
@hookspec
|
|
49
|
+
def connect(self, device: Device) -> bool:
|
|
50
|
+
"""Connect to the device.
|
|
51
|
+
Third step in device lifecycle.
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
device: Device to connect to
|
|
55
|
+
|
|
56
|
+
Returns:
|
|
57
|
+
bool: True if connection successful
|
|
58
|
+
"""
|
|
59
|
+
|
|
60
|
+
@hookspec
|
|
61
|
+
def command(self, device: Device, command: str) -> Optional[str]:
|
|
62
|
+
"""Send a command to the device.
|
|
63
|
+
Only available in CONNECTED state.
|
|
64
|
+
|
|
65
|
+
Args:
|
|
66
|
+
device: Target device
|
|
67
|
+
command: Command string to execute
|
|
68
|
+
|
|
69
|
+
Returns:
|
|
70
|
+
Optional[str]: Command response if any
|
|
71
|
+
"""
|
|
72
|
+
|
|
73
|
+
@hookspec
|
|
74
|
+
def reset(self, device: Device) -> bool:
|
|
75
|
+
"""Reset the device to its initial state.
|
|
76
|
+
Can be called from any state except UNKNOWN.
|
|
77
|
+
|
|
78
|
+
Args:
|
|
79
|
+
device: Device to reset
|
|
80
|
+
|
|
81
|
+
Returns:
|
|
82
|
+
bool: True if reset successful
|
|
83
|
+
"""
|
|
84
|
+
|
|
85
|
+
@hookspec
|
|
86
|
+
def close(self, device: Device) -> bool:
|
|
87
|
+
"""Close the device connection.
|
|
88
|
+
Final step in device lifecycle.
|
|
89
|
+
|
|
90
|
+
Args:
|
|
91
|
+
device: Device to close
|
|
92
|
+
|
|
93
|
+
Returns:
|
|
94
|
+
bool: True if closed successfully
|
|
95
|
+
"""
|
|
96
|
+
|
|
97
|
+
@hookspec
|
|
98
|
+
def execute(self, device: Device, target: str):
|
|
99
|
+
"""Execute an action on the target using the device."""
|
|
100
|
+
warnings.warn(
|
|
101
|
+
"The 'execute' method is deprecated and will be removed in a future release. "
|
|
102
|
+
"Please use the 'command' method instead.",
|
|
103
|
+
DeprecationWarning,
|
|
104
|
+
stacklevel=2
|
|
105
|
+
)
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
from typing import Dict, Optional
|
|
2
|
+
import logging
|
|
3
|
+
from iotsploit_core.domain.device import Device, DeviceType, SerialDevice, SocketCANDevice, USBDevice
|
|
4
|
+
from iotsploit_core.core.device_config import DeviceConfigManager
|
|
5
|
+
|
|
6
|
+
logger = logging.getLogger(__name__)
|
|
7
|
+
|
|
8
|
+
class DeviceStore:
|
|
9
|
+
def __init__(self):
|
|
10
|
+
self.devices = {}
|
|
11
|
+
self.device_sources = {}
|
|
12
|
+
self.config_manager = DeviceConfigManager()
|
|
13
|
+
|
|
14
|
+
def register_device(self, device: Device, source: str = "dynamic"):
|
|
15
|
+
"""注册设备并保存其配置"""
|
|
16
|
+
self.devices[device.device_id] = device
|
|
17
|
+
self.device_sources[device.device_id] = source
|
|
18
|
+
|
|
19
|
+
def get_device(self, device_id: str) -> Optional[Device]:
|
|
20
|
+
device = self.devices.get(device_id)
|
|
21
|
+
if not device:
|
|
22
|
+
config = self.config_manager.get_device_config(device_id)
|
|
23
|
+
if config:
|
|
24
|
+
return self._dict_to_device(config)
|
|
25
|
+
return device
|
|
26
|
+
|
|
27
|
+
def _device_to_dict(self, device: Device) -> Dict:
|
|
28
|
+
"""将设备对象转换为字典"""
|
|
29
|
+
base_dict = {
|
|
30
|
+
"device_id": device.device_id,
|
|
31
|
+
"name": device.name,
|
|
32
|
+
"device_type": device.device_type.value,
|
|
33
|
+
"attributes": device.attributes
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if isinstance(device, SerialDevice):
|
|
37
|
+
base_dict.update({
|
|
38
|
+
"port": device.port,
|
|
39
|
+
"baud_rate": device.baud_rate
|
|
40
|
+
})
|
|
41
|
+
elif isinstance(device, USBDevice):
|
|
42
|
+
base_dict.update({
|
|
43
|
+
"vendor_id": device.vendor_id,
|
|
44
|
+
"product_id": device.product_id
|
|
45
|
+
})
|
|
46
|
+
elif isinstance(device, SocketCANDevice):
|
|
47
|
+
base_dict.update({
|
|
48
|
+
"interface": device.interface
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
return base_dict
|
|
52
|
+
|
|
53
|
+
def _dict_to_device(self, data: Dict) -> Device:
|
|
54
|
+
"""从字典创建设备对象"""
|
|
55
|
+
device_type = DeviceType(data["device_type"])
|
|
56
|
+
|
|
57
|
+
if device_type == DeviceType.Serial:
|
|
58
|
+
return SerialDevice(
|
|
59
|
+
device_id=data["device_id"],
|
|
60
|
+
name=data["name"],
|
|
61
|
+
port=data.get("port", ""),
|
|
62
|
+
baud_rate=data.get("baud_rate", 115200),
|
|
63
|
+
attributes=data.get("attributes", {})
|
|
64
|
+
)
|
|
65
|
+
elif device_type == DeviceType.USB:
|
|
66
|
+
return USBDevice(
|
|
67
|
+
device_id=data["device_id"],
|
|
68
|
+
name=data["name"],
|
|
69
|
+
vendor_id=data.get("vendor_id", ""),
|
|
70
|
+
product_id=data.get("product_id", ""),
|
|
71
|
+
attributes=data.get("attributes", {})
|
|
72
|
+
)
|
|
73
|
+
elif device_type == DeviceType.CAN:
|
|
74
|
+
return SocketCANDevice(
|
|
75
|
+
device_id=data["device_id"],
|
|
76
|
+
name=data["name"],
|
|
77
|
+
interface=data.get("interface", "can0"),
|
|
78
|
+
attributes=data.get("attributes", {})
|
|
79
|
+
)
|
|
80
|
+
else:
|
|
81
|
+
return Device(
|
|
82
|
+
device_id=data["device_id"],
|
|
83
|
+
name=data["name"],
|
|
84
|
+
device_type=device_type,
|
|
85
|
+
attributes=data.get("attributes", {})
|
|
86
|
+
)
|