UNPKG

@moontra/moonui-pro

Version:

Premium React components for MoonUI - Advanced UI library with 50+ pro components including performance, interactive, and gesture components

336 lines (279 loc) 11.5 kB
#!/usr/bin/env node import https from 'https'; import fs from 'fs'; import path from 'path'; import os from 'os'; import crypto from 'crypto'; import { fileURLToPath } from 'url'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); // ANSI color codes for console output const colors = { reset: '\x1b[0m', bright: '\x1b[1m', red: '\x1b[31m', green: '\x1b[32m', yellow: '\x1b[33m', blue: '\x1b[34m', cyan: '\x1b[36m', gray: '\x1b[90m' }; const log = (message, color = '') => { console.log(`${color}${message}${colors.reset}`); }; const getDeviceFingerprint = () => { // Create a unique device fingerprint using multiple system attributes const hostname = os.hostname(); const username = os.userInfo().username; const platform = os.platform(); const arch = os.arch(); const cpus = os.cpus(); const cpuModel = cpus[0]?.model || 'unknown'; const cpuCount = cpus.length; const homeDir = os.homedir(); // Combine all attributes for a unique device ID const deviceString = `${hostname}|${username}|${platform}|${arch}|${cpuModel}|${cpuCount}|${homeDir}`; return crypto.createHash('sha256').update(deviceString).digest('hex'); }; const getAuthConfig = () => { try { const authPath = path.join(os.homedir(), '.moonui', 'auth.encrypted'); if (!fs.existsSync(authPath)) { return null; } // Read encrypted auth const encryptedData = fs.readFileSync(authPath, 'utf-8'); const parts = encryptedData.split('.'); if (parts.length !== 3) { // Encrypted format: iv.encrypted.signature return null; } const [ivHex, encrypted, signature] = parts; const iv = Buffer.from(ivHex, 'hex'); // Get device-specific key using same fingerprint method const deviceFingerprint = getDeviceFingerprint(); const key = crypto.createHash('sha256').update(deviceFingerprint).digest(); // Verify signature const hmac = crypto.createHmac('sha256', key); hmac.update(encrypted); const computedSignature = hmac.digest('hex'); if (computedSignature !== signature) { return null; } // Decrypt const decipher = crypto.createDecipheriv('aes-256-cbc', key, iv); let decrypted = decipher.update(encrypted, 'hex', 'utf8'); decrypted += decipher.final('utf8'); const cache = JSON.parse(decrypted); // Verify device matches if (cache.deviceId && cache.deviceId !== deviceFingerprint) { log('❌ Device mismatch detected!', colors.red + colors.bright); log(' This license is registered to a different device', colors.red); log(' MoonUI Pro licenses are single-device only', colors.yellow); return null; } // Extract token from cache const auth = cache.token || cache; // Check if expired if (new Date(auth.expiresAt) < new Date()) { return null; } return auth; } catch (error) { // Silent fail - will show auth required message return null; } }; const validateAuth = async (token) => { return new Promise((resolve) => { const API_BASE = process.env.MOONUI_API_BASE || 'moonui.dev'; const options = { hostname: API_BASE.replace('https://', '').replace('http://', ''), port: 443, path: '/api/auth/validate', method: 'GET', headers: { 'Authorization': `Bearer ${token}`, 'User-Agent': 'moonui-pro-postinstall/2.0.0' }, timeout: 10000 }; const req = https.request(options, (res) => { let data = ''; res.on('data', (chunk) => { data += chunk; }); res.on('end', () => { try { if (res.statusCode === 200) { const result = JSON.parse(data); resolve({ valid: true, ...result }); } else { resolve({ valid: false, error: 'INVALID_TOKEN', message: 'Authentication token is invalid' }); } } catch (error) { resolve({ valid: false, error: 'PARSE_ERROR', message: 'Invalid response from server' }); } }); }); req.on('error', (error) => { resolve({ valid: false, error: 'NETWORK_ERROR', message: 'Could not connect to auth server' }); }); req.on('timeout', () => { resolve({ valid: false, error: 'TIMEOUT', message: 'Auth validation timeout' }); }); req.end(); }); }; const checkEnvironmentAuth = () => { // Check for auth token in environment variables const envToken = process.env.MOONUI_AUTH_TOKEN || process.env.MOONUI_ACCESS_TOKEN; if (envToken) { log('🔑 Found auth token in environment variables', colors.blue); return envToken; } return null; }; const main = async () => { log('', ''); // Empty line log('🌙 MoonUI Pro Installation', colors.cyan + colors.bright); log('═'.repeat(50), colors.gray); // Check for development bypass if (process.env.MOONUI_DEV_MODE === 'true' || process.env.MOONUI_SKIP_AUTH === 'true') { log('🔧 Development Mode Enabled', colors.yellow + colors.bright); log(' Authentication bypassed for local development', colors.yellow); log(' This mode should only be used during development', colors.gray); log('', ''); log('✅ MoonUI Pro ready for development!', colors.green); log('═'.repeat(50), colors.gray); return; } // Check if running on localhost (development) const isLocalDev = process.env.NODE_ENV === 'development' || process.cwd().includes('moonui') || fs.existsSync(path.join(process.cwd(), '.moonui-dev')); if (isLocalDev && !process.env.MOONUI_FORCE_AUTH) { log('🚀 Local Development Detected', colors.blue + colors.bright); log(' Running in development mode without auth', colors.blue); log(' To enable auth checks: MOONUI_FORCE_AUTH=true npm install', colors.gray); log('', ''); log('✅ MoonUI Pro ready for development!', colors.green); log('═'.repeat(50), colors.gray); return; } // Check if this is a CI environment const isCI = process.env.CI || process.env.CONTINUOUS_INTEGRATION || process.env.GITHUB_ACTIONS; if (isCI) { log('🤖 CI Environment detected', colors.blue); const envToken = checkEnvironmentAuth(); if (!envToken) { log('⚠️ No auth token found in CI environment', colors.yellow); log(' Set MOONUI_AUTH_TOKEN environment variable for CI builds', colors.gray); log(' Get your token by running: moonui whoami --token', colors.gray); return; } // Validate CI auth log('🔍 Validating CI authentication...', colors.blue); const validation = await validateAuth(envToken); if (validation.valid) { log('✅ CI Authentication successful!', colors.green); log(` Plan: ${validation.user?.plan || 'N/A'}`, colors.blue); return; } else { log('❌ CI Authentication failed!', colors.red); log(` Error: ${validation.message}`, colors.red); process.exit(1); } } // Regular installation - check for existing auth const authConfig = getAuthConfig(); if (!authConfig || !authConfig.accessToken) { log('🔐 MoonUI Pro Authentication Required', colors.yellow + colors.bright); log('', ''); log('This package requires authentication with a MoonUI Pro account.', colors.yellow); log('', ''); log('📋 Next Steps:', colors.blue + colors.bright); log(' 1. Install MoonUI CLI: npm install -g @moontra/moonui-cli', colors.blue); log(' 2. Login to your account: moonui login', colors.blue); log(' 3. Or set environment variable: MOONUI_AUTH_TOKEN=<your-token>', colors.blue); log('', ''); log('📖 Documentation: https://moonui.dev/docs/authentication', colors.gray); log('🔧 Get your account: https://moonui.dev/pricing', colors.gray); log('', ''); process.exit(1); } // Check if Pro access const hasPro = authConfig.user?.plan === 'pro_monthly' || authConfig.user?.plan === 'pro_annual' || authConfig.user?.plan === 'pro_lifetime' || authConfig.user?.features?.includes('pro_components'); if (!hasPro) { log('❌ MoonUI Pro Access Required', colors.red + colors.bright); log('', ''); log('Your account does not have access to Pro components.', colors.red); log(`Current plan: ${authConfig.user?.plan || 'free'}`, colors.yellow); log('', ''); log('📋 Upgrade your account:', colors.blue + colors.bright); log(' Visit: https://moonui.dev/pricing', colors.blue); log('', ''); process.exit(1); } // Validate existing auth log('🔍 Validating authentication...', colors.blue); const validation = await validateAuth(authConfig.accessToken); if (validation.valid) { log('✅ Authentication successful!', colors.green + colors.bright); log(` Plan: ${validation.user?.plan || authConfig.user?.plan}`, colors.blue); log(` Account: ${authConfig.user?.email || 'N/A'}`, colors.blue); if (validation.expiresAt) { const expiryDate = new Date(validation.expiresAt); const daysLeft = Math.ceil((expiryDate - new Date()) / (1000 * 60 * 60 * 24)); if (daysLeft > 0) { log(` Expires: ${expiryDate.toLocaleDateString()} (${daysLeft} days)`, colors.blue); } else { log(` Status: EXPIRED on ${expiryDate.toLocaleDateString()}`, colors.red); } } else { log(' Expires: Never (Lifetime)', colors.green); } if (validation.downloadLimit) { const { current, max, period } = validation.downloadLimit; const percentage = Math.round((current / max) * 100); const warningColor = percentage > 80 ? colors.yellow : colors.blue; log(` Usage: ${current}/${max} downloads this ${period} (${percentage}%)`, warningColor); } log('', ''); log('🚀 Ready to use MoonUI Pro components!', colors.green); log(' Documentation: https://moonui.dev/docs/components', colors.gray); } else { log('❌ Authentication failed!', colors.red + colors.bright); log(` Error: ${validation.message}`, colors.red); log('', ''); if (validation.error === 'INVALID_TOKEN') { log('🔧 Troubleshooting:', colors.yellow + colors.bright); log(' • Your session may have expired', colors.yellow); log(' • Run: moonui login', colors.yellow); log(' • Contact support: support@moonui.dev', colors.yellow); } else if (validation.error === 'NETWORK_ERROR') { log('🌐 Network Issue:', colors.yellow + colors.bright); log(' • Auth validation requires internet connection', colors.yellow); log(' • Components will work offline after initial validation', colors.yellow); log(' • Retry: npm install --force', colors.yellow); } log('', ''); log('📖 Auth Guide: https://moonui.dev/docs/authentication', colors.gray); // Don't fail installation for network issues, only for invalid auth if (validation.error === 'INVALID_TOKEN') { process.exit(1); } } log('═'.repeat(50), colors.gray); log('', ''); }; // Run postinstall script main().catch((error) => { log('❌ Postinstall script failed:', colors.red); log(` ${error.message}`, colors.red); log('', ''); log('📖 If this persists, see: https://moonui.dev/docs/troubleshooting', colors.gray); });