UNPKG

capsule-ai-cli

Version:

The AI Model Orchestrator - Intelligent multi-model workflows with device-locked licensing

197 lines 7.44 kB
import { configManager } from '../core/config.js'; import chalk from 'chalk'; import crypto from 'crypto'; import os from 'os'; export class AuthService { baseUrl; devMode = false; deviceId; constructor(baseUrl = 'https://www.capsulecli.dev') { this.baseUrl = baseUrl; const config = configManager.getConfig(); this.deviceId = config.auth?.deviceId || this.generateDeviceId(); } setDevMode(enabled) { this.devMode = enabled; } generateDeviceId() { const fingerprint = [ os.hostname(), os.platform(), os.arch(), os.homedir(), os.cpus()[0]?.model || 'unknown-cpu' ].join('-'); return crypto.createHash('sha256').update(fingerprint).digest('hex'); } getDeviceId() { return this.deviceId; } async activate(activationCode) { try { const response = await fetch(`${this.baseUrl}/api/activate`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ code: activationCode, deviceId: this.deviceId }), }); if (!response.ok) { const error = await response.json(); if (response.status === 400) { throw new Error(error.message || 'Invalid activation code'); } if (response.status === 409) { throw new Error('This activation code has already been used on another device'); } throw new Error('Activation failed'); } const data = await response.json(); const authData = { ...data, tier: 'base' }; configManager.setConfig('auth', { token: authData.token, email: authData.email, tier: authData.tier, deviceId: this.deviceId, remainingRUs: authData.remainingRUs, validUntil: authData.validUntil, }); return authData; } catch (error) { if (error.message.includes('fetch')) { throw new Error('Unable to connect to Capsule servers. Please check your internet connection.'); } throw error; } } async authenticate(_email) { throw new Error('Email authentication is deprecated. Please use "capsule activate <code>" instead.'); } async getStatus() { if (this.devMode) { return { isAuthenticated: true, tier: 'super', email: 'dev@capsule.local', deviceId: this.deviceId, remainingRUs: 999999, validUntil: new Date(Date.now() + 365 * 24 * 60 * 60 * 1000).toISOString() }; } const config = configManager.getConfig(); if (!config.auth?.token) { return { isAuthenticated: false }; } try { const response = await fetch(`${this.baseUrl}/api/auth/verify`, { method: 'POST', headers: { 'Authorization': `Bearer ${config.auth.token}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ deviceId: this.deviceId }), }); if (!response.ok) { configManager.setConfig('auth', undefined); if (response.status === 403) { const error = await response.json(); return { isAuthenticated: false, email: error.email, message: 'License is activated on a different device. Please contact support@capsulecli.dev to reset your activation.' }; } else if (response.status === 401) { return { isAuthenticated: false, message: 'License verification failed. Please run `capsule activate <code>` to reactivate.' }; } return { isAuthenticated: false, message: 'Unable to verify license. Please check your activation status.' }; } const data = await response.json(); configManager.setConfig('auth', { token: config.auth.token, email: data.email, tier: data.tier, deviceId: data.deviceId, remainingRUs: data.remainingRUs, validUntil: data.validUntil, }); return { isAuthenticated: true, tier: data.tier, email: data.email, deviceId: data.deviceId, remainingRUs: data.remainingRUs, validUntil: data.validUntil, }; } catch (error) { return { isAuthenticated: false, message: 'Unable to verify license. Please check your activation status.' }; } } async deductRUs(usage) { const config = configManager.getConfig(); if (!config.auth?.token || config.auth.tier !== 'super') { return; } try { await fetch(`${this.baseUrl}/api/usage/deduct`, { method: 'POST', headers: { 'Authorization': `Bearer ${config.auth.token}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ tokens: usage.totalTokens }), }); } catch { } } async logout() { configManager.setConfig('auth', undefined); } formatStatus(status) { if (!status.isAuthenticated) { if (status.message) { return chalk.yellow(status.message); } if (status.email) { return chalk.yellow(`License for ${status.email} is activated on a different device.\nPlease contact support@capsulecli.dev to reset your activation.`); } return chalk.yellow('Not activated. Run `capsule activate <code>` with your activation code.'); } const tierColor = status.tier === 'super' ? chalk.cyan : chalk.green; let output = `${tierColor(`${status.tier?.toUpperCase()} Tier`)} - ${status.email}`; if (status.tier === 'super' && status.remainingRUs !== undefined) { output += `\n${chalk.gray('Remaining RUs:')} ${status.remainingRUs.toLocaleString()}`; } if (status.validUntil) { const validUntil = new Date(status.validUntil); const daysLeft = Math.ceil((validUntil.getTime() - Date.now()) / (1000 * 60 * 60 * 24)); output += `\n${chalk.gray('Valid for:')} ${daysLeft} days`; } if (status.deviceId) { output += `\n${chalk.gray('Device ID:')} ${status.deviceId.substring(0, 8)}...`; } return output; } } export const authService = new AuthService(); //# sourceMappingURL=auth.js.map