@moontra/moonui-pro 2.37.0 → 2.37.2

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moontra/moonui-pro",
3
- "version": "2.37.0",
3
+ "version": "2.37.2",
4
4
  "description": "Premium React components for MoonUI - Advanced UI library with 50+ pro components including performance, interactive, and gesture components",
5
5
  "type": "module",
6
6
  "main": "dist/index.mjs",
@@ -1,5 +1,5 @@
1
1
  /**
2
- * MoonUI Pro - Server-side License Validation Route
2
+ * MoonUI Pro - Server-side License Validation Route with Enhanced Security
3
3
  *
4
4
  * This route handles license validation on the server to prevent browser API calls.
5
5
  * Copy this file to: app/api/moonui/validate-pro/route.ts (App Router)
@@ -8,11 +8,23 @@
8
8
  * Required environment variables:
9
9
  * - MOONUI_LICENSE_KEY: Your MoonUI Pro license key
10
10
  * - MOONUI_ENCRYPTION_KEY (optional): Custom encryption key for cookies
11
+ * - MOONUI_SECURITY_HASH (auto-generated): Security checksum for validation
12
+ *
13
+ * SECURITY WARNING: Do not modify the validation logic.
14
+ * Any tampering will be detected and reported.
11
15
  */
12
16
 
13
17
  import { NextRequest, NextResponse } from 'next/server';
14
18
  import { cookies, headers } from 'next/headers';
15
19
  import crypto from 'crypto';
20
+ import os from 'os';
21
+ import { execSync } from 'child_process';
22
+
23
+ // Security checksum - DO NOT MODIFY
24
+ const SECURITY_CHECKSUM = process.env.MOONUI_SECURITY_HASH ||
25
+ crypto.createHash('sha256')
26
+ .update(`moonui-pro-${process.env.MOONUI_LICENSE_KEY || 'default'}-validation`)
27
+ .digest('hex');
16
28
 
17
29
  // Cache configuration
18
30
  const CACHE_DURATION = process.env.NODE_ENV === 'production'
@@ -30,21 +42,107 @@ const validationCache = new Map<string, {
30
42
  expiresAt: number;
31
43
  }>();
32
44
 
45
+ /**
46
+ * Get MAC address for hardware fingerprinting
47
+ */
48
+ function getMacAddress(): string {
49
+ try {
50
+ const platform = os.platform();
51
+ let command: string;
52
+
53
+ switch (platform) {
54
+ case 'darwin':
55
+ command = "ifconfig | grep ether | head -1 | awk '{print $2}'";
56
+ break;
57
+ case 'linux':
58
+ command = "ip link show | grep ether | head -1 | awk '{print $2}'";
59
+ break;
60
+ case 'win32':
61
+ command = 'getmac /NH /FO csv | findstr /r "^"';
62
+ break;
63
+ default:
64
+ return 'unknown-mac';
65
+ }
66
+
67
+ const result = execSync(command, { encoding: 'utf8' }).trim();
68
+ const match = result.match(/([a-f0-9:]+)/i);
69
+
70
+ if (match && match[1]) {
71
+ return match[1].replace(/[:-]/g, '').toLowerCase();
72
+ }
73
+
74
+ // Fallback to network interfaces
75
+ const interfaces = os.networkInterfaces();
76
+ for (const name in interfaces) {
77
+ const iface = interfaces[name];
78
+ if (iface) {
79
+ for (const entry of iface) {
80
+ if (entry.mac && entry.mac !== '00:00:00:00:00:00') {
81
+ return entry.mac.replace(/[:-]/g, '').toLowerCase();
82
+ }
83
+ }
84
+ }
85
+ }
86
+ return 'fallback-mac';
87
+ } catch (error) {
88
+ console.error('[Hardware] Error getting MAC:', error);
89
+ return 'error-mac';
90
+ }
91
+ }
92
+
93
+ /**
94
+ * Generate hardware-based device fingerprint
95
+ * Format: hw-{platform}-{macHash}-{cpuHash}
96
+ */
97
+ function generateHardwareFingerprint(): string {
98
+ const platform = os.platform();
99
+ const macAddress = getMacAddress();
100
+ const cpuCount = os.cpus().length;
101
+ const totalMem = Math.round(os.totalmem() / (1024 * 1024 * 1024)); // GB
102
+ const hostname = os.hostname();
103
+
104
+ // Create hashes
105
+ const macHash = crypto.createHash('sha256')
106
+ .update(macAddress)
107
+ .digest('hex')
108
+ .substring(0, 8);
109
+
110
+ const systemHash = crypto.createHash('sha256')
111
+ .update(`${cpuCount}:${totalMem}:${hostname}`)
112
+ .digest('hex')
113
+ .substring(0, 6);
114
+
115
+ return `hw-${platform}-${macHash}-${systemHash}`;
116
+ }
117
+
33
118
  /**
34
119
  * Generate a device fingerprint from request headers
120
+ * Combines hardware fingerprint with browser characteristics
35
121
  */
36
122
  async function getDeviceFingerprint(request: NextRequest): Promise<string> {
37
- const headersList = await headers();
38
- const ua = headersList.get('user-agent') || 'unknown';
39
- const lang = headersList.get('accept-language') || 'unknown';
40
- const ip = headersList.get('x-forwarded-for') ||
41
- headersList.get('x-real-ip') ||
42
- 'unknown';
123
+ // In development with CLI auth, generate hardware-based fingerprint
124
+ if (process.env.NODE_ENV === 'development') {
125
+ // Use hardware fingerprint for maximum security
126
+ const hardwareId = generateHardwareFingerprint();
127
+
128
+ // If CLI device ID is set, validate it matches hardware
129
+ if (process.env.NEXT_PUBLIC_MOONUI_DEVICE_ID) {
130
+ const cliDeviceId = process.env.NEXT_PUBLIC_MOONUI_DEVICE_ID;
131
+
132
+ // For backward compatibility, accept both old and new format
133
+ if (cliDeviceId.startsWith('hw-')) {
134
+ return cliDeviceId; // New hardware-based format
135
+ } else {
136
+ console.log('[MoonUI] Migrating to hardware-based device ID');
137
+ return hardwareId; // Use new hardware ID
138
+ }
139
+ }
43
140
 
44
- return crypto
45
- .createHash('sha256')
46
- .update(`${ua}|${lang}|${ip}`)
47
- .digest('hex');
141
+ return hardwareId;
142
+ }
143
+
144
+ // In production, use hardware fingerprint
145
+ return generateHardwareFingerprint();
48
146
  }
49
147
 
50
148
  /**
@@ -83,20 +181,56 @@ async function validateWithMoonUIServer(
83
181
  const devToken = process.env.NEXT_PUBLIC_MOONUI_DEV_TOKEN;
84
182
  const devDeviceId = process.env.NEXT_PUBLIC_MOONUI_DEVICE_ID;
85
183
 
86
- if (devToken && devDeviceId === deviceId) {
184
+ console.log('[MoonUI Dev Auth] Checking CLI authentication:');
185
+ console.log('[MoonUI Dev Auth] Device IDs match:', devDeviceId === deviceId);
186
+
187
+ // STRICT DEVICE ID VALIDATION - Prevent token sharing
188
+ if (devToken && devDeviceId && devDeviceId === deviceId) {
87
189
  try {
88
190
  // Decode the dev token
89
191
  const decoded = JSON.parse(Buffer.from(devToken, 'base64').toString());
192
+
193
+ // Verify token structure and session
194
+ if (!decoded.deviceId || !decoded.session || !decoded.security) {
195
+ console.error('[MoonUI Security] Invalid token structure');
196
+ return { valid: false, hasProAccess: false };
197
+ }
198
+
199
+ // Verify device ID in token matches
200
+ if (decoded.deviceId !== devDeviceId) {
201
+ console.error('[MoonUI Security] Token device ID mismatch');
202
+ return { valid: false, hasProAccess: false };
203
+ }
204
+
205
+ // Verify session hasn't expired
206
+ if (decoded.session?.expiresAt && decoded.session.expiresAt < Date.now()) {
207
+ console.error('[MoonUI Security] Token session expired');
208
+ return { valid: false, hasProAccess: false };
209
+ }
210
+
211
+ console.log('[MoonUI Dev Auth] Token validated successfully');
212
+ console.log('[MoonUI Dev Auth] User plan:', decoded.user?.plan);
213
+
90
214
  if (decoded.user?.plan === 'pro_lifetime' || decoded.user?.hasProAccess) {
215
+ console.log('[MoonUI Dev Auth] Pro access granted via CLI token');
91
216
  return {
92
217
  valid: true,
93
218
  hasProAccess: true,
94
- plan: 'lifetime'
219
+ plan: decoded.user?.plan || 'lifetime'
95
220
  };
96
221
  }
97
222
  } catch (e) {
98
- console.error('[MoonUI] Error parsing dev token:', e);
223
+ console.error('[MoonUI Security] Error parsing dev token:', e);
224
+ return { valid: false, hasProAccess: false };
99
225
  }
226
+ } else if (devToken && !devDeviceId) {
227
+ console.warn('[MoonUI Security] Token found but no device ID - possible token sharing attempt');
228
+ return { valid: false, hasProAccess: false };
229
+ } else if (devDeviceId !== deviceId) {
230
+ console.warn('[MoonUI Security] Device ID mismatch - token not valid for this device');
231
+ console.warn('[MoonUI Security] This token is locked to device:', devDeviceId);
232
+ console.warn('[MoonUI Security] Current device:', deviceId);
233
+ return { valid: false, hasProAccess: false };
100
234
  }
101
235
  }
102
236
 
@@ -150,10 +284,86 @@ async function validateWithMoonUIServer(
150
284
  }
151
285
 
152
286
  /**
153
- * Main API route handler
287
+ * Verify request integrity
288
+ */
289
+ function verifyRequestIntegrity(request: NextRequest): boolean {
290
+ // Check for suspicious patterns
291
+ const url = new URL(request.url);
292
+
293
+ // Reject if trying to bypass with query params
294
+ if (url.searchParams.has('bypass') ||
295
+ url.searchParams.has('force') ||
296
+ url.searchParams.has('admin')) {
297
+ console.warn('[MoonUI Security] Suspicious query params detected');
298
+ return false;
299
+ }
300
+
301
+ // Check request headers for tampering
302
+ const suspiciousHeaders = [
303
+ 'x-moonui-bypass',
304
+ 'x-force-pro',
305
+ 'x-admin-override',
306
+ 'x-moonui-device-override',
307
+ 'x-moonui-token-override'
308
+ ];
309
+
310
+ for (const header of suspiciousHeaders) {
311
+ if (request.headers.has(header)) {
312
+ console.warn(`[MoonUI Security] Suspicious header detected: ${header}`);
313
+ return false;
314
+ }
315
+ }
316
+
317
+ // Check for proxy/VPN indicators
318
+ const proxyHeaders = [
319
+ 'x-proxy-connection',
320
+ 'x-forwarded-server',
321
+ 'x-originating-ip',
322
+ 'x-remote-ip'
323
+ ];
324
+
325
+ const hasProxy = proxyHeaders.some(header => request.headers.has(header));
326
+ if (hasProxy) {
327
+ console.warn('[MoonUI Security] Proxy/VPN detected - additional validation required');
328
+ }
329
+
330
+ return true;
331
+ }
332
+
333
+ /**
334
+ * Generate validation signature for response
335
+ */
336
+ function generateValidationSignature(data: any): string {
337
+ const payload = JSON.stringify({
338
+ ...data,
339
+ timestamp: Date.now(),
340
+ checksum: SECURITY_CHECKSUM,
341
+ });
342
+
343
+ return crypto
344
+ .createHash('sha256')
345
+ .update(payload)
346
+ .digest('hex')
347
+ .substring(0, 16);
348
+ }
349
+
350
+ /**
351
+ * Main API route handler with enhanced security
154
352
  */
155
353
  export async function GET(request: NextRequest) {
156
354
  try {
355
+ // Security check
356
+ if (!verifyRequestIntegrity(request)) {
357
+ return NextResponse.json(
358
+ {
359
+ error: 'Invalid request',
360
+ valid: false,
361
+ hasProAccess: false
362
+ },
363
+ { status: 403 }
364
+ );
365
+ }
366
+
157
367
  // Generate device fingerprint
158
368
  const deviceId = await getDeviceFingerprint(request);
159
369
 
@@ -208,7 +418,8 @@ export async function GET(request: NextRequest) {
208
418
  maxAge: CACHE_DURATION / 1000, // Convert to seconds
209
419
  });
210
420
 
211
- return NextResponse.json({
421
+ // Prepare response data
422
+ const responseData = {
212
423
  valid: validation.valid,
213
424
  hasProAccess: validation.hasProAccess,
214
425
  isAuthenticated: validation.valid,
@@ -217,7 +428,19 @@ export async function GET(request: NextRequest) {
217
428
  status: validation.hasProAccess ? 'active' : 'inactive',
218
429
  plan: validation.hasProAccess ? 'lifetime' : 'free',
219
430
  },
220
- });
431
+ _signature: generateValidationSignature({
432
+ valid: validation.valid,
433
+ hasProAccess: validation.hasProAccess,
434
+ deviceId: deviceId,
435
+ }),
436
+ };
437
+
438
+ // Log security events
439
+ if (validation.hasProAccess) {
440
+ console.log(`[MoonUI Security] Pro access granted for device: ${deviceId.substring(0, 8)}...`);
441
+ }
442
+
443
+ return NextResponse.json(responseData);
221
444
 
222
445
  } catch (error) {
223
446
  console.error('[MoonUI] Validation error:', error);