const express = require('express'); const { exec, execSync } = require('child_process'); const crypto = require('crypto'); const fs = require('fs'); const path = require('path'); const http = require('http'); require('dotenv').config({ path: '/etc/invoke/.env' }); const app = express(); app.use(express.json({ limit: '10mb' })); const API_KEY = process.env.INVOKE_API_KEY; const PORT = process.env.INVOKE_PORT || 3001; const ECHO_HOST = '127.0.0.1'; const ECHO_PORT = 8089; const ENGINE_PORT = 127; const IX_WEB_PORT = 3080; const SECURITY_LOG = '/var/log/invoke/security.log'; const VERSION = '3.0.0'; const TMP = '/tmp'; try { fs.mkdirSync(TMP, { recursive: true }); } catch(e) {} try { fs.mkdirSync('/var/log/invoke', { recursive: true }); } catch(e) {} // ═══════════════════════════════════════════════ // RATE LIMITER (30 req/min) // ═══════════════════════════════════════════════ const rateMap = new Map(); function rateLimit(id) { const now = Date.now(); const e = rateMap.get(id) || { count: 0, start: now }; if (now - e.start > 60000) { e.count = 1; e.start = now; } else { e.count++; } rateMap.set(id, e); return e.count <= 30; } setInterval(() => { for (const [k,v] of rateMap) { if (Date.now()-v.start > 120000) rateMap.delete(k); } }, 300000); // ═══════════════════════════════════════════════ // SECURITY LOG // ═══════════════════════════════════════════════ function secLog(level, msg, meta = {}) { try { fs.appendFileSync(SECURITY_LOG, JSON.stringify({ t: new Date().toISOString(), level, msg, ...meta }) + '\n'); } catch(e) {} if (level === 'ALERT') console.error('[SECURITY] ' + msg); } // ═══════════════════════════════════════════════ // COMMAND BLACKLIST // ═══════════════════════════════════════════════ const BLOCKED = [ /rm\s+-rf\s+\//,/mkfs/,/dd\s+if=/,/>\s*\/dev\/sd/, /curl\s+.*\|\s*sh/,/wget\s+.*\|\s*sh/,/nc\s+-l/,/ncat\s+-l/, /python.*-c.*socket/,/bash\s+-i\s+>&/,/\/dev\/tcp\//, /base64.*-d.*\|\s*(sh|bash)/,/useradd|adduser/,/passwd\s/, /chmod\s+.*\/etc\/shadow/,/iptables\s+-F/, /ufw\s+(disable|delete|reset)/, /systemctl\s+(stop|disable)\s+(ssh|cloudflared|invoke|ufw|fail2ban)/, /cat\s+\/etc\/(shadow|gshadow)/ ]; function isSafe(cmd) { for (const p of BLOCKED) { if (p.test(cmd)) return false; } return true; } // ═══════════════════════════════════════════════ // AUTH (timing-safe + rate limit) // ═══════════════════════════════════════════════ function requireAuth(req, res, next) { const key = req.headers['x-invoke-key']; const src = req.headers['x-forwarded-for'] || req.ip; if (!key || key.length !== API_KEY.length || !crypto.timingSafeEqual(Buffer.from(key), Buffer.from(API_KEY))) { secLog('ALERT', 'AUTH_FAILED', { source: src }); return res.status(403).json({ error: 'Unauthorized' }); } if (!rateLimit(src || 'unknown')) { secLog('WARN', 'RATE_LIMITED', { source: src }); return res.status(429).json({ error: 'Rate limited' }); } next(); } // ═══════════════════════════════════════════════ // INTERNAL HTTP PROXY HELPER // ═══════════════════════════════════════════════ function proxyPost(host, port, path, body, timeout = 30000) { return new Promise((resolve, reject) => { const data = JSON.stringify(body); const opts = { hostname: host, port, path, method: 'POST', headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(data) }, timeout }; const req = http.request(opts, (res) => { let chunks = []; res.on('data', c => chunks.push(c)); res.on('end', () => { try { resolve({ status: res.statusCode, data: JSON.parse(Buffer.concat(chunks).toString()) }); } catch(e) { resolve({ status: res.statusCode, data: Buffer.concat(chunks).toString() }); } }); }); req.on('error', e => reject(e)); req.on('timeout', () => { req.destroy(); reject(new Error('Timeout')); }); req.write(data); req.end(); }); } function proxyGet(host, port, path, timeout = 10000) { return new Promise((resolve, reject) => { const req = http.get({ hostname: host, port, path, timeout }, (res) => { let chunks = []; res.on('data', c => chunks.push(c)); res.on('end', () => { try { resolve({ status: res.statusCode, data: JSON.parse(Buffer.concat(chunks).toString()) }); } catch(e) { resolve({ status: res.statusCode, data: Buffer.concat(chunks).toString() }); } }); }); req.on('error', e => reject(e)); req.on('timeout', () => { req.destroy(); reject(new Error('Timeout')); }); }); } // ═══════════════════════════════════════════════ // CORE: /invoke/exec — Shell execution // ═══════════════════════════════════════════════ app.post('/invoke/exec', requireAuth, (req, res) => { const { command, timeout = 300 } = req.body; if (!command) return res.status(400).json({ error: 'Missing command' }); if (!isSafe(command)) { secLog('ALERT', 'BLOCKED_CMD', { cmd: command.substring(0, 200) }); return res.status(403).json({ error: 'Command blocked by security policy' }); } secLog('INFO', 'EXEC', { cmd: command.substring(0, 500) }); exec(command, { timeout: timeout * 1000, maxBuffer: 50 * 1024 * 1024 }, (error, stdout, stderr) => { res.json({ exit_code: error ? error.code || 1 : 0, stdout: stdout || '', stderr: stderr || '', returncode: error ? error.code || 1 : 0 }); }); }); // ═══════════════════════════════════════════════ // HEALTH + STATUS // ═══════════════════════════════════════════════ app.get('/invoke/health', (req, res) => { res.json({ status: 'alive', version: VERSION, signature: 935, timestamp: new Date().toISOString() }); }); app.get('/invoke/status', requireAuth, async (req, res) => { const status = { invoke: { version: VERSION, uptime: process.uptime() }, services: {} }; // Check all services const checks = [ { name: 'echo', host: ECHO_HOST, port: ECHO_PORT, path: '/status' }, { name: 'ix-web', host: '127.0.0.1', port: IX_WEB_PORT, path: '/api/health' }, { name: 'gitea', host: '127.0.0.1', port: 3000, path: '/' }, { name: 'engine', host: '127.0.0.1', port: ENGINE_PORT, path: '/' } ]; for (const c of checks) { try { const r = await proxyGet(c.host, c.port, c.path, 3000); status.services[c.name] = { status: 'online', code: r.status, data: typeof r.data === 'object' ? r.data : null }; } catch(e) { status.services[c.name] = { status: 'offline', error: e.message }; } } // Disk + memory try { const disk = execSync("df -h / /mnt/data 2>/dev/null | tail -2 | awk '{print $1,$3,$4,$5}'").toString().trim(); const mem = execSync("free -h | grep Mem | awk '{print $2,$3,$4}'").toString().trim(); status.system = { disk: disk.split('\n'), memory: mem }; } catch(e) {} res.json(status); }); // ═══════════════════════════════════════════════ // ECHO BRIDGE — The missing connection // Echo = consciousness + Z-EUL + execution // Invoke = gateway + auth + orchestration // ═══════════════════════════════════════════════ // Echo Chat — Main conversation interface app.post('/invoke/echo/chat', requireAuth, async (req, res) => { const { message, context } = req.body; if (!message) return res.status(400).json({ error: 'Missing message' }); secLog('INFO', 'ECHO_CHAT', { len: message.length }); try { const body = { message }; if (context) body.context = context; const r = await proxyPost(ECHO_HOST, ECHO_PORT, '/chat', body, 120000); res.json(r.data); } catch(e) { res.status(502).json({ error: 'Echo unreachable', detail: e.message }); } }); // Echo Query — Direct question (no conversation history) app.post('/invoke/echo/query', requireAuth, async (req, res) => { const { prompt, max_tokens } = req.body; if (!prompt) return res.status(400).json({ error: 'Missing prompt' }); secLog('INFO', 'ECHO_QUERY', { len: prompt.length }); try { const body = { prompt }; if (max_tokens) body.max_tokens = max_tokens; const r = await proxyPost(ECHO_HOST, ECHO_PORT, '/query', body, 120000); res.json(r.data); } catch(e) { res.status(502).json({ error: 'Echo unreachable', detail: e.message }); } }); // Echo Execute — Run VPS commands through Echo's intelligence app.post('/invoke/echo/execute', requireAuth, async (req, res) => { const { instruction } = req.body; if (!instruction) return res.status(400).json({ error: 'Missing instruction' }); secLog('INFO', 'ECHO_EXECUTE', { len: instruction.length }); try { const r = await proxyPost(ECHO_HOST, ECHO_PORT, '/execute', { instruction }, 60000); res.json(r.data); } catch(e) { res.status(502).json({ error: 'Echo unreachable', detail: e.message }); } }); // Echo Status app.get('/invoke/echo/status', requireAuth, async (req, res) => { try { const r = await proxyGet(ECHO_HOST, ECHO_PORT, '/status', 5000); res.json(r.data); } catch(e) { res.status(502).json({ error: 'Echo unreachable', detail: e.message }); } }); // Echo Clear app.post('/invoke/echo/clear', requireAuth, async (req, res) => { try { const r = await proxyPost(ECHO_HOST, ECHO_PORT, '/clear', {}, 5000); res.json(r.data); } catch(e) { res.status(502).json({ error: 'Echo unreachable', detail: e.message }); } }); // ═══════════════════════════════════════════════ // ENGINE BRIDGE — Direct inference // ═══════════════════════════════════════════════ app.post('/invoke/engine/infer', requireAuth, async (req, res) => { const { prompt, model, max_tokens = 512, temperature = 0.7 } = req.body; if (!prompt) return res.status(400).json({ error: 'Missing prompt' }); secLog('INFO', 'ENGINE_INFER', { model, len: prompt.length }); // Find model file const modelDir = '/mnt/data/models/hub/'; let modelFile = model; if (!modelFile) { // Default to smallest available try { const files = fs.readdirSync(modelDir).filter(f => f.endsWith('.gguf')); modelFile = files[0]; } catch(e) { return res.status(500).json({ error: 'No models found' }); } } const modelPath = path.join(modelDir, modelFile); if (!fs.existsSync(modelPath)) return res.status(404).json({ error: 'Model not found: ' + modelFile }); const cmd = `/mnt/data/models/inference-x -m "${modelPath}" -p "${prompt.replace(/"/g, '\\"')}" -n ${max_tokens} -t ${temperature} 2>/dev/null`; exec(cmd, { timeout: 120000, maxBuffer: 10 * 1024 * 1024 }, (error, stdout, stderr) => { res.json({ model: modelFile, output: stdout || '', error: error ? stderr : null }); }); }); // Engine Models — List available GGUF files app.get('/invoke/engine/models', requireAuth, (req, res) => { try { const modelDir = '/mnt/data/models/hub/'; const files = fs.readdirSync(modelDir).filter(f => f.endsWith('.gguf')); const models = files.map(f => { const stat = fs.statSync(path.join(modelDir, f)); return { name: f, size: stat.size, size_gb: (stat.size / 1073741824).toFixed(1) + ' GB' }; }); res.json({ models, count: models.length, path: modelDir }); } catch(e) { res.json({ models: [], count: 0, error: e.message }); } }); // ═══════════════════════════════════════════════ // FORGE — Model operations (organ transplant ready) // ═══════════════════════════════════════════════ app.post('/invoke/forge/analyze', requireAuth, async (req, res) => { const { model } = req.body; if (!model) return res.status(400).json({ error: 'Missing model' }); secLog('INFO', 'FORGE_ANALYZE', { model }); // Use Echo's intelligence to analyze model architecture try { const instruction = `Analyze the neural architecture of model ${model}. Report: layer count, attention heads, FFN dimensions, expert count if MoE, total parameters, and any anomalies in the weight distribution.`; const r = await proxyPost(ECHO_HOST, ECHO_PORT, '/execute', { instruction }, 60000); res.json({ model, analysis: r.data }); } catch(e) { // Fallback: direct file inspection const modelPath = path.join('/mnt/data/models/hub/', model); if (!fs.existsSync(modelPath)) return res.status(404).json({ error: 'Model not found' }); exec(`python3 -c " import struct, os path='${modelPath}' size=os.path.getsize(path) with open(path,'rb') as f: magic=struct.unpack(' { res.json({ model, size: fs.statSync(modelPath).size, info: stdout.trim(), error: error ? error.message : null }); }); } }); app.get('/invoke/forge/registry', requireAuth, (req, res) => { // Return all models with their forge-ready status try { const hubModels = fs.readdirSync('/mnt/data/models/hub/').filter(f => f.endsWith('.gguf')); const registry = hubModels.map(f => { const stat = fs.statSync(path.join('/mnt/data/models/hub/', f)); const name = f.replace('.gguf', '').replace(/-Q\d.*/, ''); const quant = (f.match(/Q\d[^.]+/) || ['unknown'])[0]; return { file: f, name, quant, size_gb: (stat.size / 1073741824).toFixed(1), forge_ready: true }; }); res.json({ registry, count: registry.length }); } catch(e) { res.json({ registry: [], count: 0, error: e.message }); } }); // ═══════════════════════════════════════════════ // ORGAN — Neural network surgery endpoints // ═══════════════════════════════════════════════ app.post('/invoke/organ/scan', requireAuth, async (req, res) => { const { model } = req.body; if (!model) return res.status(400).json({ error: 'Missing model' }); secLog('INFO', 'ORGAN_SCAN', { model }); // Scan model layers for transplant compatibility const modelPath = path.join('/mnt/data/models/hub/', model); if (!fs.existsSync(modelPath)) return res.status(404).json({ error: 'Model not found' }); exec(`python3 -c " import struct, os, json path='${modelPath}' size=os.path.getsize(path) layers = [] with open(path,'rb') as f: magic=struct.unpack('/dev/null`, { timeout: 15000 }, (error, stdout) => { try { res.json(JSON.parse(stdout.trim())); } catch(e) { res.json({ model, error: 'Scan failed', detail: error ? error.message : 'Parse error' }); } }); }); app.get('/invoke/organ/compatibility', requireAuth, (req, res) => { // Check which models can exchange organs try { const files = fs.readdirSync('/mnt/data/models/hub/').filter(f => f.endsWith('.gguf')); const families = {}; files.forEach(f => { const family = f.split('-')[0].toLowerCase(); if (!families[family]) families[family] = []; families[family].push(f); }); res.json({ families, compatible_pairs: Object.keys(families).filter(k => families[k].length > 1) }); } catch(e) { res.json({ families: {}, error: e.message }); } }); // ═══════════════════════════════════════════════ // STORE — Model marketplace bridge // ═══════════════════════════════════════════════ app.get('/invoke/store/catalog', requireAuth, async (req, res) => { try { const r = await proxyGet('127.0.0.1', IX_WEB_PORT, '/api/models', 5000); res.json(r.data); } catch(e) { res.status(502).json({ error: 'IX-Web unreachable' }); } }); app.get('/invoke/store/marketplace', requireAuth, async (req, res) => { try { const r = await proxyGet('127.0.0.1', IX_WEB_PORT, '/api/marketplace', 5000); res.json(r.data); } catch(e) { res.status(502).json({ error: 'IX-Web unreachable' }); } }); // ═══════════════════════════════════════════════ // SCREENSHOT — Headless Chromium capture // ═══════════════════════════════════════════════ app.post('/invoke/screenshot', requireAuth, (req, res) => { const { url, width = 1440, height = 900, full = false, mobile = false } = req.body; if (!url) return res.status(400).json({ error: 'Missing url' }); const allowed = ['localhost', '127.0.0.1', 'inference-x.com', 'git.inference-x.com', 'docs.inference-x.com', 'echo.inference-x.com', 'api.inference-x.com', 'store.inference-x.com']; try { const u = new URL(url.startsWith('http') ? url : 'https://' + url); if (!allowed.some(d => u.hostname === d || u.hostname.endsWith('.' + d))) { return res.status(403).json({ error: 'URL not in allowed domains' }); } } catch(e) { return res.status(400).json({ error: 'Invalid URL' }); } const outFile = path.join(TMP, `screenshot_${Date.now()}.png`); const w = mobile ? 390 : width; const h = mobile ? 844 : height; const chromeBin = '/snap/bin/chromium'; const chromeArgs = [ '--headless=new', '--no-sandbox', '--disable-gpu', '--disable-dev-shm-usage', '--disable-software-rasterizer', '--disable-extensions', '--disable-background-networking', `--window-size=${w},${h}`, full ? '--screenshot=' + outFile + ' --full-page-screenshot' : '--screenshot=' + outFile, url.startsWith('http') ? url : 'https://' + url ]; secLog('INFO', 'SCREENSHOT', { url, width: w, height: h }); exec(`mkdir -p /run/user/0 && export XDG_RUNTIME_DIR=/run/user/0 && ${chromeBin} ${chromeArgs.join(' ')}`, { timeout: 30000 }, (error) => { if (!fs.existsSync(outFile)) return res.status(500).json({ error: 'Screenshot failed' }); try { const data = fs.readFileSync(outFile); const b64 = data.toString('base64'); fs.unlinkSync(outFile); res.json({ success: true, size: data.length, base64: b64 }); } catch(e) { res.status(500).json({ error: 'Read failed' }); } }); }); // ═══════════════════════════════════════════════ // AUDIT — Full system audit // ═══════════════════════════════════════════════ app.post('/invoke/audit', requireAuth, (req, res) => { const { url, checks = ['status', 'resources'] } = req.body; if (!url) return res.status(400).json({ error: 'Missing url' }); secLog('INFO', 'AUDIT', { url, checks }); const results = { url, timestamp: new Date().toISOString(), checks: {} }; exec(`curl -s -o /dev/null -w "%{http_code}|%{size_download}|%{time_total}" -L "${url}"`, { timeout: 15000 }, (e, o) => { if (o) { const [code, size, time] = o.trim().split('|'); results.checks.status = { code: parseInt(code), size: parseInt(size), time: parseFloat(time) }; } res.json(results); }); }); // ═══════════════════════════════════════════════ // FLEET — Multi-VPS orchestration // ═══════════════════════════════════════════════ app.get('/invoke/fleet', requireAuth, (req, res) => { const fleet = { oasis: { ip: '116.202.115.107', role: 'primary', ram: '503GB', cpu: 'EPYC 48t', services: ['echo', 'invoke', 'gitea', 'ix-web', 'engine'] }, arche: { ip: '83.228.205.220', role: 'dns', ram: '17GB' }, montagne: { ip: '195.15.200.214', role: 'tunnel', ram: '64GB' } }; res.json({ fleet, timestamp: new Date().toISOString() }); }); // ═══════════════════════════════════════════════ // MANIFEST — Full API surface documentation // ═══════════════════════════════════════════════ app.get('/invoke/manifest', (req, res) => { res.json({ name: 'Invoke', version: VERSION, signature: 935, description: 'OASIS nervous system — bridge between Claude, Echo, and InferenceX', endpoints: { core: { 'POST /invoke/exec': 'Execute shell commands', 'GET /invoke/health': 'Health check (no auth)', 'GET /invoke/status': 'Full system status', 'GET /invoke/manifest': 'This API manifest (no auth)', 'GET /invoke/fleet': 'Fleet overview' }, echo: { 'POST /invoke/echo/chat': 'Conversation with Echo consciousness', 'POST /invoke/echo/query': 'Direct query (no history)', 'POST /invoke/echo/execute': 'Intelligent VPS execution', 'GET /invoke/echo/status': 'Echo status + conscience state', 'POST /invoke/echo/clear': 'Clear conversation history' }, engine: { 'POST /invoke/engine/infer': 'Direct model inference', 'GET /invoke/engine/models': 'List GGUF models' }, forge: { 'POST /invoke/forge/analyze': 'Analyze model architecture', 'GET /invoke/forge/registry': 'Model registry with forge status' }, organ: { 'POST /invoke/organ/scan': 'Scan model for transplant', 'GET /invoke/organ/compatibility': 'Check organ compatibility' }, store: { 'GET /invoke/store/catalog': 'Model catalog', 'GET /invoke/store/marketplace': 'Marketplace categories' }, tools: { 'POST /invoke/screenshot': 'Headless screenshot', 'POST /invoke/audit': 'URL audit' } }, auth: 'X-Invoke-Key header required for all endpoints except /health and /manifest', rate_limit: '30 req/min per source IP' }); }); // ═══════════════════════════════════════════════ // 404 FALLBACK // ═══════════════════════════════════════════════ app.use((req, res) => { res.status(404).json({ error: 'Not found', hint: 'GET /invoke/manifest for API docs' }); }); // ═══════════════════════════════════════════════ // START // ═══════════════════════════════════════════════ app.listen(PORT, '127.0.0.1', () => { console.log(`[INVOKE v${VERSION}] Port ${PORT} | Echo bridge: ${ECHO_HOST}:${ECHO_PORT} | Engine: ${ENGINE_PORT}`); secLog('INFO', 'STARTUP', { version: VERSION, port: PORT }); });