UNPKG

hawiyat-client

Version:

Official CLI tool for managing Hawiyat installations

352 lines (287 loc) 9.38 kB
#!/usr/bin/env node const { Command } = require("commander") const axios = require("axios") const fs = require("fs") const path = require("path") const { execSync, spawn } = require("child_process") const chalk = require("chalk") const os = require("os") const program = new Command() const BASE_URL = "https://hawiyat.vercel.app" const Hawiyat_CHECK = "/etc/Dokploy" // In-memory config (no file persistence) let config = { JWT_TOKEN: null, email: null } // Utility functions const log = { info: (msg) => console.log(chalk.blue("[INFO]"), msg), success: (msg) => console.log(chalk.green("[SUCCESS]"), msg), warning: (msg) => console.log(chalk.yellow("[WARNING]"), msg), error: (msg) => console.log(chalk.red("[ERROR]"), msg), } // Check if running as root for certain operations function requireRoot() { if (process.getuid && process.getuid() !== 0) { log.error("This operation requires root privileges. Please run with sudo.") process.exit(1) } } // Check if Hawiyat is installed function checkHawiyatInstalled() { return fs.existsSync(Hawiyat_CHECK) } // Make authenticated request async function makeAuthRequest(method, endpoint, data = null) { if (!config.JWT_TOKEN) { log.error("Not logged in. Please run: hawiyat login <email> <password>") process.exit(1) } try { const options = { method, url: `${BASE_URL}${endpoint}`, headers: { Cookie: `hawiyat_token=${config.JWT_TOKEN}`, "Content-Type": "application/json", }, timeout: 30000, } if (data) { options.data = data } const response = await axios(options) return response.data } catch (error) { if (error.response?.status === 401) { log.error("Authentication failed. Please login again.") } else { log.error(`Request failed: ${error.message}`) } process.exit(1) } } // Get system information function getSystemInfo() { let serverIp = "unknown" let machineId = "unknown" let osInfo = "unknown" try { serverIp = execSync("curl -s ifconfig.me", { timeout: 10000 }).toString().trim() } catch (error) { log.warning("Could not get server IP") } try { machineId = fs.readFileSync("/etc/machine-id", "utf8").trim() } catch (error) { try { machineId = execSync("hostname").toString().trim() } catch (e) { log.warning("Could not get machine ID") } } try { const osRelease = fs.readFileSync("/etc/os-release", "utf8") const prettyNameMatch = osRelease.match(/PRETTY_NAME="([^"]+)"/) if (prettyNameMatch) { osInfo = prettyNameMatch[1] } } catch (error) { log.warning("Could not get OS information") } return { ip: serverIp, machine_id: machineId, os: osInfo, install_date: new Date().toISOString(), } } // Commands // Init command async function cmdInit() { log.info("Initializing hawiyat client...") if (!checkHawiyatInstalled()) { log.info("Hawiyat is installed. install Hawiyat first.") } const systemInfo = getSystemInfo() log.info("Registering system with hawiyat...") log.info(JSON.stringify(systemInfo, null, 2)) try { const response = await axios.post(`${BASE_URL}/api/webhooks/headless/anyjson`, systemInfo, { headers: { "Content-Type": "application/json" }, timeout: 30000, }) if (response.data.success) { log.success("System initialized successfully") log.info("You can now login using: hawiyat login <email> <password>") } else { log.error(`Failed to initialize system: ${response.data.error || response.data.message}`) process.exit(1) } } catch (error) { if (error.response?.data) { log.error(`Failed to initialize system: ${error.response.data.error || error.response.data.message || error.message}`) } else { log.error(`Failed to initialize system: ${error.message}`) } process.exit(1) } } // Login command async function cmdLogin(email, password) { if (!email || !password) { log.error("Usage: hawiyat login <email> <password>") process.exit(1) } log.info(`Logging in as ${email}...`) try { const response = await axios.post( `${BASE_URL}/api/login`, { email, password, }, { headers: { "Content-Type": "application/json" }, timeout: 30000, }, ) // Extract JWT token from response or cookies let token = null if (response.data.token) { token = response.data.token } else if (response.data.jwt) { token = response.data.jwt } else if (response.data.access_token) { token = response.data.access_token } if (!token && response.headers['set-cookie']) { const cookies = response.headers['set-cookie'] for (const cookie of cookies) { if (cookie.startsWith('hawiyat_token=')) { token = cookie.split('=')[1].split(';')[0] break } } } if (token) { // Store in memory instead of file config.JWT_TOKEN = token config.email = email log.success("Login successful") } else { log.error("Login failed: No token received") process.exit(1) } } catch (error) { if (error.response?.status === 401 || error.response?.status === 400) { log.error("Login failed: Invalid credentials") } else { log.error(`Login failed: ${error.message}`) } process.exit(1) } } // Logout command function cmdLogout() { config.JWT_TOKEN = null config.email = null log.success("Logged out successfully") } // Get installer script async function getInstallerScript() { try { log.info("Downloading installer script...") const response = await axios.get(`${BASE_URL}/api/installer`, { headers: { "Content-Type": "application/json" }, timeout: 30000, }) // Create hawiyat directory if it doesn't exist const hawiyatDir = "/etc/hawiyat" if (!fs.existsSync(hawiyatDir)) { fs.mkdirSync(hawiyatDir, { recursive: true }) } const scriptPath = path.join(hawiyatDir, "installer.sh") // Write script content to file const scriptContent = response.data.script || response.data || response.file console.log(`Script content length: ${response}`) fs.writeFileSync(scriptPath, scriptContent, { mode: 0o755 }) log.success(`Installer script downloaded to ${scriptPath}`) return scriptPath } catch (error) { log.error(`Failed to download installer script: ${error.message}`); process.exit(1) } } // Install command async function cmdInstall() { requireRoot() log.info("Installing Hawiyat...") try { const scriptPath = await getInstallerScript() log.info("Running installer script...") execSync(`sudo sh ${scriptPath}`, { stdio: 'inherit' }) log.success("Hawiyat installation completed") } catch (error) { log.error(`Installation failed: ${error.message}`) process.exit(1) } } // Update command async function cmdUpdate() { requireRoot() log.info("Updating Hawiyat...") try { const scriptPath = await getInstallerScript() log.info("Running update script...") execSync(`sudo sh ${scriptPath} update`, { stdio: 'inherit' }) log.success("Hawiyat update completed") } catch (error) { log.error(`Update failed: ${error.message}`) process.exit(1) } } // Info command - show user data async function cmdInfo() { if (!config.JWT_TOKEN) { log.error("Not logged in. Please run: hawiyat login <email> <password>") process.exit(1) } try { log.info("Fetching user information...") const userData = await makeAuthRequest('GET', '/api/user/organization') console.log(chalk.cyan("\n=== User Information ===")) console.log(`Email: ${userData.email || config.email}`) console.log(`Name: ${userData.name || 'N/A'}`) console.log(`ID: ${userData.id || 'N/A'}`) console.log(`Role: ${userData.role || 'N/A'}`) console.log(`Created: ${userData.createdAt || 'N/A'}`) console.log(chalk.cyan("========================\n")) } catch (error) { // Try alternative endpoint if profile doesn't work try { const userData = await makeAuthRequest('GET', '/api/user') console.log(chalk.cyan("\n=== User Information ===")) console.log(`Email: ${config.email}`) console.log(`Status: Authenticated`) console.log(`Token: Active`) console.log(chalk.cyan("========================\n")) } catch (altError) { log.error("Failed to fetch user information") console.log(`Logged in as: ${config.email}`) } } } // Setup CLI program.name("hawiyat").description("Hawiyat client for managing Hawiyat installations").version("1.0.0") program .command("init [organizationId] [organizationName]") .description("Initialize hawiyat client") .action(cmdInit) program.command("login <email> <password>").description("Login to hawiyat").action(cmdLogin) program.command("logout").description("Logout from hawiyat").action(cmdLogout) program.command("install").description("Install Hawiyat").action(cmdInstall) program.command("update").description("Update Hawiyat").action(cmdUpdate) program.command("info").description("Show user information").action(cmdInfo) program.parse()