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.
Files changed (40) hide show
  1. iflow_mcp_bethington_cheat_engine_server_python-0.1.0.dist-info/METADATA +16 -0
  2. iflow_mcp_bethington_cheat_engine_server_python-0.1.0.dist-info/RECORD +40 -0
  3. iflow_mcp_bethington_cheat_engine_server_python-0.1.0.dist-info/WHEEL +5 -0
  4. iflow_mcp_bethington_cheat_engine_server_python-0.1.0.dist-info/entry_points.txt +2 -0
  5. iflow_mcp_bethington_cheat_engine_server_python-0.1.0.dist-info/licenses/LICENSE +21 -0
  6. iflow_mcp_bethington_cheat_engine_server_python-0.1.0.dist-info/top_level.txt +1 -0
  7. server/cheatengine/__init__.py +19 -0
  8. server/cheatengine/ce_bridge.py +1670 -0
  9. server/cheatengine/lua_interface.py +460 -0
  10. server/cheatengine/table_parser.py +1221 -0
  11. server/config/__init__.py +20 -0
  12. server/config/settings.py +347 -0
  13. server/config/whitelist.py +378 -0
  14. server/gui_automation/__init__.py +43 -0
  15. server/gui_automation/core/__init__.py +8 -0
  16. server/gui_automation/core/integration.py +951 -0
  17. server/gui_automation/demos/__init__.py +8 -0
  18. server/gui_automation/demos/basic_demo.py +754 -0
  19. server/gui_automation/demos/notepad_demo.py +460 -0
  20. server/gui_automation/demos/simple_demo.py +319 -0
  21. server/gui_automation/tools/__init__.py +8 -0
  22. server/gui_automation/tools/mcp_tools.py +974 -0
  23. server/main.py +519 -0
  24. server/memory/__init__.py +0 -0
  25. server/memory/analyzer.py +0 -0
  26. server/memory/reader.py +0 -0
  27. server/memory/scanner.py +0 -0
  28. server/memory/symbols.py +0 -0
  29. server/process/__init__.py +16 -0
  30. server/process/launcher.py +608 -0
  31. server/process/manager.py +185 -0
  32. server/process/monitors.py +202 -0
  33. server/process/permissions.py +131 -0
  34. server/process_whitelist.json +119 -0
  35. server/pyautogui/__init__.py +0 -0
  36. server/utils/__init__.py +37 -0
  37. server/utils/data_types.py +368 -0
  38. server/utils/formatters.py +430 -0
  39. server/utils/validators.py +340 -0
  40. 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
+ }