iflow-mcp_bethington-cheat-engine-server-python 0.1.0__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.
- iflow_mcp_bethington_cheat_engine_server_python-0.1.0.dist-info/METADATA +16 -0
- iflow_mcp_bethington_cheat_engine_server_python-0.1.0.dist-info/RECORD +40 -0
- iflow_mcp_bethington_cheat_engine_server_python-0.1.0.dist-info/WHEEL +5 -0
- iflow_mcp_bethington_cheat_engine_server_python-0.1.0.dist-info/entry_points.txt +2 -0
- iflow_mcp_bethington_cheat_engine_server_python-0.1.0.dist-info/licenses/LICENSE +21 -0
- iflow_mcp_bethington_cheat_engine_server_python-0.1.0.dist-info/top_level.txt +1 -0
- server/cheatengine/__init__.py +19 -0
- server/cheatengine/ce_bridge.py +1670 -0
- server/cheatengine/lua_interface.py +460 -0
- server/cheatengine/table_parser.py +1221 -0
- server/config/__init__.py +20 -0
- server/config/settings.py +347 -0
- server/config/whitelist.py +378 -0
- server/gui_automation/__init__.py +43 -0
- server/gui_automation/core/__init__.py +8 -0
- server/gui_automation/core/integration.py +951 -0
- server/gui_automation/demos/__init__.py +8 -0
- server/gui_automation/demos/basic_demo.py +754 -0
- server/gui_automation/demos/notepad_demo.py +460 -0
- server/gui_automation/demos/simple_demo.py +319 -0
- server/gui_automation/tools/__init__.py +8 -0
- server/gui_automation/tools/mcp_tools.py +974 -0
- server/main.py +519 -0
- server/memory/__init__.py +0 -0
- server/memory/analyzer.py +0 -0
- server/memory/reader.py +0 -0
- server/memory/scanner.py +0 -0
- server/memory/symbols.py +0 -0
- server/process/__init__.py +16 -0
- server/process/launcher.py +608 -0
- server/process/manager.py +185 -0
- server/process/monitors.py +202 -0
- server/process/permissions.py +131 -0
- server/process_whitelist.json +119 -0
- server/pyautogui/__init__.py +0 -0
- server/utils/__init__.py +37 -0
- server/utils/data_types.py +368 -0
- server/utils/formatters.py +430 -0
- server/utils/validators.py +340 -0
- server/window_automation/__init__.py +59 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Configuration Module
|
|
3
|
+
Handles server settings and security configuration
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from .settings import (
|
|
7
|
+
ServerConfig, SecurityConfig, AnalysisConfig,
|
|
8
|
+
PerformanceConfig, LoggingConfig
|
|
9
|
+
)
|
|
10
|
+
from .whitelist import ProcessWhitelist, WhitelistEntry
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
'ServerConfig',
|
|
14
|
+
'SecurityConfig',
|
|
15
|
+
'AnalysisConfig',
|
|
16
|
+
'PerformanceConfig',
|
|
17
|
+
'LoggingConfig',
|
|
18
|
+
'ProcessWhitelist',
|
|
19
|
+
'WhitelistEntry'
|
|
20
|
+
]
|
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Server Configuration Module
|
|
3
|
+
Handles server settings and configuration management
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import json
|
|
7
|
+
import os
|
|
8
|
+
import logging
|
|
9
|
+
from typing import Dict, Any, Optional, List
|
|
10
|
+
from dataclasses import dataclass, asdict
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
|
|
13
|
+
logger = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
@dataclass
|
|
16
|
+
class SecurityConfig:
|
|
17
|
+
"""Security-related configuration"""
|
|
18
|
+
read_only_mode: bool = True
|
|
19
|
+
enable_audit_log: bool = True
|
|
20
|
+
audit_log_path: str = "audit.log"
|
|
21
|
+
max_memory_read_size: int = 10 * 1024 * 1024 # 10MB
|
|
22
|
+
require_elevation: bool = False
|
|
23
|
+
enable_process_whitelist: bool = True
|
|
24
|
+
whitelist_path: str = "process_whitelist.json"
|
|
25
|
+
|
|
26
|
+
@dataclass
|
|
27
|
+
class AnalysisConfig:
|
|
28
|
+
"""Analysis-related configuration"""
|
|
29
|
+
enable_disassembly: bool = True
|
|
30
|
+
enable_symbol_loading: bool = True
|
|
31
|
+
symbol_cache_size: int = 1000
|
|
32
|
+
max_scan_results: int = 10000
|
|
33
|
+
scan_chunk_size: int = 1024 * 1024 # 1MB
|
|
34
|
+
structure_analysis_depth: int = 3
|
|
35
|
+
auto_detect_architecture: bool = True
|
|
36
|
+
|
|
37
|
+
@dataclass
|
|
38
|
+
class PerformanceConfig:
|
|
39
|
+
"""Performance-related configuration"""
|
|
40
|
+
memory_cache_size: int = 100 * 1024 * 1024 # 100MB
|
|
41
|
+
cache_timeout: float = 300.0 # 5 minutes
|
|
42
|
+
max_concurrent_scans: int = 2
|
|
43
|
+
scan_timeout: float = 30.0
|
|
44
|
+
background_cleanup_interval: float = 60.0
|
|
45
|
+
|
|
46
|
+
@dataclass
|
|
47
|
+
class LoggingConfig:
|
|
48
|
+
"""Logging configuration"""
|
|
49
|
+
log_level: str = "INFO"
|
|
50
|
+
log_to_file: bool = True
|
|
51
|
+
log_file_path: str = "mcp_cheat_engine.log"
|
|
52
|
+
max_log_size: int = 10 * 1024 * 1024 # 10MB
|
|
53
|
+
log_backup_count: int = 5
|
|
54
|
+
enable_debug_logging: bool = False
|
|
55
|
+
|
|
56
|
+
class ServerConfig:
|
|
57
|
+
"""Main server configuration manager"""
|
|
58
|
+
|
|
59
|
+
def __init__(self):
|
|
60
|
+
self.security = SecurityConfig()
|
|
61
|
+
self.analysis = AnalysisConfig()
|
|
62
|
+
self.performance = PerformanceConfig()
|
|
63
|
+
self.logging = LoggingConfig()
|
|
64
|
+
self.config_file: Optional[str] = None
|
|
65
|
+
self._loaded = False
|
|
66
|
+
|
|
67
|
+
def load_config(self, config_path: Optional[str] = None):
|
|
68
|
+
"""Load configuration from file
|
|
69
|
+
|
|
70
|
+
Args:
|
|
71
|
+
config_path: Path to configuration file (optional)
|
|
72
|
+
"""
|
|
73
|
+
if config_path and os.path.exists(config_path):
|
|
74
|
+
self.config_file = config_path
|
|
75
|
+
try:
|
|
76
|
+
with open(config_path, 'r') as f:
|
|
77
|
+
config_data = json.load(f)
|
|
78
|
+
|
|
79
|
+
self._apply_config_data(config_data)
|
|
80
|
+
self._loaded = True
|
|
81
|
+
logger.info(f"Configuration loaded from {config_path}")
|
|
82
|
+
|
|
83
|
+
except Exception as e:
|
|
84
|
+
logger.error(f"Failed to load config from {config_path}: {e}")
|
|
85
|
+
self._load_defaults()
|
|
86
|
+
else:
|
|
87
|
+
logger.info("Using default configuration")
|
|
88
|
+
self._load_defaults()
|
|
89
|
+
|
|
90
|
+
# Validate configuration
|
|
91
|
+
self._validate_config()
|
|
92
|
+
|
|
93
|
+
def _load_defaults(self):
|
|
94
|
+
"""Load default configuration values"""
|
|
95
|
+
# Defaults are already set in dataclass definitions
|
|
96
|
+
self._loaded = True
|
|
97
|
+
|
|
98
|
+
def _apply_config_data(self, config_data: Dict[str, Any]):
|
|
99
|
+
"""Apply configuration data from dictionary"""
|
|
100
|
+
|
|
101
|
+
# Security settings
|
|
102
|
+
if 'security' in config_data:
|
|
103
|
+
sec_config = config_data['security']
|
|
104
|
+
for key, value in sec_config.items():
|
|
105
|
+
if hasattr(self.security, key):
|
|
106
|
+
setattr(self.security, key, value)
|
|
107
|
+
|
|
108
|
+
# Analysis settings
|
|
109
|
+
if 'analysis' in config_data:
|
|
110
|
+
analysis_config = config_data['analysis']
|
|
111
|
+
for key, value in analysis_config.items():
|
|
112
|
+
if hasattr(self.analysis, key):
|
|
113
|
+
setattr(self.analysis, key, value)
|
|
114
|
+
|
|
115
|
+
# Performance settings
|
|
116
|
+
if 'performance' in config_data:
|
|
117
|
+
perf_config = config_data['performance']
|
|
118
|
+
for key, value in perf_config.items():
|
|
119
|
+
if hasattr(self.performance, key):
|
|
120
|
+
setattr(self.performance, key, value)
|
|
121
|
+
|
|
122
|
+
# Logging settings
|
|
123
|
+
if 'logging' in config_data:
|
|
124
|
+
log_config = config_data['logging']
|
|
125
|
+
for key, value in log_config.items():
|
|
126
|
+
if hasattr(self.logging, key):
|
|
127
|
+
setattr(self.logging, key, value)
|
|
128
|
+
|
|
129
|
+
def _validate_config(self):
|
|
130
|
+
"""Validate configuration values"""
|
|
131
|
+
|
|
132
|
+
# Validate security settings
|
|
133
|
+
if self.security.max_memory_read_size <= 0:
|
|
134
|
+
logger.warning("Invalid max_memory_read_size, using default")
|
|
135
|
+
self.security.max_memory_read_size = 10 * 1024 * 1024
|
|
136
|
+
|
|
137
|
+
if self.security.max_memory_read_size > 1024 * 1024 * 1024: # 1GB limit
|
|
138
|
+
logger.warning("max_memory_read_size too large, capping at 1GB")
|
|
139
|
+
self.security.max_memory_read_size = 1024 * 1024 * 1024
|
|
140
|
+
|
|
141
|
+
# Validate analysis settings
|
|
142
|
+
if self.analysis.max_scan_results <= 0:
|
|
143
|
+
self.analysis.max_scan_results = 10000
|
|
144
|
+
|
|
145
|
+
if self.analysis.scan_chunk_size <= 0:
|
|
146
|
+
self.analysis.scan_chunk_size = 1024 * 1024
|
|
147
|
+
|
|
148
|
+
# Validate performance settings
|
|
149
|
+
if self.performance.cache_timeout <= 0:
|
|
150
|
+
self.performance.cache_timeout = 300.0
|
|
151
|
+
|
|
152
|
+
if self.performance.max_concurrent_scans <= 0:
|
|
153
|
+
self.performance.max_concurrent_scans = 1
|
|
154
|
+
|
|
155
|
+
# Validate logging settings
|
|
156
|
+
valid_log_levels = ['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL']
|
|
157
|
+
if self.logging.log_level.upper() not in valid_log_levels:
|
|
158
|
+
logger.warning(f"Invalid log level {self.logging.log_level}, using INFO")
|
|
159
|
+
self.logging.log_level = "INFO"
|
|
160
|
+
|
|
161
|
+
def save_config(self, config_path: Optional[str] = None):
|
|
162
|
+
"""Save current configuration to file
|
|
163
|
+
|
|
164
|
+
Args:
|
|
165
|
+
config_path: Path to save configuration (optional, uses loaded path if not specified)
|
|
166
|
+
"""
|
|
167
|
+
save_path = config_path or self.config_file or "config.json"
|
|
168
|
+
|
|
169
|
+
try:
|
|
170
|
+
config_data = {
|
|
171
|
+
'security': asdict(self.security),
|
|
172
|
+
'analysis': asdict(self.analysis),
|
|
173
|
+
'performance': asdict(self.performance),
|
|
174
|
+
'logging': asdict(self.logging)
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
with open(save_path, 'w') as f:
|
|
178
|
+
json.dump(config_data, f, indent=2)
|
|
179
|
+
|
|
180
|
+
logger.info(f"Configuration saved to {save_path}")
|
|
181
|
+
|
|
182
|
+
except Exception as e:
|
|
183
|
+
logger.error(f"Failed to save config to {save_path}: {e}")
|
|
184
|
+
|
|
185
|
+
def get_whitelist_path(self) -> str:
|
|
186
|
+
"""Get the process whitelist file path"""
|
|
187
|
+
if os.path.isabs(self.security.whitelist_path):
|
|
188
|
+
return self.security.whitelist_path
|
|
189
|
+
else:
|
|
190
|
+
# Relative to config file directory or current directory
|
|
191
|
+
if self.config_file:
|
|
192
|
+
config_dir = os.path.dirname(self.config_file)
|
|
193
|
+
return os.path.join(config_dir, self.security.whitelist_path)
|
|
194
|
+
else:
|
|
195
|
+
return self.security.whitelist_path
|
|
196
|
+
|
|
197
|
+
def get_audit_log_path(self) -> str:
|
|
198
|
+
"""Get the audit log file path"""
|
|
199
|
+
if os.path.isabs(self.security.audit_log_path):
|
|
200
|
+
return self.security.audit_log_path
|
|
201
|
+
else:
|
|
202
|
+
# Relative to config file directory or current directory
|
|
203
|
+
if self.config_file:
|
|
204
|
+
config_dir = os.path.dirname(self.config_file)
|
|
205
|
+
return os.path.join(config_dir, self.security.audit_log_path)
|
|
206
|
+
else:
|
|
207
|
+
return self.security.audit_log_path
|
|
208
|
+
|
|
209
|
+
def get_log_file_path(self) -> str:
|
|
210
|
+
"""Get the main log file path"""
|
|
211
|
+
if os.path.isabs(self.logging.log_file_path):
|
|
212
|
+
return self.logging.log_file_path
|
|
213
|
+
else:
|
|
214
|
+
# Relative to config file directory or current directory
|
|
215
|
+
if self.config_file:
|
|
216
|
+
config_dir = os.path.dirname(self.config_file)
|
|
217
|
+
return os.path.join(config_dir, self.logging.log_file_path)
|
|
218
|
+
else:
|
|
219
|
+
return self.logging.log_file_path
|
|
220
|
+
|
|
221
|
+
def is_read_only_mode(self) -> bool:
|
|
222
|
+
"""Check if server is in read-only mode"""
|
|
223
|
+
return self.security.read_only_mode
|
|
224
|
+
|
|
225
|
+
def is_audit_enabled(self) -> bool:
|
|
226
|
+
"""Check if audit logging is enabled"""
|
|
227
|
+
return self.security.enable_audit_log
|
|
228
|
+
|
|
229
|
+
def get_max_memory_read_size(self) -> int:
|
|
230
|
+
"""Get maximum allowed memory read size"""
|
|
231
|
+
return self.security.max_memory_read_size
|
|
232
|
+
|
|
233
|
+
def is_process_whitelist_enabled(self) -> bool:
|
|
234
|
+
"""Check if process whitelist is enabled"""
|
|
235
|
+
return self.security.enable_process_whitelist
|
|
236
|
+
|
|
237
|
+
def create_default_config_file(self, path: str = "config.json"):
|
|
238
|
+
"""Create a default configuration file
|
|
239
|
+
|
|
240
|
+
Args:
|
|
241
|
+
path: Path where to create the config file
|
|
242
|
+
"""
|
|
243
|
+
try:
|
|
244
|
+
# Create default configuration
|
|
245
|
+
default_config = {
|
|
246
|
+
"security": {
|
|
247
|
+
"read_only_mode": True,
|
|
248
|
+
"enable_audit_log": True,
|
|
249
|
+
"audit_log_path": "audit.log",
|
|
250
|
+
"max_memory_read_size": 10485760,
|
|
251
|
+
"require_elevation": False,
|
|
252
|
+
"enable_process_whitelist": True,
|
|
253
|
+
"whitelist_path": "process_whitelist.json"
|
|
254
|
+
},
|
|
255
|
+
"analysis": {
|
|
256
|
+
"enable_disassembly": True,
|
|
257
|
+
"enable_symbol_loading": True,
|
|
258
|
+
"symbol_cache_size": 1000,
|
|
259
|
+
"max_scan_results": 10000,
|
|
260
|
+
"scan_chunk_size": 1048576,
|
|
261
|
+
"structure_analysis_depth": 3,
|
|
262
|
+
"auto_detect_architecture": True
|
|
263
|
+
},
|
|
264
|
+
"performance": {
|
|
265
|
+
"memory_cache_size": 104857600,
|
|
266
|
+
"cache_timeout": 300.0,
|
|
267
|
+
"max_concurrent_scans": 2,
|
|
268
|
+
"scan_timeout": 30.0,
|
|
269
|
+
"background_cleanup_interval": 60.0
|
|
270
|
+
},
|
|
271
|
+
"logging": {
|
|
272
|
+
"log_level": "INFO",
|
|
273
|
+
"log_to_file": True,
|
|
274
|
+
"log_file_path": "mcp_cheat_engine.log",
|
|
275
|
+
"max_log_size": 10485760,
|
|
276
|
+
"log_backup_count": 5,
|
|
277
|
+
"enable_debug_logging": False
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
with open(path, 'w') as f:
|
|
282
|
+
json.dump(default_config, f, indent=2)
|
|
283
|
+
|
|
284
|
+
logger.info(f"Default configuration created at {path}")
|
|
285
|
+
return True
|
|
286
|
+
|
|
287
|
+
except Exception as e:
|
|
288
|
+
logger.error(f"Failed to create default config at {path}: {e}")
|
|
289
|
+
return False
|
|
290
|
+
|
|
291
|
+
def update_setting(self, section: str, key: str, value: Any):
|
|
292
|
+
"""Update a specific configuration setting
|
|
293
|
+
|
|
294
|
+
Args:
|
|
295
|
+
section: Configuration section ('security', 'analysis', 'performance', 'logging')
|
|
296
|
+
key: Setting key
|
|
297
|
+
value: New value
|
|
298
|
+
"""
|
|
299
|
+
try:
|
|
300
|
+
if section == 'security' and hasattr(self.security, key):
|
|
301
|
+
setattr(self.security, key, value)
|
|
302
|
+
elif section == 'analysis' and hasattr(self.analysis, key):
|
|
303
|
+
setattr(self.analysis, key, value)
|
|
304
|
+
elif section == 'performance' and hasattr(self.performance, key):
|
|
305
|
+
setattr(self.performance, key, value)
|
|
306
|
+
elif section == 'logging' and hasattr(self.logging, key):
|
|
307
|
+
setattr(self.logging, key, value)
|
|
308
|
+
else:
|
|
309
|
+
raise ValueError(f"Invalid section '{section}' or key '{key}'")
|
|
310
|
+
|
|
311
|
+
# Re-validate after update
|
|
312
|
+
self._validate_config()
|
|
313
|
+
logger.info(f"Updated {section}.{key} = {value}")
|
|
314
|
+
|
|
315
|
+
except Exception as e:
|
|
316
|
+
logger.error(f"Failed to update setting {section}.{key}: {e}")
|
|
317
|
+
raise
|
|
318
|
+
|
|
319
|
+
def get_setting(self, section: str, key: str) -> Any:
|
|
320
|
+
"""Get a specific configuration setting
|
|
321
|
+
|
|
322
|
+
Args:
|
|
323
|
+
section: Configuration section
|
|
324
|
+
key: Setting key
|
|
325
|
+
|
|
326
|
+
Returns:
|
|
327
|
+
Setting value
|
|
328
|
+
"""
|
|
329
|
+
if section == 'security' and hasattr(self.security, key):
|
|
330
|
+
return getattr(self.security, key)
|
|
331
|
+
elif section == 'analysis' and hasattr(self.analysis, key):
|
|
332
|
+
return getattr(self.analysis, key)
|
|
333
|
+
elif section == 'performance' and hasattr(self.performance, key):
|
|
334
|
+
return getattr(self.performance, key)
|
|
335
|
+
elif section == 'logging' and hasattr(self.logging, key):
|
|
336
|
+
return getattr(self.logging, key)
|
|
337
|
+
else:
|
|
338
|
+
raise ValueError(f"Invalid section '{section}' or key '{key}'")
|
|
339
|
+
|
|
340
|
+
def get_all_settings(self) -> Dict[str, Dict[str, Any]]:
|
|
341
|
+
"""Get all configuration settings as a dictionary"""
|
|
342
|
+
return {
|
|
343
|
+
'security': asdict(self.security),
|
|
344
|
+
'analysis': asdict(self.analysis),
|
|
345
|
+
'performance': asdict(self.performance),
|
|
346
|
+
'logging': asdict(self.logging)
|
|
347
|
+
}
|