hawiyat-client
Version:
Official CLI tool for managing Hawiyat installations
352 lines (287 loc) • 9.38 kB
JavaScript
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()