lightman-agent 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agent.config.template.json +30 -0
- package/bin/cms-agent.js +233 -0
- package/nssm/nssm.exe +0 -0
- package/package.json +52 -0
- package/public/assets/index-CcBNCz6h.css +1 -0
- package/public/assets/index-H-8HDl46.js +1 -0
- package/public/index.html +19 -0
- package/scripts/guardian.ps1 +75 -0
- package/scripts/install-linux.sh +134 -0
- package/scripts/install-rpi.sh +117 -0
- package/scripts/install-windows.ps1 +529 -0
- package/scripts/launch-kiosk.vbs +101 -0
- package/scripts/lightman-agent.logrotate +12 -0
- package/scripts/lightman-agent.service +38 -0
- package/scripts/lightman-shell.bat +128 -0
- package/scripts/reinstall-windows.ps1 +26 -0
- package/scripts/restore-desktop.ps1 +32 -0
- package/scripts/setup.ps1 +116 -0
- package/scripts/setup.sh +115 -0
- package/scripts/uninstall-linux.sh +50 -0
- package/scripts/uninstall-windows.ps1 +54 -0
- package/src/commands/display.ts +177 -0
- package/src/commands/kiosk.ts +113 -0
- package/src/commands/maintenance.ts +106 -0
- package/src/commands/network.ts +129 -0
- package/src/commands/power.ts +163 -0
- package/src/commands/rpi.ts +45 -0
- package/src/commands/screenshot.ts +166 -0
- package/src/commands/serial.ts +17 -0
- package/src/commands/update.ts +124 -0
- package/src/index.ts +652 -0
- package/src/lib/config.ts +69 -0
- package/src/lib/identity.ts +40 -0
- package/src/lib/logger.ts +137 -0
- package/src/lib/platform.ts +10 -0
- package/src/lib/rpi.ts +180 -0
- package/src/lib/screens.ts +128 -0
- package/src/lib/types.ts +176 -0
- package/src/services/commands.ts +107 -0
- package/src/services/health.ts +161 -0
- package/src/services/kiosk.ts +395 -0
- package/src/services/localEvents.ts +60 -0
- package/src/services/logForwarder.ts +72 -0
- package/src/services/multiScreenKiosk.ts +324 -0
- package/src/services/oscBridge.ts +186 -0
- package/src/services/powerScheduler.ts +260 -0
- package/src/services/provisioning.ts +120 -0
- package/src/services/serialBridge.ts +230 -0
- package/src/services/serviceLauncher.ts +183 -0
- package/src/services/staticServer.ts +226 -0
- package/src/services/updater.ts +249 -0
- package/src/services/watchdog.ts +310 -0
- package/src/services/websocket.ts +152 -0
- package/tsconfig.json +28 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
[Unit]
|
|
2
|
+
Description=LIGHTMAN Agent - Museum Display Management
|
|
3
|
+
Documentation=https://github.com/sagrkv/lightman-app01
|
|
4
|
+
After=network-online.target
|
|
5
|
+
Wants=network-online.target
|
|
6
|
+
|
|
7
|
+
[Service]
|
|
8
|
+
Type=simple
|
|
9
|
+
User=lightman
|
|
10
|
+
Group=lightman
|
|
11
|
+
WorkingDirectory=/opt/lightman/agent
|
|
12
|
+
ExecStart=/usr/bin/node dist/index.js
|
|
13
|
+
Restart=always
|
|
14
|
+
RestartSec=10
|
|
15
|
+
StartLimitIntervalSec=300
|
|
16
|
+
StartLimitBurst=5
|
|
17
|
+
|
|
18
|
+
# Environment
|
|
19
|
+
Environment=NODE_ENV=production
|
|
20
|
+
EnvironmentFile=-/opt/lightman/agent/.env
|
|
21
|
+
|
|
22
|
+
# Security hardening
|
|
23
|
+
ProtectSystem=strict
|
|
24
|
+
ReadWritePaths=/opt/lightman/agent /var/log/lightman /tmp
|
|
25
|
+
PrivateTmp=true
|
|
26
|
+
NoNewPrivileges=true
|
|
27
|
+
ProtectHome=true
|
|
28
|
+
ProtectKernelTunables=true
|
|
29
|
+
ProtectControlGroups=true
|
|
30
|
+
RestrictSUIDSGID=true
|
|
31
|
+
|
|
32
|
+
# Logging
|
|
33
|
+
StandardOutput=journal
|
|
34
|
+
StandardError=journal
|
|
35
|
+
SyslogIdentifier=lightman-agent
|
|
36
|
+
|
|
37
|
+
[Install]
|
|
38
|
+
WantedBy=multi-user.target
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
@echo off
|
|
2
|
+
REM ================================================================
|
|
3
|
+
REM LIGHTMAN Shell - Replaces explorer.exe as the Windows shell
|
|
4
|
+
REM ================================================================
|
|
5
|
+
REM SINGLE SOURCE OF TRUTH: agent.config.json
|
|
6
|
+
REM
|
|
7
|
+
REM Boot flow:
|
|
8
|
+
REM 1. Auto-login (no password)
|
|
9
|
+
REM 2. This script runs INSTEAD of explorer.exe
|
|
10
|
+
REM 3. Reads slug + browser from agent.config.json (THE ONLY SOURCE)
|
|
11
|
+
REM 4. Waits for agent service (port 3403)
|
|
12
|
+
REM 5. Launches Chrome fullscreen
|
|
13
|
+
REM 6. If Chrome crashes, relaunches in 3 seconds (infinite loop)
|
|
14
|
+
REM ================================================================
|
|
15
|
+
|
|
16
|
+
set INSTALL_DIR=C:\Program Files\Lightman\Agent
|
|
17
|
+
set CONFIG_FILE=%INSTALL_DIR%\agent.config.json
|
|
18
|
+
set CHROME_DATA=C:\ProgramData\Lightman\chrome-kiosk
|
|
19
|
+
set LOG_FILE=C:\ProgramData\Lightman\logs\shell.log
|
|
20
|
+
|
|
21
|
+
REM Ensure directories exist
|
|
22
|
+
if not exist "C:\ProgramData\Lightman\logs" mkdir "C:\ProgramData\Lightman\logs"
|
|
23
|
+
if not exist "%CHROME_DATA%" mkdir "%CHROME_DATA%"
|
|
24
|
+
|
|
25
|
+
echo [%date% %time%] ===== LIGHTMAN Shell starting ===== >> "%LOG_FILE%"
|
|
26
|
+
|
|
27
|
+
REM ----------------------------------------------------------------
|
|
28
|
+
REM Read slug and browser from agent.config.json ONLY
|
|
29
|
+
REM No sidecar files, no hardcoded URLs, no confusion.
|
|
30
|
+
REM ----------------------------------------------------------------
|
|
31
|
+
set DEVICE_SLUG=
|
|
32
|
+
set BROWSER=
|
|
33
|
+
set URL=
|
|
34
|
+
|
|
35
|
+
REM Wait for node.exe to be available
|
|
36
|
+
set NODE_WAIT=0
|
|
37
|
+
:wait_for_node
|
|
38
|
+
where node >nul 2>&1
|
|
39
|
+
if %errorlevel%==0 goto node_ready
|
|
40
|
+
set /a NODE_WAIT+=1
|
|
41
|
+
if %NODE_WAIT% geq 30 (
|
|
42
|
+
echo [%date% %time%] ERROR: node.exe not found after 30s >> "%LOG_FILE%"
|
|
43
|
+
goto use_fallbacks
|
|
44
|
+
)
|
|
45
|
+
timeout /t 1 /nobreak >nul
|
|
46
|
+
goto wait_for_node
|
|
47
|
+
|
|
48
|
+
:node_ready
|
|
49
|
+
|
|
50
|
+
REM Read slug from config
|
|
51
|
+
if exist "%CONFIG_FILE%" (
|
|
52
|
+
for /f "delims=" %%a in ('node -e "try{console.log(JSON.parse(require('fs').readFileSync(String.raw`%CONFIG_FILE%`,'utf8')).deviceSlug)}catch(e){console.log('')}" 2^>nul') do set DEVICE_SLUG=%%a
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
REM Read browser from config
|
|
56
|
+
if exist "%CONFIG_FILE%" (
|
|
57
|
+
for /f "delims=" %%a in ('node -e "try{const c=JSON.parse(require('fs').readFileSync(String.raw`%CONFIG_FILE%`,'utf8'));console.log(c.kiosk&&c.kiosk.browserPath||'')}catch(e){console.log('')}" 2^>nul') do set BROWSER=%%a
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
:use_fallbacks
|
|
61
|
+
|
|
62
|
+
REM Build URL from slug (ALWAYS from config, never from sidecar)
|
|
63
|
+
if not "%DEVICE_SLUG%"=="" (
|
|
64
|
+
set URL=http://localhost:3403/display/%DEVICE_SLUG%
|
|
65
|
+
echo [%date% %time%] Slug: %DEVICE_SLUG% >> "%LOG_FILE%"
|
|
66
|
+
) else (
|
|
67
|
+
set URL=http://localhost:3403/display
|
|
68
|
+
echo [%date% %time%] WARNING: No slug in config! >> "%LOG_FILE%"
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
REM Fallback browser
|
|
72
|
+
if "%BROWSER%"=="" (
|
|
73
|
+
if exist "C:\Program Files\Google\Chrome\Application\chrome.exe" (
|
|
74
|
+
set "BROWSER=C:\Program Files\Google\Chrome\Application\chrome.exe"
|
|
75
|
+
) else if exist "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" (
|
|
76
|
+
set "BROWSER=C:\Program Files (x86)\Google\Chrome\Application\chrome.exe"
|
|
77
|
+
) else (
|
|
78
|
+
echo [%date% %time%] ERROR: Chrome not found! >> "%LOG_FILE%"
|
|
79
|
+
start explorer.exe
|
|
80
|
+
exit /b 1
|
|
81
|
+
)
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
echo [%date% %time%] Browser: %BROWSER% >> "%LOG_FILE%"
|
|
85
|
+
echo [%date% %time%] URL: %URL% >> "%LOG_FILE%"
|
|
86
|
+
|
|
87
|
+
REM ----------------------------------------------------------------
|
|
88
|
+
REM Wait for agent service (port 3403)
|
|
89
|
+
REM ----------------------------------------------------------------
|
|
90
|
+
echo [%date% %time%] Waiting for port 3403... >> "%LOG_FILE%"
|
|
91
|
+
set WAIT_COUNT=0
|
|
92
|
+
set MAX_WAIT=60
|
|
93
|
+
|
|
94
|
+
:wait_for_agent
|
|
95
|
+
netstat -an | findstr ":3403.*LISTENING" >nul 2>&1
|
|
96
|
+
if %errorlevel%==0 goto agent_ready
|
|
97
|
+
set /a WAIT_COUNT+=1
|
|
98
|
+
if %WAIT_COUNT% geq %MAX_WAIT% (
|
|
99
|
+
echo [%date% %time%] Port 3403 not ready after %MAX_WAIT%s, launching anyway >> "%LOG_FILE%"
|
|
100
|
+
goto agent_ready
|
|
101
|
+
)
|
|
102
|
+
timeout /t 1 /nobreak >nul
|
|
103
|
+
goto wait_for_agent
|
|
104
|
+
|
|
105
|
+
:agent_ready
|
|
106
|
+
echo [%date% %time%] Agent ready >> "%LOG_FILE%"
|
|
107
|
+
|
|
108
|
+
REM ----------------------------------------------------------------
|
|
109
|
+
REM Infinite Chrome loop
|
|
110
|
+
REM ----------------------------------------------------------------
|
|
111
|
+
:loop
|
|
112
|
+
REM Re-read slug from config on every loop iteration
|
|
113
|
+
REM This way if someone changes agent.config.json, the next
|
|
114
|
+
REM Chrome restart picks up the new slug automatically.
|
|
115
|
+
if exist "%CONFIG_FILE%" (
|
|
116
|
+
for /f "delims=" %%a in ('node -e "try{console.log(JSON.parse(require('fs').readFileSync(String.raw`%CONFIG_FILE%`,'utf8')).deviceSlug)}catch(e){console.log('')}" 2^>nul') do (
|
|
117
|
+
if not "%%a"=="" set URL=http://localhost:3403/display/%%a
|
|
118
|
+
)
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
echo [%date% %time%] Launching Chrome: %URL% >> "%LOG_FILE%"
|
|
122
|
+
|
|
123
|
+
start /wait "" "%BROWSER%" --kiosk --noerrdialogs --disable-infobars --disable-session-crashed-bubble --no-first-run --no-default-browser-check --start-fullscreen --disable-translate --disable-extensions --autoplay-policy=no-user-gesture-required --disable-features=TranslateUI --user-data-dir="%CHROME_DATA%" "%URL%"
|
|
124
|
+
|
|
125
|
+
echo [%date% %time%] Chrome exited (code: %errorlevel%). Restarting in 3s... >> "%LOG_FILE%"
|
|
126
|
+
timeout /t 3 /nobreak >nul
|
|
127
|
+
|
|
128
|
+
goto loop
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#Requires -RunAsAdministrator
|
|
2
|
+
<#
|
|
3
|
+
.SYNOPSIS
|
|
4
|
+
LIGHTMAN Agent - Reinstall (install-windows.ps1 handles cleanup automatically)
|
|
5
|
+
.EXAMPLE
|
|
6
|
+
powershell -ExecutionPolicy Bypass -File scripts\reinstall-windows.ps1 -Slug "F-AV04" -Server "http://192.168.1.180:3401" -ShellReplace
|
|
7
|
+
#>
|
|
8
|
+
param(
|
|
9
|
+
[Parameter(Mandatory=$true)] [string]$Slug,
|
|
10
|
+
[Parameter(Mandatory=$true)] [string]$Server,
|
|
11
|
+
[switch]$ShellReplace = $false,
|
|
12
|
+
[string]$Timezone = "Asia/Kolkata",
|
|
13
|
+
[switch]$NoReboot = $false
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
|
17
|
+
|
|
18
|
+
$args = @("-ExecutionPolicy", "Bypass", "-File", "$ScriptDir\install-windows.ps1", "-Slug", $Slug, "-Server", $Server, "-Timezone", $Timezone)
|
|
19
|
+
if ($ShellReplace) { $args += "-ShellReplace" }
|
|
20
|
+
& powershell @args
|
|
21
|
+
|
|
22
|
+
if (-not $NoReboot) {
|
|
23
|
+
Write-Host " Rebooting in 10 seconds... (Ctrl+C to cancel)" -ForegroundColor Yellow
|
|
24
|
+
Start-Sleep -Seconds 10
|
|
25
|
+
Restart-Computer -Force
|
|
26
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# LIGHTMAN - Restore Windows Desktop
|
|
2
|
+
# Reverses shell replacement: sets explorer.exe back as the Windows shell.
|
|
3
|
+
# Run via RDP with admin account, or from Safe Mode:
|
|
4
|
+
# powershell -ExecutionPolicy Bypass -File restore-desktop.ps1
|
|
5
|
+
#Requires -RunAsAdministrator
|
|
6
|
+
|
|
7
|
+
$ErrorActionPreference = "Stop"
|
|
8
|
+
|
|
9
|
+
Write-Host ""
|
|
10
|
+
Write-Host "=== LIGHTMAN - Restore Windows Desktop ===" -ForegroundColor Cyan
|
|
11
|
+
Write-Host ""
|
|
12
|
+
|
|
13
|
+
# Restore HKLM shell
|
|
14
|
+
$HKLMPath = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon"
|
|
15
|
+
$original = (Get-ItemProperty -Path $HKLMPath -Name "Shell_Original" -ErrorAction SilentlyContinue).Shell_Original
|
|
16
|
+
if ($original) {
|
|
17
|
+
Set-ItemProperty -Path $HKLMPath -Name "Shell" -Value $original
|
|
18
|
+
Write-Host " HKLM shell restored to: $original" -ForegroundColor Green
|
|
19
|
+
} else {
|
|
20
|
+
Set-ItemProperty -Path $HKLMPath -Name "Shell" -Value "explorer.exe"
|
|
21
|
+
Write-Host " HKLM shell restored to: explorer.exe" -ForegroundColor Green
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
# Remove HKCU shell override
|
|
25
|
+
$HKCUPath = "HKCU:\Software\Microsoft\Windows NT\CurrentVersion\Winlogon"
|
|
26
|
+
Remove-ItemProperty -Path $HKCUPath -Name "Shell" -ErrorAction SilentlyContinue
|
|
27
|
+
Write-Host " HKCU shell override removed" -ForegroundColor Green
|
|
28
|
+
|
|
29
|
+
Write-Host ""
|
|
30
|
+
Write-Host " Desktop will be restored on next reboot." -ForegroundColor Yellow
|
|
31
|
+
Write-Host " Run: Restart-Computer" -ForegroundColor Yellow
|
|
32
|
+
Write-Host ""
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# LIGHTMAN Agent - Device Setup Script (Windows)
|
|
2
|
+
# Generates agent.config.json for this specific device.
|
|
3
|
+
#
|
|
4
|
+
# Usage (run from agent directory or scripts directory):
|
|
5
|
+
# powershell -ExecutionPolicy Bypass -File setup.ps1 -Slug "f-av01" -Server "http://192.168.1.100:3401"
|
|
6
|
+
# powershell -ExecutionPolicy Bypass -File setup.ps1 -Slug "f-av01" -Server "http://192.168.1.100:3401" -Timezone "Asia/Kolkata"
|
|
7
|
+
#
|
|
8
|
+
# This script MUST be run once on every new device installation.
|
|
9
|
+
# It clears any cached identity so the device provisions fresh.
|
|
10
|
+
|
|
11
|
+
param(
|
|
12
|
+
[Parameter(Mandatory=$true)]
|
|
13
|
+
[string]$Slug,
|
|
14
|
+
|
|
15
|
+
[Parameter(Mandatory=$true)]
|
|
16
|
+
[string]$Server,
|
|
17
|
+
|
|
18
|
+
[Parameter(Mandatory=$false)]
|
|
19
|
+
[string]$Timezone = "Asia/Kolkata",
|
|
20
|
+
|
|
21
|
+
[Parameter(Mandatory=$false)]
|
|
22
|
+
[string]$InstallDir = $null,
|
|
23
|
+
|
|
24
|
+
[Parameter(Mandatory=$false)]
|
|
25
|
+
[switch]$ShellMode = $false
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
$ErrorActionPreference = "Stop"
|
|
29
|
+
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
|
30
|
+
$AgentDir = Split-Path -Parent $ScriptDir
|
|
31
|
+
|
|
32
|
+
# Default install dir: the agent folder itself (for dev) or passed explicitly
|
|
33
|
+
if (-not $InstallDir) {
|
|
34
|
+
$InstallDir = $AgentDir
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
Write-Host ""
|
|
38
|
+
Write-Host "=== LIGHTMAN Agent - Device Setup ===" -ForegroundColor Cyan
|
|
39
|
+
Write-Host " Slug: $Slug"
|
|
40
|
+
Write-Host " Server: $Server"
|
|
41
|
+
Write-Host " Install dir: $InstallDir"
|
|
42
|
+
Write-Host " Timezone: $Timezone"
|
|
43
|
+
Write-Host ""
|
|
44
|
+
|
|
45
|
+
# 1. Clear cached identity (CRITICAL - prevents old device credentials leaking)
|
|
46
|
+
$IdentityFile = Join-Path $InstallDir ".lightman-identity.json"
|
|
47
|
+
if (Test-Path $IdentityFile) {
|
|
48
|
+
Remove-Item $IdentityFile -Force
|
|
49
|
+
Write-Host "[OK] Cleared old identity cache (.lightman-identity.json)" -ForegroundColor Green
|
|
50
|
+
} else {
|
|
51
|
+
Write-Host "[OK] No existing identity cache found (clean install)" -ForegroundColor DarkGray
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
# 2. Kiosk display URL - always localhost since agent runs the static server locally on port 3403
|
|
55
|
+
$KioskUrl = "http://localhost:3403/display/$Slug"
|
|
56
|
+
|
|
57
|
+
# 3. Detect browser path
|
|
58
|
+
$BrowserPath = "C:\Program Files\Google\Chrome\Application\chrome.exe"
|
|
59
|
+
if (-not (Test-Path $BrowserPath)) {
|
|
60
|
+
$BrowserPath = "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe"
|
|
61
|
+
}
|
|
62
|
+
if (-not (Test-Path $BrowserPath)) {
|
|
63
|
+
$BrowserPath = "chromium-browser"
|
|
64
|
+
Write-Host "[WARN] Chrome not found - using 'chromium-browser'" -ForegroundColor Yellow
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
$ChromeDataDir = "C:\ProgramData\Lightman\chrome-kiosk"
|
|
68
|
+
|
|
69
|
+
# 4. Read template
|
|
70
|
+
$TemplatePath = Join-Path $AgentDir "agent.config.template.json"
|
|
71
|
+
if (-not (Test-Path $TemplatePath)) {
|
|
72
|
+
# If running from install dir (post-install), template should have been copied there
|
|
73
|
+
$TemplatePath = Join-Path $InstallDir "agent.config.template.json"
|
|
74
|
+
}
|
|
75
|
+
if (-not (Test-Path $TemplatePath)) {
|
|
76
|
+
Write-Host "[ERROR] Template not found. Expected: $TemplatePath" -ForegroundColor Red
|
|
77
|
+
exit 1
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
$Template = Get-Content $TemplatePath -Raw
|
|
81
|
+
|
|
82
|
+
# 5. Replace placeholders
|
|
83
|
+
$BrowserEscaped = $BrowserPath -replace '\\', '\\'
|
|
84
|
+
$ChromeDirEscaped = $ChromeDataDir -replace '\\', '\\'
|
|
85
|
+
|
|
86
|
+
$Config = $Template `
|
|
87
|
+
-replace '__SERVER_URL__', $Server `
|
|
88
|
+
-replace '__DEVICE_SLUG__', $Slug `
|
|
89
|
+
-replace '__KIOSK_URL__', $KioskUrl `
|
|
90
|
+
-replace '__BROWSER_PATH__', $BrowserEscaped `
|
|
91
|
+
-replace '__CHROME_DATA_DIR__', $ChromeDirEscaped `
|
|
92
|
+
-replace 'Asia/Kolkata', $Timezone
|
|
93
|
+
|
|
94
|
+
# 6. Inject shellMode into kiosk config if requested
|
|
95
|
+
if ($ShellMode) {
|
|
96
|
+
# Parse as object, set shellMode, re-serialize (reliable, no regex fragility)
|
|
97
|
+
$configObj = $Config | ConvertFrom-Json
|
|
98
|
+
$configObj.kiosk | Add-Member -NotePropertyName "shellMode" -NotePropertyValue $true -Force
|
|
99
|
+
$Config = $configObj | ConvertTo-Json -Depth 4
|
|
100
|
+
Write-Host "[OK] Shell replacement mode enabled in config" -ForegroundColor Magenta
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
# 7. Write config
|
|
104
|
+
$ConfigPath = Join-Path $InstallDir "agent.config.json"
|
|
105
|
+
# Write as UTF-8 WITHOUT BOM (BOM breaks JSON parsing in Node.js)
|
|
106
|
+
[System.IO.File]::WriteAllText($ConfigPath, $Config, [System.Text.UTF8Encoding]::new($false))
|
|
107
|
+
|
|
108
|
+
Write-Host "[OK] Created agent.config.json" -ForegroundColor Green
|
|
109
|
+
Write-Host ""
|
|
110
|
+
Write-Host " Device slug : $Slug"
|
|
111
|
+
Write-Host " Server : $Server"
|
|
112
|
+
Write-Host " Kiosk URL : $KioskUrl"
|
|
113
|
+
Write-Host ""
|
|
114
|
+
Write-Host "Setup complete. Start the agent - it will provision automatically." -ForegroundColor Cyan
|
|
115
|
+
Write-Host "(If IP matches, provisioning is instant. Otherwise enter pairing code shown in admin.)" -ForegroundColor DarkGray
|
|
116
|
+
Write-Host ""
|
package/scripts/setup.sh
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# LIGHTMAN Agent — Device Setup Script (Linux / Raspberry Pi)
|
|
3
|
+
# Generates agent.config.json for this specific device.
|
|
4
|
+
#
|
|
5
|
+
# Usage:
|
|
6
|
+
# sudo bash setup.sh --slug f-av01 --server http://192.168.1.100:3401
|
|
7
|
+
# sudo bash setup.sh --slug f-av01 --server http://192.168.1.100:3401 --timezone Asia/Kolkata --dir /opt/lightman/agent
|
|
8
|
+
#
|
|
9
|
+
# This script MUST be run once on every new device installation.
|
|
10
|
+
# It clears any cached identity so the device provisions fresh.
|
|
11
|
+
|
|
12
|
+
set -euo pipefail
|
|
13
|
+
|
|
14
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
15
|
+
AGENT_DIR="$(dirname "$SCRIPT_DIR")"
|
|
16
|
+
|
|
17
|
+
# Defaults
|
|
18
|
+
SLUG=""
|
|
19
|
+
SERVER=""
|
|
20
|
+
TIMEZONE="Asia/Kolkata"
|
|
21
|
+
INSTALL_DIR="/opt/lightman/agent"
|
|
22
|
+
|
|
23
|
+
# ── Parse arguments ──
|
|
24
|
+
while [[ $# -gt 0 ]]; do
|
|
25
|
+
case $1 in
|
|
26
|
+
--slug) SLUG="$2"; shift 2 ;;
|
|
27
|
+
--server) SERVER="$2"; shift 2 ;;
|
|
28
|
+
--timezone) TIMEZONE="$2"; shift 2 ;;
|
|
29
|
+
--dir) INSTALL_DIR="$2"; shift 2 ;;
|
|
30
|
+
-h|--help)
|
|
31
|
+
echo "Usage: bash setup.sh --slug SLUG --server http://SERVER:3401 [--timezone TZ] [--dir /path]"
|
|
32
|
+
exit 0
|
|
33
|
+
;;
|
|
34
|
+
*) echo "Unknown option: $1"; exit 1 ;;
|
|
35
|
+
esac
|
|
36
|
+
done
|
|
37
|
+
|
|
38
|
+
if [[ -z "$SLUG" ]]; then
|
|
39
|
+
echo "Error: --slug is required"
|
|
40
|
+
echo "Usage: bash setup.sh --slug f-av01 --server http://192.168.1.100:3401"
|
|
41
|
+
exit 1
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
if [[ -z "$SERVER" ]]; then
|
|
45
|
+
echo "Error: --server is required"
|
|
46
|
+
echo "Usage: bash setup.sh --slug f-av01 --server http://192.168.1.100:3401"
|
|
47
|
+
exit 1
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
echo ""
|
|
51
|
+
echo "=== LIGHTMAN Agent — Device Setup ==="
|
|
52
|
+
echo " Slug: $SLUG"
|
|
53
|
+
echo " Server: $SERVER"
|
|
54
|
+
echo " Install dir: $INSTALL_DIR"
|
|
55
|
+
echo " Timezone: $TIMEZONE"
|
|
56
|
+
echo ""
|
|
57
|
+
|
|
58
|
+
# ── 1. Clear cached identity (CRITICAL — prevents old device credentials leaking) ──
|
|
59
|
+
IDENTITY_FILE="$INSTALL_DIR/.lightman-identity.json"
|
|
60
|
+
if [[ -f "$IDENTITY_FILE" ]]; then
|
|
61
|
+
rm -f "$IDENTITY_FILE"
|
|
62
|
+
echo "[OK] Cleared old identity cache (.lightman-identity.json)"
|
|
63
|
+
else
|
|
64
|
+
echo "[OK] No existing identity cache found (clean install)"
|
|
65
|
+
fi
|
|
66
|
+
|
|
67
|
+
# ── 2. Derive kiosk display URL from server URL ──
|
|
68
|
+
# Replace port with 3403 (display server)
|
|
69
|
+
KIOSK_BASE="$(echo "$SERVER" | sed 's/:[0-9]*$//')"
|
|
70
|
+
KIOSK_URL="${KIOSK_BASE}:3403/display/${SLUG}"
|
|
71
|
+
|
|
72
|
+
# ── 3. Detect browser ──
|
|
73
|
+
BROWSER_PATH="chromium-browser"
|
|
74
|
+
if command -v chromium &>/dev/null; then
|
|
75
|
+
BROWSER_PATH="chromium"
|
|
76
|
+
elif command -v chromium-browser &>/dev/null; then
|
|
77
|
+
BROWSER_PATH="chromium-browser"
|
|
78
|
+
elif command -v google-chrome &>/dev/null; then
|
|
79
|
+
BROWSER_PATH="google-chrome"
|
|
80
|
+
fi
|
|
81
|
+
CHROME_DATA_DIR="/opt/lightman/chrome-kiosk"
|
|
82
|
+
|
|
83
|
+
# ── 4. Find template ──
|
|
84
|
+
TEMPLATE="$AGENT_DIR/agent.config.template.json"
|
|
85
|
+
if [[ ! -f "$TEMPLATE" ]]; then
|
|
86
|
+
# Post-install: template may be in install dir
|
|
87
|
+
TEMPLATE="$INSTALL_DIR/agent.config.template.json"
|
|
88
|
+
fi
|
|
89
|
+
if [[ ! -f "$TEMPLATE" ]]; then
|
|
90
|
+
echo "[ERROR] Template not found at $TEMPLATE"
|
|
91
|
+
exit 1
|
|
92
|
+
fi
|
|
93
|
+
|
|
94
|
+
# ── 5. Create install dir if needed ──
|
|
95
|
+
mkdir -p "$INSTALL_DIR"
|
|
96
|
+
|
|
97
|
+
# ── 6. Replace placeholders and write config ──
|
|
98
|
+
sed \
|
|
99
|
+
-e "s|__SERVER_URL__|${SERVER}|g" \
|
|
100
|
+
-e "s|__DEVICE_SLUG__|${SLUG}|g" \
|
|
101
|
+
-e "s|__KIOSK_URL__|${KIOSK_URL}|g" \
|
|
102
|
+
-e "s|__BROWSER_PATH__|${BROWSER_PATH}|g" \
|
|
103
|
+
-e "s|__CHROME_DATA_DIR__|${CHROME_DATA_DIR}|g" \
|
|
104
|
+
-e "s|Asia/Kolkata|${TIMEZONE}|g" \
|
|
105
|
+
"$TEMPLATE" > "$INSTALL_DIR/agent.config.json"
|
|
106
|
+
|
|
107
|
+
echo "[OK] Created agent.config.json"
|
|
108
|
+
echo ""
|
|
109
|
+
echo " Device slug : $SLUG"
|
|
110
|
+
echo " Server : $SERVER"
|
|
111
|
+
echo " Kiosk URL : $KIOSK_URL"
|
|
112
|
+
echo ""
|
|
113
|
+
echo "Setup complete. Start the agent — it will provision automatically."
|
|
114
|
+
echo "(If IP matches, provisioning is instant. Otherwise enter pairing code shown in admin.)"
|
|
115
|
+
echo ""
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# LIGHTMAN Agent — Linux Uninstaller
|
|
3
|
+
# Run as root: sudo bash uninstall-linux.sh
|
|
4
|
+
set -euo pipefail
|
|
5
|
+
|
|
6
|
+
INSTALL_DIR="/opt/lightman/agent"
|
|
7
|
+
LOG_DIR="/var/log/lightman"
|
|
8
|
+
SERVICE_NAME="lightman-agent"
|
|
9
|
+
|
|
10
|
+
if [[ $EUID -ne 0 ]]; then
|
|
11
|
+
echo "Error: This script must be run as root (use sudo)."
|
|
12
|
+
exit 1
|
|
13
|
+
fi
|
|
14
|
+
|
|
15
|
+
echo "=== LIGHTMAN Agent — Linux Uninstaller ==="
|
|
16
|
+
echo ""
|
|
17
|
+
|
|
18
|
+
# --- Stop and disable service ---
|
|
19
|
+
echo "[1/5] Stopping service..."
|
|
20
|
+
systemctl stop "$SERVICE_NAME" 2>/dev/null || true
|
|
21
|
+
systemctl disable "$SERVICE_NAME" 2>/dev/null || true
|
|
22
|
+
|
|
23
|
+
# --- Remove systemd unit ---
|
|
24
|
+
echo "[2/5] Removing systemd unit..."
|
|
25
|
+
rm -f "/etc/systemd/system/${SERVICE_NAME}.service"
|
|
26
|
+
systemctl daemon-reload
|
|
27
|
+
|
|
28
|
+
# --- Remove logrotate config ---
|
|
29
|
+
echo "[3/5] Removing logrotate config..."
|
|
30
|
+
rm -f "/etc/logrotate.d/${SERVICE_NAME}"
|
|
31
|
+
|
|
32
|
+
# --- Remove installation directory ---
|
|
33
|
+
echo "[4/5] Removing ${INSTALL_DIR}..."
|
|
34
|
+
rm -rf "$INSTALL_DIR"
|
|
35
|
+
|
|
36
|
+
# --- Remove log directory ---
|
|
37
|
+
echo "[5/5] Removing ${LOG_DIR}..."
|
|
38
|
+
rm -rf "$LOG_DIR"
|
|
39
|
+
|
|
40
|
+
# --- Remove user/group (optional) ---
|
|
41
|
+
read -rp "Remove 'lightman' user and group? [y/N]: " REMOVE_USER
|
|
42
|
+
if [[ "$REMOVE_USER" =~ ^[Yy]$ ]]; then
|
|
43
|
+
userdel lightman 2>/dev/null || true
|
|
44
|
+
groupdel lightman 2>/dev/null || true
|
|
45
|
+
echo "User and group removed."
|
|
46
|
+
fi
|
|
47
|
+
|
|
48
|
+
echo ""
|
|
49
|
+
echo "=== Uninstallation Complete ==="
|
|
50
|
+
echo ""
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# LIGHTMAN Agent - Windows Uninstaller
|
|
2
|
+
# Removes everything: service, tasks, processes, files, shell.
|
|
3
|
+
#Requires -RunAsAdministrator
|
|
4
|
+
|
|
5
|
+
$ErrorActionPreference = "Continue"
|
|
6
|
+
$NssmExe = "C:\ProgramData\Lightman\nssm\nssm.exe"
|
|
7
|
+
$ServiceName = "LightmanAgent"
|
|
8
|
+
|
|
9
|
+
Write-Host ""
|
|
10
|
+
Write-Host "=== LIGHTMAN Agent - Uninstaller ===" -ForegroundColor Cyan
|
|
11
|
+
|
|
12
|
+
# 1. Service
|
|
13
|
+
Write-Host "[1/6] Removing service..." -ForegroundColor Yellow
|
|
14
|
+
if (Test-Path $NssmExe) { & $NssmExe stop $ServiceName 2>$null; & $NssmExe remove $ServiceName confirm 2>$null }
|
|
15
|
+
foreach ($sn in @($ServiceName,"lightmanagent.exe")) { sc.exe stop $sn 2>$null; sc.exe delete $sn 2>$null }
|
|
16
|
+
$s = Get-Service -DisplayName "LIGHTMAN*" -ErrorAction SilentlyContinue
|
|
17
|
+
if ($s) { Stop-Service $s.Name -Force -ErrorAction SilentlyContinue; sc.exe delete $s.Name 2>$null }
|
|
18
|
+
|
|
19
|
+
# 2. Tasks
|
|
20
|
+
Write-Host "[2/6] Removing tasks..." -ForegroundColor Yellow
|
|
21
|
+
foreach ($tn in @("LIGHTMAN Agent","LIGHTMAN Kiosk Browser","LIGHTMAN Guardian")) {
|
|
22
|
+
$t = Get-ScheduledTask -TaskName $tn -ErrorAction SilentlyContinue
|
|
23
|
+
if ($t) { Stop-ScheduledTask -TaskName $tn -ErrorAction SilentlyContinue; Unregister-ScheduledTask -TaskName $tn -Confirm:$false -ErrorAction SilentlyContinue }
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
# 3. Processes
|
|
27
|
+
Write-Host "[3/6] Killing processes..." -ForegroundColor Yellow
|
|
28
|
+
Get-Process -Name "node" -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue
|
|
29
|
+
Get-Process -Name "chrome" -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue
|
|
30
|
+
|
|
31
|
+
# 4. Firewall
|
|
32
|
+
Write-Host "[4/6] Removing firewall rule..." -ForegroundColor Yellow
|
|
33
|
+
Remove-NetFirewallRule -DisplayName "LIGHTMAN Agent WebSocket" -ErrorAction SilentlyContinue
|
|
34
|
+
|
|
35
|
+
# 5. Shell
|
|
36
|
+
Write-Host "[5/6] Restoring shell..." -ForegroundColor Yellow
|
|
37
|
+
$HKLMPath = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon"
|
|
38
|
+
$shell = (Get-ItemProperty -Path $HKLMPath -Name "Shell" -ErrorAction SilentlyContinue).Shell
|
|
39
|
+
if ($shell -and $shell -like "*lightman*") {
|
|
40
|
+
$orig = (Get-ItemProperty -Path $HKLMPath -Name "Shell_Original" -ErrorAction SilentlyContinue).Shell_Original
|
|
41
|
+
Set-ItemProperty -Path $HKLMPath -Name "Shell" -Value $(if ($orig) { $orig } else { "explorer.exe" })
|
|
42
|
+
Remove-ItemProperty -Path "HKCU:\Software\Microsoft\Windows NT\CurrentVersion\Winlogon" -Name "Shell" -ErrorAction SilentlyContinue
|
|
43
|
+
Write-Host " Shell restored"
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
# 6. Files
|
|
47
|
+
Write-Host "[6/6] Removing files..." -ForegroundColor Yellow
|
|
48
|
+
Remove-Item "C:\Program Files\Lightman" -Recurse -Force -ErrorAction SilentlyContinue
|
|
49
|
+
$choice = Read-Host "Remove all data (logs, chrome cache, nssm)? [y/N]"
|
|
50
|
+
if ($choice -eq 'y') { Remove-Item "C:\ProgramData\Lightman" -Recurse -Force -ErrorAction SilentlyContinue }
|
|
51
|
+
|
|
52
|
+
Write-Host ""
|
|
53
|
+
Write-Host "=== Done. Reboot: Restart-Computer ===" -ForegroundColor Green
|
|
54
|
+
Write-Host ""
|