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,378 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Process Whitelist Module
|
|
3
|
+
Manages allowed processes for security
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import json
|
|
7
|
+
import os
|
|
8
|
+
import logging
|
|
9
|
+
import re
|
|
10
|
+
from typing import List, Set, Dict, Any, Optional
|
|
11
|
+
from dataclasses import dataclass
|
|
12
|
+
from datetime import datetime
|
|
13
|
+
|
|
14
|
+
logger = logging.getLogger(__name__)
|
|
15
|
+
|
|
16
|
+
@dataclass
|
|
17
|
+
class WhitelistEntry:
|
|
18
|
+
"""Single whitelist entry"""
|
|
19
|
+
process_name: str
|
|
20
|
+
description: str
|
|
21
|
+
category: str
|
|
22
|
+
added_date: str
|
|
23
|
+
enabled: bool = True
|
|
24
|
+
exact_match: bool = True
|
|
25
|
+
|
|
26
|
+
def matches(self, process_name: str) -> bool:
|
|
27
|
+
"""Check if this entry matches a process name"""
|
|
28
|
+
if not self.enabled:
|
|
29
|
+
return False
|
|
30
|
+
|
|
31
|
+
if self.exact_match:
|
|
32
|
+
return self.process_name.lower() == process_name.lower()
|
|
33
|
+
else:
|
|
34
|
+
# Pattern matching for non-exact matches
|
|
35
|
+
try:
|
|
36
|
+
pattern = self.process_name.replace('*', '.*').replace('?', '.')
|
|
37
|
+
return bool(re.match(pattern, process_name, re.IGNORECASE))
|
|
38
|
+
except re.error:
|
|
39
|
+
# Fallback to exact match if regex is invalid
|
|
40
|
+
return self.process_name.lower() == process_name.lower()
|
|
41
|
+
|
|
42
|
+
class ProcessWhitelist:
|
|
43
|
+
"""Manages process whitelist for security"""
|
|
44
|
+
|
|
45
|
+
def __init__(self):
|
|
46
|
+
self.entries: List[WhitelistEntry] = []
|
|
47
|
+
self.enabled = True
|
|
48
|
+
self.whitelist_file: Optional[str] = None
|
|
49
|
+
self.last_modified = 0
|
|
50
|
+
self._initialize_defaults()
|
|
51
|
+
|
|
52
|
+
def _initialize_defaults(self):
|
|
53
|
+
"""Initialize with default safe processes"""
|
|
54
|
+
default_entries = [
|
|
55
|
+
# Development tools
|
|
56
|
+
WhitelistEntry("notepad.exe", "Windows Notepad", "system", self._get_timestamp()),
|
|
57
|
+
WhitelistEntry("code.exe", "Visual Studio Code", "development", self._get_timestamp()),
|
|
58
|
+
WhitelistEntry("devenv.exe", "Visual Studio", "development", self._get_timestamp()),
|
|
59
|
+
WhitelistEntry("windbg.exe", "Windows Debugger", "development", self._get_timestamp()),
|
|
60
|
+
WhitelistEntry("x64dbg.exe", "x64dbg Debugger", "development", self._get_timestamp()),
|
|
61
|
+
WhitelistEntry("ollydbg.exe", "OllyDbg Debugger", "development", self._get_timestamp()),
|
|
62
|
+
|
|
63
|
+
# Common safe applications
|
|
64
|
+
WhitelistEntry("calc.exe", "Windows Calculator", "system", self._get_timestamp()),
|
|
65
|
+
WhitelistEntry("mspaint.exe", "Microsoft Paint", "system", self._get_timestamp()),
|
|
66
|
+
WhitelistEntry("wordpad.exe", "Windows WordPad", "system", self._get_timestamp()),
|
|
67
|
+
|
|
68
|
+
# Games (educational purposes)
|
|
69
|
+
WhitelistEntry("minesweeper.exe", "Minesweeper", "game", self._get_timestamp()),
|
|
70
|
+
WhitelistEntry("solitaire.exe", "Solitaire", "game", self._get_timestamp()),
|
|
71
|
+
|
|
72
|
+
# Test applications
|
|
73
|
+
WhitelistEntry("test*.exe", "Test Applications", "test", self._get_timestamp(), exact_match=False),
|
|
74
|
+
WhitelistEntry("demo*.exe", "Demo Applications", "test", self._get_timestamp(), exact_match=False),
|
|
75
|
+
]
|
|
76
|
+
|
|
77
|
+
self.entries = default_entries
|
|
78
|
+
|
|
79
|
+
def _get_timestamp(self) -> str:
|
|
80
|
+
"""Get current timestamp as string"""
|
|
81
|
+
return datetime.now().isoformat()
|
|
82
|
+
|
|
83
|
+
def load_whitelist(self, whitelist_path: str):
|
|
84
|
+
"""Load whitelist from file
|
|
85
|
+
|
|
86
|
+
Args:
|
|
87
|
+
whitelist_path: Path to whitelist file
|
|
88
|
+
"""
|
|
89
|
+
self.whitelist_file = whitelist_path
|
|
90
|
+
|
|
91
|
+
if not os.path.exists(whitelist_path):
|
|
92
|
+
logger.info(f"Whitelist file not found, creating default: {whitelist_path}")
|
|
93
|
+
self.save_whitelist()
|
|
94
|
+
return
|
|
95
|
+
|
|
96
|
+
try:
|
|
97
|
+
# Check if file was modified
|
|
98
|
+
file_mtime = os.path.getmtime(whitelist_path)
|
|
99
|
+
if file_mtime <= self.last_modified:
|
|
100
|
+
return # No changes
|
|
101
|
+
|
|
102
|
+
with open(whitelist_path, 'r') as f:
|
|
103
|
+
data = json.load(f)
|
|
104
|
+
|
|
105
|
+
# Load configuration
|
|
106
|
+
self.enabled = data.get('enabled', True)
|
|
107
|
+
|
|
108
|
+
# Load entries
|
|
109
|
+
entries_data = data.get('entries', [])
|
|
110
|
+
self.entries = []
|
|
111
|
+
|
|
112
|
+
for entry_data in entries_data:
|
|
113
|
+
entry = WhitelistEntry(
|
|
114
|
+
process_name=entry_data['process_name'],
|
|
115
|
+
description=entry_data.get('description', ''),
|
|
116
|
+
category=entry_data.get('category', 'custom'),
|
|
117
|
+
added_date=entry_data.get('added_date', self._get_timestamp()),
|
|
118
|
+
enabled=entry_data.get('enabled', True),
|
|
119
|
+
exact_match=entry_data.get('exact_match', True)
|
|
120
|
+
)
|
|
121
|
+
self.entries.append(entry)
|
|
122
|
+
|
|
123
|
+
self.last_modified = file_mtime
|
|
124
|
+
logger.info(f"Loaded {len(self.entries)} whitelist entries from {whitelist_path}")
|
|
125
|
+
|
|
126
|
+
except Exception as e:
|
|
127
|
+
logger.error(f"Failed to load whitelist from {whitelist_path}: {e}")
|
|
128
|
+
logger.info("Using default whitelist")
|
|
129
|
+
|
|
130
|
+
def save_whitelist(self, whitelist_path: Optional[str] = None):
|
|
131
|
+
"""Save whitelist to file
|
|
132
|
+
|
|
133
|
+
Args:
|
|
134
|
+
whitelist_path: Path to save whitelist (optional)
|
|
135
|
+
"""
|
|
136
|
+
save_path = whitelist_path or self.whitelist_file or "process_whitelist.json"
|
|
137
|
+
|
|
138
|
+
try:
|
|
139
|
+
data = {
|
|
140
|
+
'enabled': self.enabled,
|
|
141
|
+
'description': 'Process whitelist for MCP Cheat Engine Server',
|
|
142
|
+
'last_updated': self._get_timestamp(),
|
|
143
|
+
'entries': []
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
for entry in self.entries:
|
|
147
|
+
entry_data = {
|
|
148
|
+
'process_name': entry.process_name,
|
|
149
|
+
'description': entry.description,
|
|
150
|
+
'category': entry.category,
|
|
151
|
+
'added_date': entry.added_date,
|
|
152
|
+
'enabled': entry.enabled,
|
|
153
|
+
'exact_match': entry.exact_match
|
|
154
|
+
}
|
|
155
|
+
data['entries'].append(entry_data)
|
|
156
|
+
|
|
157
|
+
with open(save_path, 'w') as f:
|
|
158
|
+
json.dump(data, f, indent=2)
|
|
159
|
+
|
|
160
|
+
logger.info(f"Saved whitelist to {save_path}")
|
|
161
|
+
|
|
162
|
+
except Exception as e:
|
|
163
|
+
logger.error(f"Failed to save whitelist to {save_path}: {e}")
|
|
164
|
+
|
|
165
|
+
def is_enabled(self) -> bool:
|
|
166
|
+
"""Check if whitelist is enabled"""
|
|
167
|
+
return self.enabled
|
|
168
|
+
|
|
169
|
+
def is_allowed(self, process_name: str) -> bool:
|
|
170
|
+
"""Check if a process is allowed by the whitelist
|
|
171
|
+
|
|
172
|
+
Args:
|
|
173
|
+
process_name: Name of the process to check
|
|
174
|
+
|
|
175
|
+
Returns:
|
|
176
|
+
True if allowed, False otherwise
|
|
177
|
+
"""
|
|
178
|
+
if not self.enabled:
|
|
179
|
+
return True # If whitelist is disabled, allow all
|
|
180
|
+
|
|
181
|
+
# Check against each whitelist entry
|
|
182
|
+
for entry in self.entries:
|
|
183
|
+
if entry.matches(process_name):
|
|
184
|
+
return True
|
|
185
|
+
|
|
186
|
+
return False
|
|
187
|
+
|
|
188
|
+
def add_process(self, process_name: str, description: str = "", category: str = "custom") -> bool:
|
|
189
|
+
"""Add a process to the whitelist
|
|
190
|
+
|
|
191
|
+
Args:
|
|
192
|
+
process_name: Name of the process
|
|
193
|
+
description: Description of the process
|
|
194
|
+
category: Category for organization
|
|
195
|
+
|
|
196
|
+
Returns:
|
|
197
|
+
True if added, False if already exists
|
|
198
|
+
"""
|
|
199
|
+
# Check if already exists
|
|
200
|
+
for entry in self.entries:
|
|
201
|
+
if entry.process_name.lower() == process_name.lower() and entry.exact_match:
|
|
202
|
+
return False
|
|
203
|
+
|
|
204
|
+
entry = WhitelistEntry(
|
|
205
|
+
process_name=process_name,
|
|
206
|
+
description=description or f"Custom entry for {process_name}",
|
|
207
|
+
category=category,
|
|
208
|
+
added_date=self._get_timestamp()
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
self.entries.append(entry)
|
|
212
|
+
logger.info(f"Added process to whitelist: {process_name}")
|
|
213
|
+
|
|
214
|
+
# Auto-save if we have a file path
|
|
215
|
+
if self.whitelist_file:
|
|
216
|
+
self.save_whitelist()
|
|
217
|
+
|
|
218
|
+
return True
|
|
219
|
+
|
|
220
|
+
def remove_process(self, process_name: str) -> bool:
|
|
221
|
+
"""Remove a process from the whitelist
|
|
222
|
+
|
|
223
|
+
Args:
|
|
224
|
+
process_name: Name of the process to remove
|
|
225
|
+
|
|
226
|
+
Returns:
|
|
227
|
+
True if removed, False if not found
|
|
228
|
+
"""
|
|
229
|
+
original_count = len(self.entries)
|
|
230
|
+
self.entries = [entry for entry in self.entries
|
|
231
|
+
if entry.process_name.lower() != process_name.lower()]
|
|
232
|
+
|
|
233
|
+
removed = len(self.entries) < original_count
|
|
234
|
+
|
|
235
|
+
if removed:
|
|
236
|
+
logger.info(f"Removed process from whitelist: {process_name}")
|
|
237
|
+
# Auto-save if we have a file path
|
|
238
|
+
if self.whitelist_file:
|
|
239
|
+
self.save_whitelist()
|
|
240
|
+
|
|
241
|
+
return removed
|
|
242
|
+
|
|
243
|
+
def enable_process(self, process_name: str) -> bool:
|
|
244
|
+
"""Enable a process in the whitelist
|
|
245
|
+
|
|
246
|
+
Args:
|
|
247
|
+
process_name: Name of the process to enable
|
|
248
|
+
|
|
249
|
+
Returns:
|
|
250
|
+
True if found and enabled, False otherwise
|
|
251
|
+
"""
|
|
252
|
+
for entry in self.entries:
|
|
253
|
+
if entry.process_name.lower() == process_name.lower():
|
|
254
|
+
entry.enabled = True
|
|
255
|
+
logger.info(f"Enabled process in whitelist: {process_name}")
|
|
256
|
+
return True
|
|
257
|
+
|
|
258
|
+
return False
|
|
259
|
+
|
|
260
|
+
def disable_process(self, process_name: str) -> bool:
|
|
261
|
+
"""Disable a process in the whitelist
|
|
262
|
+
|
|
263
|
+
Args:
|
|
264
|
+
process_name: Name of the process to disable
|
|
265
|
+
|
|
266
|
+
Returns:
|
|
267
|
+
True if found and disabled, False otherwise
|
|
268
|
+
"""
|
|
269
|
+
for entry in self.entries:
|
|
270
|
+
if entry.process_name.lower() == process_name.lower():
|
|
271
|
+
entry.enabled = False
|
|
272
|
+
logger.info(f"Disabled process in whitelist: {process_name}")
|
|
273
|
+
return True
|
|
274
|
+
|
|
275
|
+
return False
|
|
276
|
+
|
|
277
|
+
def get_processes_by_category(self, category: str) -> List[WhitelistEntry]:
|
|
278
|
+
"""Get all processes in a specific category
|
|
279
|
+
|
|
280
|
+
Args:
|
|
281
|
+
category: Category to filter by
|
|
282
|
+
|
|
283
|
+
Returns:
|
|
284
|
+
List of whitelist entries in the category
|
|
285
|
+
"""
|
|
286
|
+
return [entry for entry in self.entries if entry.category == category]
|
|
287
|
+
|
|
288
|
+
def get_all_categories(self) -> Set[str]:
|
|
289
|
+
"""Get all categories in the whitelist"""
|
|
290
|
+
return {entry.category for entry in self.entries}
|
|
291
|
+
|
|
292
|
+
def get_enabled_processes(self) -> List[str]:
|
|
293
|
+
"""Get list of all enabled process names"""
|
|
294
|
+
return [entry.process_name for entry in self.entries if entry.enabled]
|
|
295
|
+
|
|
296
|
+
def get_whitelist_summary(self) -> Dict[str, Any]:
|
|
297
|
+
"""Get summary of whitelist status"""
|
|
298
|
+
enabled_count = sum(1 for entry in self.entries if entry.enabled)
|
|
299
|
+
categories = self.get_all_categories()
|
|
300
|
+
|
|
301
|
+
return {
|
|
302
|
+
'enabled': self.enabled,
|
|
303
|
+
'total_entries': len(self.entries),
|
|
304
|
+
'enabled_entries': enabled_count,
|
|
305
|
+
'disabled_entries': len(self.entries) - enabled_count,
|
|
306
|
+
'categories': sorted(list(categories)),
|
|
307
|
+
'last_modified': self.last_modified
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
def import_processes(self, process_list: List[str], category: str = "imported"):
|
|
311
|
+
"""Import a list of processes to the whitelist
|
|
312
|
+
|
|
313
|
+
Args:
|
|
314
|
+
process_list: List of process names to import
|
|
315
|
+
category: Category for the imported processes
|
|
316
|
+
"""
|
|
317
|
+
added_count = 0
|
|
318
|
+
|
|
319
|
+
for process_name in process_list:
|
|
320
|
+
if self.add_process(process_name, f"Imported process", category):
|
|
321
|
+
added_count += 1
|
|
322
|
+
|
|
323
|
+
logger.info(f"Imported {added_count} processes to whitelist")
|
|
324
|
+
return added_count
|
|
325
|
+
|
|
326
|
+
def export_processes(self, category: Optional[str] = None) -> List[str]:
|
|
327
|
+
"""Export process names from the whitelist
|
|
328
|
+
|
|
329
|
+
Args:
|
|
330
|
+
category: Optional category filter
|
|
331
|
+
|
|
332
|
+
Returns:
|
|
333
|
+
List of process names
|
|
334
|
+
"""
|
|
335
|
+
if category:
|
|
336
|
+
return [entry.process_name for entry in self.entries
|
|
337
|
+
if entry.category == category and entry.enabled]
|
|
338
|
+
else:
|
|
339
|
+
return [entry.process_name for entry in self.entries if entry.enabled]
|
|
340
|
+
|
|
341
|
+
def validate_process_name(self, process_name: str) -> bool:
|
|
342
|
+
"""Validate a process name format
|
|
343
|
+
|
|
344
|
+
Args:
|
|
345
|
+
process_name: Process name to validate
|
|
346
|
+
|
|
347
|
+
Returns:
|
|
348
|
+
True if valid, False otherwise
|
|
349
|
+
"""
|
|
350
|
+
if not process_name or not isinstance(process_name, str):
|
|
351
|
+
return False
|
|
352
|
+
|
|
353
|
+
# Check length
|
|
354
|
+
if len(process_name) > 255:
|
|
355
|
+
return False
|
|
356
|
+
|
|
357
|
+
# Check for valid characters (allowing wildcards for pattern matching)
|
|
358
|
+
valid_chars = re.compile(r'^[a-zA-Z0-9_\-\.\*\?]+\.exe$', re.IGNORECASE)
|
|
359
|
+
return bool(valid_chars.match(process_name))
|
|
360
|
+
|
|
361
|
+
def cleanup_entries(self):
|
|
362
|
+
"""Remove duplicate and invalid entries"""
|
|
363
|
+
seen = set()
|
|
364
|
+
valid_entries = []
|
|
365
|
+
|
|
366
|
+
for entry in self.entries:
|
|
367
|
+
key = (entry.process_name.lower(), entry.exact_match)
|
|
368
|
+
if key not in seen and self.validate_process_name(entry.process_name):
|
|
369
|
+
seen.add(key)
|
|
370
|
+
valid_entries.append(entry)
|
|
371
|
+
|
|
372
|
+
removed_count = len(self.entries) - len(valid_entries)
|
|
373
|
+
self.entries = valid_entries
|
|
374
|
+
|
|
375
|
+
if removed_count > 0:
|
|
376
|
+
logger.info(f"Cleaned up {removed_count} invalid/duplicate whitelist entries")
|
|
377
|
+
|
|
378
|
+
return removed_count
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"""
|
|
2
|
+
GUI Automation Module
|
|
3
|
+
=====================
|
|
4
|
+
|
|
5
|
+
GUI automation module for the MCP Cheat Engine Server.
|
|
6
|
+
|
|
7
|
+
This module provides comprehensive PyAutoGUI integration as part of the
|
|
8
|
+
MCP Cheat Engine Server, offering secure and powerful GUI automation capabilities.
|
|
9
|
+
|
|
10
|
+
Modules:
|
|
11
|
+
--------
|
|
12
|
+
- core.integration: Main PyAutoGUI controller and integration
|
|
13
|
+
- tools.mcp_tools: MCP tool definitions for PyAutoGUI functionality
|
|
14
|
+
- demos: Example usage and demonstration scripts
|
|
15
|
+
- tests: Test suites for validation
|
|
16
|
+
|
|
17
|
+
Usage:
|
|
18
|
+
------
|
|
19
|
+
from server.gui_automation.core.integration import PyAutoGUIController
|
|
20
|
+
from server.gui_automation.tools.mcp_tools import ALL_PYAUTOGUI_TOOLS, PyAutoGUIToolHandler
|
|
21
|
+
|
|
22
|
+
# Initialize controller
|
|
23
|
+
controller = PyAutoGUIController()
|
|
24
|
+
|
|
25
|
+
# Use MCP tools
|
|
26
|
+
from server.gui_automation.tools.mcp_tools import get_pyautogui_controller
|
|
27
|
+
gui = get_pyautogui_controller()
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
# Re-export main components for easy access
|
|
31
|
+
from .core.integration import PyAutoGUIController, get_pyautogui_controller, PYAUTOGUI_AVAILABLE
|
|
32
|
+
from .tools.mcp_tools import ALL_PYAUTOGUI_TOOLS, PyAutoGUIToolHandler
|
|
33
|
+
|
|
34
|
+
__version__ = "1.0.0"
|
|
35
|
+
__author__ = "MCP Cheat Engine Server"
|
|
36
|
+
|
|
37
|
+
__all__ = [
|
|
38
|
+
'PyAutoGUIController',
|
|
39
|
+
'get_pyautogui_controller',
|
|
40
|
+
'PYAUTOGUI_AVAILABLE',
|
|
41
|
+
'ALL_PYAUTOGUI_TOOLS',
|
|
42
|
+
'PyAutoGUIToolHandler'
|
|
43
|
+
]
|