feat: Fleet Forge UEM - device management, agent, remote desktop (VNC), TLS reverse proxy

This commit is contained in:
Pepe44DEV
2026-09-06 22:09:28 +00:00
commit db16ad5cc1
154 changed files with 22920 additions and 0 deletions
+177
View File
@@ -0,0 +1,177 @@
package main
import (
"flag"
"fmt"
"log"
"os"
"github.com/fleetforge/forge-agent/internal/agent"
"github.com/fleetforge/forge-agent/internal/client"
"github.com/fleetforge/forge-agent/internal/config"
"github.com/fleetforge/forge-agent/internal/inventory"
"github.com/fleetforge/forge-agent/internal/winsvc"
)
const AgentVersion = "0.1.0"
func main() {
flag.Usage = func() {
fmt.Fprintf(os.Stderr, "Forge Agent v%s\n", AgentVersion)
fmt.Fprintf(os.Stderr, "Usage:\n")
fmt.Fprintf(os.Stderr, " forge-agent enroll -token <token> -server <url> Enroll this device\n")
fmt.Fprintf(os.Stderr, " forge-agent run [--service] Run the agent\n")
fmt.Fprintf(os.Stderr, " forge-agent install -server <url> -token <token> Install as Windows Service\n")
fmt.Fprintf(os.Stderr, " forge-agent uninstall Uninstall Windows Service\n")
fmt.Fprintf(os.Stderr, " forge-agent version Print version\n")
}
if len(os.Args) < 2 {
flag.Usage()
os.Exit(1)
}
switch os.Args[1] {
case "enroll":
cmdEnroll(os.Args[2:])
case "run":
cmdRun(os.Args[2:])
case "install":
cmdInstall(os.Args[2:])
case "uninstall":
cmdUninstall()
case "version":
fmt.Printf("Forge Agent v%s\n", AgentVersion)
default:
fmt.Fprintf(os.Stderr, "Unknown command: %s\n\n", os.Args[1])
flag.Usage()
os.Exit(1)
}
}
func cmdEnroll(args []string) {
fs := flag.NewFlagSet("enroll", flag.ExitOnError)
token := fs.String("token", "", "Enrollment token")
server := fs.String("server", "http://localhost:3002", "Server URL")
label := fs.String("label", "", "Device label")
fs.Parse(args)
if *token == "" {
log.Fatal("Error: -token is required")
}
performEnrollment(*server, *token, *label)
}
func cmdRun(args []string) {
fs := flag.NewFlagSet("run", flag.ExitOnError)
serviceMode := fs.Bool("service", false, "Run as Windows Service (use with --service flag)")
fs.Parse(args)
cfg, err := config.Load()
if err != nil {
log.Fatalf("Failed to load config: %v\nRun 'forge-agent enroll' or 'forge-agent install' first.", err)
}
if cfg.EnrollmentToken != "" && cfg.DeviceID == "" {
log.Println("First run detected: attempting auto-enrollment...")
if err := performEnrollment(cfg.ServerURL, cfg.EnrollmentToken, cfg.Label); err != nil {
log.Printf("WARNING: Auto-enrollment failed: %v", err)
log.Println("Agent will retry enrollment on next heartbeat cycle.")
} else {
if loaded, loadErr := config.Load(); loadErr == nil {
cfg = loaded
}
log.Println("Auto-enrollment successful.")
}
}
if *serviceMode {
if err := winsvc.RunAsService(); err != nil {
log.Fatalf("Service error: %v", err)
}
return
}
a := agent.New(cfg)
if err := a.Run(); err != nil {
log.Fatalf("Agent error: %v", err)
}
}
func cmdInstall(args []string) {
fs := flag.NewFlagSet("install", flag.ExitOnError)
server := fs.String("server", "", "Server URL")
token := fs.String("token", "", "Enrollment token")
label := fs.String("label", "", "Device label")
fs.Parse(args)
if *server == "" || *token == "" {
log.Fatal("Error: -server and -token are required")
}
if err := winsvc.InstallService(*server, *token, *label); err != nil {
log.Fatalf("Install failed: %v", err)
}
}
func cmdUninstall() {
if err := winsvc.UninstallService(); err != nil {
log.Fatalf("Uninstall failed: %v", err)
}
}
func performEnrollment(serverURL, token, label string) error {
fmt.Println("Collecting system information...")
info, err := inventory.CollectSystemInfo()
if err != nil {
return fmt.Errorf("failed to collect system info: %w", err)
}
fmt.Printf("Hostname: %s\n", info.Hostname)
fmt.Printf("OS: %s %s\n", info.OSName, info.OSVersion)
fmt.Printf("Arch: %s\n", info.Architecture)
fmt.Printf("Server: %s\n", serverURL)
fmt.Println("Enrolling...")
c := client.New(serverURL, "")
resp, err := c.Enroll(client.EnrollRequest{
Token: token,
Hostname: info.Hostname,
Platform: info.Platform,
OSName: info.OSName,
OSVersion: info.OSVersion,
Architecture: info.Architecture,
KernelVersion: info.KernelVersion,
CPUModel: info.CPUModel,
CPUCores: info.CPUCores,
TotalMemoryBytes: info.TotalMemory,
TotalDiskBytes: info.TotalDisk,
IPAddress: info.IPAddress,
AgentVersion: AgentVersion,
})
if err != nil {
return fmt.Errorf("enrollment failed: %w", err)
}
cfg, err := config.Load()
if err != nil {
cfg = &config.Config{}
}
cfg.ServerURL = serverURL
cfg.DeviceID = resp.DeviceID
cfg.Credential = resp.Credential
cfg.Label = label
cfg.EnrollmentToken = ""
if cfg.HeartbeatSec <= 0 {
cfg.HeartbeatSec = 30
}
if err := config.Save(cfg); err != nil {
return fmt.Errorf("failed to save config: %w", err)
}
fmt.Printf("\nEnrollment successful!\n")
fmt.Printf("Device ID: %s\n", resp.DeviceID)
fmt.Printf("Config saved to: %s\n", config.ConfigPath())
return nil
}