@createlex/createlexgenai 1.0.0

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.
@@ -0,0 +1,7 @@
1
+ Flask>=2.2.0
2
+ fastmcp>=1.0.0
3
+ requests>=2.28.0
4
+ uvicorn>=0.18.0
5
+ python-dotenv>=0.19.0
6
+ websockets>=10.0
7
+ Pillow>=10.0.0
@@ -0,0 +1,199 @@
1
+ import hashlib
2
+ import hmac
3
+ import time
4
+ import json
5
+ import requests
6
+ from datetime import datetime, timedelta
7
+ import os
8
+
9
+ class SubscriptionValidator:
10
+ def __init__(self, api_endpoint="https://your-api.com/validate", secret_key=None):
11
+ self.api_endpoint = api_endpoint
12
+ self.secret_key = secret_key or os.environ.get("SUBSCRIPTION_SECRET", "default-secret")
13
+ self.cache_file = os.path.expanduser("~/.unrealgenai/subscription_cache.json")
14
+ self.cache_duration = 24 * 60 * 60 # 24 hours in seconds
15
+
16
+ def generate_machine_id(self):
17
+ """Generate unique machine identifier"""
18
+ import platform
19
+ import uuid
20
+
21
+ # Combine multiple machine identifiers
22
+ machine_info = f"{platform.node()}-{platform.machine()}-{platform.processor()}"
23
+ try:
24
+ mac_address = ':'.join(['{:02x}'.format((uuid.getnode() >> elements) & 0xff)
25
+ for elements in range(0,2*6,2)][::-1])
26
+ machine_info += f"-{mac_address}"
27
+ except:
28
+ pass
29
+
30
+ return hashlib.sha256(machine_info.encode()).hexdigest()[:16]
31
+
32
+ def create_signature(self, data):
33
+ """Create HMAC signature for data"""
34
+ message = json.dumps(data, sort_keys=True)
35
+ return hmac.new(
36
+ self.secret_key.encode(),
37
+ message.encode(),
38
+ hashlib.sha256
39
+ ).hexdigest()
40
+
41
+ def load_cached_validation(self):
42
+ """Load cached validation result"""
43
+ try:
44
+ if os.path.exists(self.cache_file):
45
+ with open(self.cache_file, 'r') as f:
46
+ cache_data = json.load(f)
47
+
48
+ # Check if cache is still valid
49
+ cached_time = cache_data.get('timestamp', 0)
50
+ if time.time() - cached_time < self.cache_duration:
51
+ return cache_data.get('valid', False)
52
+ except:
53
+ pass
54
+ return None
55
+
56
+ def save_cached_validation(self, is_valid):
57
+ """Save validation result to cache"""
58
+ try:
59
+ os.makedirs(os.path.dirname(self.cache_file), exist_ok=True)
60
+ cache_data = {
61
+ 'valid': is_valid,
62
+ 'timestamp': time.time()
63
+ }
64
+ with open(self.cache_file, 'w') as f:
65
+ json.dump(cache_data, f)
66
+ except:
67
+ pass
68
+
69
+ def validate_subscription(self, license_key=None, user_email=None):
70
+ """Validate subscription with server"""
71
+ # First check cache
72
+ cached_result = self.load_cached_validation()
73
+ if cached_result is not None:
74
+ return cached_result
75
+
76
+ try:
77
+ machine_id = self.generate_machine_id()
78
+
79
+ # Prepare validation data
80
+ validation_data = {
81
+ 'license_key': license_key or os.environ.get("LICENSE_KEY"),
82
+ 'user_email': user_email or os.environ.get("USER_EMAIL"),
83
+ 'machine_id': machine_id,
84
+ 'timestamp': int(time.time()),
85
+ 'product': 'unrealgenai-mcp'
86
+ }
87
+
88
+ # Create signature
89
+ signature = self.create_signature(validation_data)
90
+ validation_data['signature'] = signature
91
+
92
+ # Make API request
93
+ response = requests.post(
94
+ self.api_endpoint,
95
+ json=validation_data,
96
+ timeout=10,
97
+ headers={'Content-Type': 'application/json'}
98
+ )
99
+
100
+ if response.status_code == 200:
101
+ result = response.json()
102
+ is_valid = result.get('valid', False)
103
+
104
+ # Cache the result
105
+ self.save_cached_validation(is_valid)
106
+ return is_valid
107
+ else:
108
+ # Server error - check if we have a recent cache
109
+ return self.handle_validation_error()
110
+
111
+ except requests.RequestException:
112
+ # Network error - check if we have a recent cache
113
+ return self.handle_validation_error()
114
+ except Exception as e:
115
+ print(f"Validation error: {e}")
116
+ return False
117
+
118
+ def handle_validation_error(self):
119
+ """Handle validation errors with grace period"""
120
+ try:
121
+ if os.path.exists(self.cache_file):
122
+ with open(self.cache_file, 'r') as f:
123
+ cache_data = json.load(f)
124
+
125
+ # Allow 7 days grace period for network issues
126
+ cached_time = cache_data.get('timestamp', 0)
127
+ grace_period = 7 * 24 * 60 * 60 # 7 days
128
+
129
+ if time.time() - cached_time < grace_period:
130
+ return cache_data.get('valid', False)
131
+ except:
132
+ pass
133
+ return False
134
+
135
+ def get_subscription_info(self):
136
+ """Get detailed subscription information"""
137
+ try:
138
+ if os.path.exists(self.cache_file):
139
+ with open(self.cache_file, 'r') as f:
140
+ cache_data = json.load(f)
141
+
142
+ cached_time = cache_data.get('timestamp', 0)
143
+ is_valid = cache_data.get('valid', False)
144
+
145
+ return {
146
+ 'valid': is_valid,
147
+ 'last_checked': datetime.fromtimestamp(cached_time).isoformat(),
148
+ 'expires_in_hours': max(0, (self.cache_duration - (time.time() - cached_time)) / 3600)
149
+ }
150
+ except:
151
+ pass
152
+
153
+ return {
154
+ 'valid': False,
155
+ 'last_checked': 'Never',
156
+ 'expires_in_hours': 0
157
+ }
158
+
159
+ # Usage example:
160
+ def check_subscription():
161
+ """Main subscription check function"""
162
+ # Development / testing bypasses
163
+ dev_mode = os.environ.get('DEV_MODE')
164
+ node_env = os.environ.get('NODE_ENV')
165
+ if dev_mode == 'true' or node_env == 'development':
166
+ print("Development mode detected - bypassing subscription validation")
167
+ return True
168
+
169
+ # Explicit bypass via environment variable
170
+ if os.environ.get('BYPASS_SUBSCRIPTION') == 'true':
171
+ print("BYPASS_SUBSCRIPTION=true - bypassing subscription validation")
172
+ return True
173
+
174
+ # Bridge (Electron app) may validate the subscription already and set this flag
175
+ if os.environ.get('BRIDGE_SUBSCRIPTION_VALIDATED') == 'true':
176
+ print("Bridge has already validated subscription - bypassing local validation")
177
+ return True
178
+
179
+ validator = SubscriptionValidator()
180
+
181
+ # Try to validate
182
+ is_valid = validator.validate_subscription()
183
+
184
+ if not is_valid:
185
+ print("❌ Invalid or expired subscription!")
186
+ print("Please contact support or renew your license.")
187
+ return False
188
+
189
+ print("✅ Subscription validated successfully!")
190
+ return True
191
+
192
+ # Integration with MCP server
193
+ def require_subscription(func):
194
+ """Decorator to require valid subscription for MCP tools"""
195
+ def wrapper(*args, **kwargs):
196
+ if not check_subscription():
197
+ return "❌ This tool requires a valid subscription. Please contact support."
198
+ return func(*args, **kwargs)
199
+ return wrapper