diff --git a/api/endpoints/agent.php b/api/endpoints/agent.php index c192576..c1cd30f 100644 --- a/api/endpoints/agent.php +++ b/api/endpoints/agent.php @@ -213,7 +213,9 @@ switch ($agentAction) { foreach ($agents as &$a) { $a['capabilities'] = json_decode($a['capabilities'] ?? '[]', true); } - agent_ok(['agents' => $agents, 'my_ip' => $_SERVER['REMOTE_ADDR'] ?? '']); + $realIp = $_SERVER['HTTP_CF_CONNECTING_IP'] ?? $_SERVER['HTTP_X_FORWARDED_FOR'] ?? $_SERVER['REMOTE_ADDR'] ?? ''; + $realIp = trim(explode(',', $realIp)[0]); + agent_ok(['agents' => $agents, 'my_ip' => $realIp]); // ── LATEST METRICS (for dashboard display) ─────────────────────────────── case 'status': diff --git a/public_html/index.html b/public_html/index.html index d920156..5e53939 100644 --- a/public_html/index.html +++ b/public_html/index.html @@ -1741,12 +1741,16 @@ function speak(text) { // ── AGENT DETECTION & BROWSER INSTALL ───────────────────────────────── let _agentOnline = false; +let _myAgent = null; function detectOS() { const ua = navigator.userAgent; const p = (navigator.platform || '').toLowerCase(); - if (p.includes('mac')) return 'mac'; + // Tablets — check before desktop OS (iPads spoof MacIntel) + if (/iPad|Android/.test(ua) || (p.includes('mac') && navigator.maxTouchPoints > 1)) return 'tablet'; + if (/iPhone/.test(ua)) return 'tablet'; if (p.includes('win') || ua.includes('Windows')) return 'windows'; + if (p.includes('mac') || ua.includes('Macintosh')) return 'mac'; if (p.includes('linux') || ua.includes('Linux')) return 'linux'; return 'unknown'; } @@ -1765,12 +1769,19 @@ async function checkAgentStatus() { const cnt = document.getElementById('net-agent-count'); if (cnt) cnt.textContent = online.length + ' AGENT' + (online.length !== 1 ? 'S' : '') + ' ONLINE'; const myIp = data.my_ip || ''; - const myAgent = online.find(a => a.ip_address === myIp); - _agentOnline = !!myAgent; + // Match by exact IP first, then by same /24 subnet (handles NAT behind same router) + const mySubnet = myIp.split('.').slice(0,3).join('.'); + _myAgent = online.find(a => a.ip_address === myIp) + || online.find(a => a.ip_address && a.ip_address.startsWith(mySubnet + '.')); + _agentOnline = !!_myAgent; if (btn) { - if (_agentOnline) { + const isTablet = detectOS() === 'tablet'; + if (isTablet) { + btn.title = 'JARVIS Agent — not available for tablets'; + btn.style.opacity = '0.5'; + } else if (_agentOnline) { btn.classList.add('agent-online'); - btn.title = 'Agent active: ' + myAgent.hostname; + btn.title = 'Agent active: ' + _myAgent.hostname; } else { btn.classList.remove('agent-online'); btn.title = 'Click to install JARVIS Agent on this machine'; @@ -1885,24 +1896,35 @@ function openAgentModal() { const baseUrl = 'https://jarvis.orbishosting.com/agent'; const jUrl = 'https://jarvis.orbishosting.com'; - if (_agentOnline) { + if (os === 'tablet') { + title.textContent = '● JARVIS — TABLET / MOBILE'; + content.innerHTML = + '
✓ You\'re viewing JARVIS on a tablet or mobile device.
' + + '
The JARVIS Agent runs on desktop and server platforms (Windows, macOS, Linux).

' + + 'Tablets and phones can browse the full JARVIS dashboard but do not need an agent installed — all data comes from your other monitored machines.
'; + } else if (_agentOnline) { title.textContent = '● AGENT CONNECTED'; - content.innerHTML = '
✓ JARVIS Agent is running on this machine.
' + - '
Reporting: CPU · Memory · Disk · Services · Uptime
'; + content.innerHTML = + '
✓ JARVIS Agent is active on this machine.
' + + '
' + + 'Host: ' + (_myAgent?.hostname||'—') + '
' + + 'IP: ' + (_myAgent?.ip_address||'—') + '
' + + 'Type: ' + (_myAgent?.agent_type||'—').toUpperCase() + '
' + + 'Reporting: CPU · Memory · Disk · Services · Uptime
'; } else { const inst = { + windows: { + label:'Windows', + cmd:'# Run PowerShell as Administrator:\nSet-ExecutionPolicy Bypass -Scope Process -Force\nInvoke-WebRequest -Uri "'+baseUrl+'/install-windows.ps1" -OutFile "$env:TEMP\\install.ps1"\n& "$env:TEMP\\install.ps1" -JarvisUrl '+jUrl+' -Key '+regKey, + dl: baseUrl+'/install-windows.ps1', + note:'Run PowerShell as Administrator. Installs as a Windows Task Scheduler service.' + }, mac: { label:'macOS', cmd:'bash <(curl -sSL '+baseUrl+'/install-mac.sh) \\\n --jarvis-url '+jUrl+' \\\n --key '+regKey, dl: baseUrl+'/install-mac.sh', note:'Run in Terminal. Installs as a launchd background service.' }, - windows: { - label:'Windows', - cmd:'# Run PowerShell as Administrator:\nSet-ExecutionPolicy Bypass -Scope Process\nInvoke-WebRequest -Uri "'+baseUrl+'/install-windows.ps1" -OutFile install.ps1\n.\\install-windows.ps1 -JarvisUrl '+jUrl+' -Key '+regKey, - dl: baseUrl+'/install-windows.ps1', - note:'Run PowerShell as Administrator. Installs as Task Scheduler service.' - }, linux: { label:'Linux', cmd:'curl -sSL '+baseUrl+'/install.sh | sudo bash -s -- \\\n --jarvis-url '+jUrl+' \\\n --key '+regKey, @@ -1911,18 +1933,20 @@ function openAgentModal() { }, unknown: { label:'Your System', - cmd:'# Download from JARVIS server:\nhttps://jarvis.orbishosting.com/agent/', + cmd:'# Browse installers:\nhttps://jarvis.orbishosting.com/agent/', dl: 'https://jarvis.orbishosting.com/agent/', - note:'Select your platform from the GitHub repo.' + note:'Choose your platform installer from the JARVIS agent directory.' } }; const i = inst[os] || inst.unknown; - title.textContent = '● INSTALL AGENT · ' + i.label.toUpperCase(); + const osBadge = {windows:'🪟 WINDOWS', mac:'🍎 MACOS', linux:'🐧 LINUX', unknown:'❓ UNKNOWN'}[os] || os.toUpperCase(); + title.textContent = '● INSTALL AGENT · ' + (inst[os] ? inst[os].label.toUpperCase() : 'YOUR SYSTEM'); content.innerHTML = + '
DETECTED: ' + osBadge + '
' + '
'+i.note+'
' + '
'+i.cmd+'
' + '↓ DOWNLOAD INSTALLER' + - '
After install, this indicator turns green within 30 seconds.
'; + '
After install, the AGENT indicator turns green within 30 seconds.
'; } modal.classList.add('open'); }