Removed backup files and unused legacy scanner function. All code verified as unreferenced.
1071 lines
36 KiB
Go
1071 lines
36 KiB
Go
package handlers
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/Fimeg/RedFlag/aggregator-server/internal/config"
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
// DownloadHandler handles agent binary downloads
|
|
type DownloadHandler struct {
|
|
agentDir string
|
|
config *config.Config
|
|
}
|
|
|
|
func NewDownloadHandler(agentDir string, cfg *config.Config) *DownloadHandler {
|
|
return &DownloadHandler{
|
|
agentDir: agentDir,
|
|
config: cfg,
|
|
}
|
|
}
|
|
|
|
// getServerURL determines the server URL with proper protocol detection
|
|
func (h *DownloadHandler) getServerURL(c *gin.Context) string {
|
|
// Priority 1: Use configured public URL if set
|
|
if h.config.Server.PublicURL != "" {
|
|
return h.config.Server.PublicURL
|
|
}
|
|
|
|
// Priority 2: Construct API server URL from configuration
|
|
scheme := "http"
|
|
host := h.config.Server.Host
|
|
port := h.config.Server.Port
|
|
|
|
// Use HTTPS if TLS is enabled in config
|
|
if h.config.Server.TLS.Enabled {
|
|
scheme = "https"
|
|
}
|
|
|
|
// For default host (0.0.0.0), use localhost for client connections
|
|
if host == "0.0.0.0" {
|
|
host = "localhost"
|
|
}
|
|
|
|
// Only include port if it's not the default for the protocol
|
|
if (scheme == "http" && port != 80) || (scheme == "https" && port != 443) {
|
|
return fmt.Sprintf("%s://%s:%d", scheme, host, port)
|
|
}
|
|
|
|
return fmt.Sprintf("%s://%s", scheme, host)
|
|
}
|
|
|
|
// DownloadAgent serves agent binaries for different platforms
|
|
func (h *DownloadHandler) DownloadAgent(c *gin.Context) {
|
|
platform := c.Param("platform")
|
|
version := c.Query("version") // Optional version parameter for signed binaries
|
|
|
|
// Validate platform to prevent directory traversal
|
|
validPlatforms := map[string]bool{
|
|
"linux-amd64": true,
|
|
"linux-arm64": true,
|
|
"windows-amd64": true,
|
|
"windows-arm64": true,
|
|
}
|
|
|
|
if !validPlatforms[platform] {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid or unsupported platform"})
|
|
return
|
|
}
|
|
|
|
// Build filename based on platform
|
|
filename := "redflag-agent"
|
|
if strings.HasPrefix(platform, "windows") {
|
|
filename += ".exe"
|
|
}
|
|
|
|
var agentPath string
|
|
|
|
// Try to serve signed package first if version is specified
|
|
// TODO: Implement database lookup for signed packages
|
|
// if version != "" {
|
|
// signedPackage, err := h.packageQueries.GetSignedPackage(version, platform)
|
|
// if err == nil && fileExists(signedPackage.BinaryPath) {
|
|
// agentPath = signedPackage.BinaryPath
|
|
// }
|
|
// }
|
|
|
|
// Fallback to unsigned generic binary
|
|
if agentPath == "" {
|
|
agentPath = filepath.Join(h.agentDir, "binaries", platform, filename)
|
|
}
|
|
|
|
// Check if file exists
|
|
if _, err := os.Stat(agentPath); os.IsNotExist(err) {
|
|
c.JSON(http.StatusNotFound, gin.H{
|
|
"error": "Agent binary not found",
|
|
"platform": platform,
|
|
"version": version,
|
|
})
|
|
return
|
|
}
|
|
|
|
// Handle both GET and HEAD requests
|
|
if c.Request.Method == "HEAD" {
|
|
c.Status(http.StatusOK)
|
|
return
|
|
}
|
|
|
|
c.File(agentPath)
|
|
}
|
|
|
|
// DownloadUpdatePackage serves signed agent update packages
|
|
func (h *DownloadHandler) DownloadUpdatePackage(c *gin.Context) {
|
|
packageID := c.Param("package_id")
|
|
|
|
// Validate package ID format (UUID)
|
|
if len(packageID) != 36 {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid package ID format"})
|
|
return
|
|
}
|
|
|
|
// TODO: Implement actual package serving from database/filesystem
|
|
// For now, return a placeholder response
|
|
c.JSON(http.StatusNotImplemented, gin.H{
|
|
"error": "Update package download not yet implemented",
|
|
"package_id": packageID,
|
|
"message": "This will serve the signed update package file",
|
|
})
|
|
}
|
|
|
|
// InstallScript serves the installation script
|
|
func (h *DownloadHandler) InstallScript(c *gin.Context) {
|
|
platform := c.Param("platform")
|
|
|
|
// Validate platform
|
|
validPlatforms := map[string]bool{
|
|
"linux": true,
|
|
"windows": true,
|
|
}
|
|
|
|
if !validPlatforms[platform] {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid or unsupported platform"})
|
|
return
|
|
}
|
|
|
|
serverURL := h.getServerURL(c)
|
|
scriptContent := h.generateInstallScript(platform, serverURL)
|
|
c.Header("Content-Type", "text/plain")
|
|
c.String(http.StatusOK, scriptContent)
|
|
}
|
|
|
|
func (h *DownloadHandler) generateInstallScript(platform, baseURL string) string {
|
|
switch platform {
|
|
case "linux":
|
|
return h.generateLinuxScript(baseURL)
|
|
case "windows":
|
|
return h.generateWindowsScript(baseURL)
|
|
default:
|
|
return "# Unsupported platform: " + platform
|
|
}
|
|
}
|
|
|
|
func (h *DownloadHandler) generateLinuxScript(baseURL string) string {
|
|
return fmt.Sprintf(`#!/bin/bash
|
|
set -e
|
|
|
|
# RedFlag Agent Smart Installer
|
|
# Uses the sophisticated build orchestrator and migration system
|
|
|
|
REDFLAG_SERVER="%s"
|
|
AGENT_USER="redflag-agent"
|
|
AGENT_HOME="/var/lib/redflag-agent"
|
|
AGENT_BINARY="/usr/local/bin/redflag-agent"
|
|
SUDOERS_FILE="/etc/sudoers.d/redflag-agent"
|
|
SERVICE_FILE="/etc/systemd/system/redflag-agent.service"
|
|
CONFIG_DIR="/etc/redflag"
|
|
STATE_DIR="/var/lib/redflag"
|
|
OLD_CONFIG_DIR="/etc/aggregator"
|
|
OLD_STATE_DIR="/var/lib/aggregator"
|
|
|
|
# Colors for output
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m' # No Color
|
|
|
|
echo -e "${BLUE}=== RedFlag Agent Smart Installer ===${NC}"
|
|
echo ""
|
|
|
|
# Check if running as root
|
|
if [ "$EUID" -ne 0 ]; then
|
|
echo -e "${RED}ERROR: This script must be run as root (use sudo)${NC}"
|
|
exit 1
|
|
fi
|
|
|
|
# Get registration token from first argument
|
|
REGISTRATION_TOKEN="$1"
|
|
if [ -z "$REGISTRATION_TOKEN" ]; then
|
|
echo -e "${RED}ERROR: Registration token is required${NC}"
|
|
echo -e "${YELLOW}Usage: curl -sL ${REDFLAG_SERVER}/api/v1/install/linux | sudo bash -s -- YOUR_REGISTRATION_TOKEN${NC}"
|
|
exit 1
|
|
fi
|
|
|
|
echo -e "${BLUE}Registration token: ${GREEN}${REGISTRATION_TOKEN:0:8}...${NC}"
|
|
echo ""
|
|
|
|
# Detect architecture
|
|
ARCH=$(uname -m)
|
|
case "$ARCH" in
|
|
x86_64)
|
|
DOWNLOAD_ARCH="amd64"
|
|
;;
|
|
aarch64|arm64)
|
|
DOWNLOAD_ARCH="arm64"
|
|
;;
|
|
*)
|
|
echo -e "${RED}ERROR: Unsupported architecture: $ARCH${NC}"
|
|
echo -e "${YELLOW}Supported: x86_64 (amd64), aarch64 (arm64)${NC}"
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
echo -e "${BLUE}Detected architecture: $ARCH (using linux-$DOWNLOAD_ARCH)${NC}"
|
|
echo ""
|
|
|
|
# Function to detect existing installation using our sophisticated system
|
|
detect_existing_agent() {
|
|
echo -e "${YELLOW}Detecting existing RedFlag agent installation...${NC}"
|
|
|
|
# DEBUGGING: Start comprehensive debugging trace
|
|
echo "=== DEBUGGING: detect_existing_agent() ==="
|
|
echo "DEBUG: Starting detection process..."
|
|
|
|
# Check for config files in both new and old locations
|
|
echo "DEBUG: Checking for config files in all locations..."
|
|
|
|
# Check new location first
|
|
echo "DEBUG: Checking new config file: /etc/redflag/config.json"
|
|
if [ -f "/etc/redflag/config.json" ]; then
|
|
echo "DEBUG: New config file exists!"
|
|
CONFIG_FILE="/etc/redflag/config.json"
|
|
CONFIG_LOCATION="new"
|
|
else
|
|
echo "DEBUG: New config file does not exist, checking legacy location..."
|
|
|
|
# Check old location
|
|
if [ -f "/etc/aggregator/config.json" ]; then
|
|
echo "DEBUG: Found legacy config file: /etc/aggregator/config.json"
|
|
CONFIG_FILE="/etc/aggregator/config.json"
|
|
CONFIG_LOCATION="old"
|
|
else
|
|
echo "DEBUG: No config file found in either location"
|
|
CONFIG_FILE=""
|
|
CONFIG_LOCATION="none"
|
|
fi
|
|
fi
|
|
|
|
# If we found a config file, try to extract agent_id (using single reliable method)
|
|
if [ -n "$CONFIG_FILE" ]; then
|
|
echo "DEBUG: Processing config file: $CONFIG_FILE (location: $CONFIG_LOCATION)"
|
|
|
|
# Check file permissions
|
|
echo "DEBUG: File permissions:"
|
|
ls -la "$CONFIG_FILE"
|
|
|
|
# Check file ownership
|
|
echo "DEBUG: File ownership:"
|
|
stat -c "%U:%G" "$CONFIG_FILE"
|
|
|
|
# Try reading file content
|
|
echo "DEBUG: Attempting to read file content..."
|
|
echo "DEBUG: Method 1 - Direct cat:"
|
|
if sudo cat "$CONFIG_FILE" 2>/dev/null; then
|
|
echo "DEBUG: Direct cat successful"
|
|
else
|
|
echo "DEBUG: Direct cat failed"
|
|
fi
|
|
|
|
# Extract agent_id using single reliable method
|
|
echo "DEBUG: Extracting agent_id with grep:"
|
|
agent_id=$(grep -o '"agent_id": *"[^"]*"' "$CONFIG_FILE" 2>/dev/null | cut -d'"' -f4)
|
|
echo "DEBUG: Extracted agent_id: '$agent_id'"
|
|
|
|
# Check if agent_id looks valid (UUID format)
|
|
if [ -n "$agent_id" ]; then
|
|
if echo "$agent_id" | grep -qE '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$'; then
|
|
echo "DEBUG: Agent ID appears to be valid UUID format"
|
|
else
|
|
echo "DEBUG: Agent ID does not appear to be valid UUID format"
|
|
fi
|
|
else
|
|
echo "DEBUG: Agent ID is empty or null"
|
|
fi
|
|
|
|
# Note if migration is needed
|
|
if [ "$CONFIG_LOCATION" = "old" ]; then
|
|
echo "DEBUG: *** MIGRATION REQUIRED - Config found in legacy location ***"
|
|
fi
|
|
else
|
|
echo "DEBUG: No config files found, checking directories..."
|
|
|
|
# Check if directories exist for debugging
|
|
for dir_path in "/etc/redflag" "/etc/aggregator" "/var/lib/redflag" "/var/lib/aggregator"; do
|
|
if [ -d "$dir_path" ]; then
|
|
echo "DEBUG: Found directory: $dir_path"
|
|
echo "DEBUG: Directory contents:"
|
|
ls -la "$dir_path/" 2>/dev/null || echo "DEBUG: Cannot list contents (permissions?)"
|
|
else
|
|
echo "DEBUG: Directory does not exist: $dir_path"
|
|
fi
|
|
done
|
|
fi
|
|
|
|
# Check if systemd service exists
|
|
echo "DEBUG: Checking systemd service..."
|
|
if systemctl list-unit-files | grep -q "redflag-agent.service"; then
|
|
echo "DEBUG: Systemd service file exists"
|
|
|
|
# Check service status
|
|
echo "DEBUG: Service status:"
|
|
systemctl status redflag-agent --no-pager -l || echo "DEBUG: Could not get service status"
|
|
|
|
# Check if service is enabled
|
|
if systemctl is-enabled --quiet redflag-agent 2>/dev/null; then
|
|
echo "DEBUG: Service is enabled"
|
|
else
|
|
echo "DEBUG: Service is not enabled"
|
|
fi
|
|
|
|
# Check if service is active
|
|
if systemctl is-active --quiet redflag-agent 2>/dev/null; then
|
|
echo "DEBUG: Service is active"
|
|
else
|
|
echo "DEBUG: Service is not active"
|
|
fi
|
|
else
|
|
echo "DEBUG: Systemd service file does not exist"
|
|
fi
|
|
|
|
# Check if binary exists
|
|
echo "DEBUG: Checking for agent binary..."
|
|
for binary_path in "/usr/local/bin/redflag-agent" "/usr/bin/redflag-agent" "/opt/redflag-agent/bin/redflag-agent"; do
|
|
if [ -f "$binary_path" ]; then
|
|
echo "DEBUG: Found agent binary at: $binary_path"
|
|
echo "DEBUG: Binary permissions:"
|
|
ls -la "$binary_path"
|
|
break
|
|
fi
|
|
done
|
|
|
|
# Test server connectivity
|
|
echo "DEBUG: Testing server connectivity..."
|
|
echo "DEBUG: Server URL: ${REDFLAG_SERVER}"
|
|
|
|
# Test basic connectivity
|
|
echo "DEBUG: Testing basic HTTP connectivity..."
|
|
if curl -s --connect-timeout 5 "${REDFLAG_SERVER}/api/v1/health" >/dev/null 2>&1; then
|
|
echo "DEBUG: Server connectivity test successful"
|
|
else
|
|
echo "DEBUG: Server connectivity test failed"
|
|
echo "DEBUG: curl exit code: $?"
|
|
fi
|
|
|
|
# Call detection API with debugging
|
|
echo "DEBUG: Calling detection API..."
|
|
echo "DEBUG: URL: ${REDFLAG_SERVER}/api/v1/build/detect"
|
|
echo "DEBUG: Payload: {\"agent_id\": \"${agent_id}\"}"
|
|
|
|
DETECTION_RESPONSE=$(curl -s -X POST "${REDFLAG_SERVER}/api/v1/build/detect" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"agent_id": "'"$agent_id"'"}' 2>/dev/null)
|
|
|
|
echo "DEBUG: curl exit code: $?"
|
|
echo "DEBUG: Detection response: '$DETECTION_RESPONSE'"
|
|
|
|
if [ $? -eq 0 ] && [ -n "$DETECTION_RESPONSE" ]; then
|
|
echo "DEBUG: Successfully received detection response"
|
|
|
|
# Parse JSON response with debugging
|
|
echo "DEBUG: Parsing detection response..."
|
|
|
|
HAS_AGENT=$(echo "$DETECTION_RESPONSE" | grep -o '"has_existing_agent":[^,]*' | cut -d':' -f2 | tr -d ' ')
|
|
echo "DEBUG: Extracted has_existing_agent: '$HAS_AGENT'"
|
|
|
|
AGENT_ID=$(echo "$DETECTION_RESPONSE" | grep -o '"agent_id":"[^"]*"' | cut -d'"' -f4)
|
|
echo "DEBUG: Extracted agent_id from response: '$AGENT_ID'"
|
|
|
|
REQUIRES_MIGRATION=$(echo "$DETECTION_RESPONSE" | grep -o '"requires_migration":[^,]*' | cut -d':' -f2 | tr -d ' ')
|
|
echo "DEBUG: Extracted requires_migration: '$REQUIRES_MIGRATION'"
|
|
|
|
CURRENT_VERSION=$(echo "$DETECTION_RESPONSE" | grep -o '"current_version":"[^"]*"' | cut -d'"' -f4)
|
|
echo "DEBUG: Extracted current_version: '$CURRENT_VERSION'"
|
|
|
|
# Check conditions for successful detection
|
|
if [ "$HAS_AGENT" = "true" ] && [ -n "$AGENT_ID" ]; then
|
|
echo "DEBUG: Detection SUCCESS - existing agent found"
|
|
echo -e "${GREEN}✓ Existing agent detected: ${AGENT_ID}${NC}"
|
|
echo -e "${BLUE} Current version: ${CURRENT_VERSION}${NC}"
|
|
if [ "$REQUIRES_MIGRATION" = "true" ]; then
|
|
echo -e "${YELLOW}⚠ Migration will be performed during upgrade${NC}"
|
|
fi
|
|
echo "=== END DEBUGGING: detect_existing_agent() ==="
|
|
return 0 # Upgrade path
|
|
else
|
|
echo "DEBUG: Detection indicates no existing agent"
|
|
echo "DEBUG: has_existing_agent: '$HAS_AGENT'"
|
|
echo "DEBUG: agent_id from response: '$AGENT_ID'"
|
|
fi
|
|
else
|
|
echo "DEBUG: Detection API call failed or returned empty response"
|
|
echo "DEBUG: curl exit code: $?"
|
|
echo "DEBUG: response length: ${#DETECTION_RESPONSE}"
|
|
fi
|
|
|
|
echo "DEBUG: Returning new installation path"
|
|
echo -e "${GREEN}✓ No existing agent detected - performing new installation${NC}"
|
|
echo "=== END DEBUGGING: detect_existing_agent() ==="
|
|
return 1 # New installation path
|
|
}
|
|
|
|
# Function to perform migration from old paths
|
|
perform_migration() {
|
|
echo ""
|
|
echo -e "${BLUE}=== Migration Required ===${NC}"
|
|
|
|
# Create backup directories with timestamp
|
|
BACKUP_TIMESTAMP=$(date +%%Y%%m%%d_%%H%%M%%S)
|
|
OLD_CONFIG_BACKUP="${OLD_CONFIG_DIR}.backup.${BACKUP_TIMESTAMP}"
|
|
OLD_STATE_BACKUP="${OLD_STATE_DIR}.backup.${BACKUP_TIMESTAMP}"
|
|
|
|
# Backup old directories if they exist
|
|
if [ -d "$OLD_CONFIG_DIR" ]; then
|
|
echo -e "${YELLOW}Backing up old configuration: ${OLD_CONFIG_DIR} -> ${OLD_CONFIG_BACKUP}${NC}"
|
|
mv "$OLD_CONFIG_DIR" "$OLD_CONFIG_BACKUP"
|
|
fi
|
|
|
|
if [ -d "$OLD_STATE_DIR" ]; then
|
|
echo -e "${YELLOW}Backing up old state: ${OLD_STATE_DIR} -> ${OLD_STATE_BACKUP}${NC}"
|
|
mv "$OLD_STATE_DIR" "$OLD_STATE_BACKUP"
|
|
fi
|
|
|
|
# Migrate configuration data if backup exists
|
|
if [ -d "$OLD_CONFIG_BACKUP" ]; then
|
|
echo -e "${YELLOW}Migrating configuration data to new location...${NC}"
|
|
mkdir -p "$CONFIG_DIR"
|
|
|
|
# Copy config files, preserving permissions when possible
|
|
cp -r "$OLD_CONFIG_BACKUP"/* "$CONFIG_DIR/" 2>/dev/null || true
|
|
|
|
# Set proper ownership for new location
|
|
chown -R "$AGENT_USER:$AGENT_USER" "$CONFIG_DIR" 2>/dev/null || true
|
|
chmod 755 "$CONFIG_DIR" 2>/dev/null || true
|
|
|
|
# Ensure config file has correct permissions
|
|
if [ -f "$CONFIG_DIR/config.json" ]; then
|
|
chmod 600 "$CONFIG_DIR/config.json" 2>/dev/null || true
|
|
chown "$AGENT_USER:$AGENT_USER" "$CONFIG_DIR/config.json" 2>/dev/null || true
|
|
fi
|
|
fi
|
|
|
|
# Migrate state data if backup exists
|
|
if [ -d "$OLD_STATE_BACKUP" ]; then
|
|
echo -e "${YELLOW}Migrating state data to new location...${NC}"
|
|
mkdir -p "$STATE_DIR"
|
|
cp -r "$OLD_STATE_BACKUP"/* "$STATE_DIR/" 2>/dev/null || true
|
|
chown -R "$AGENT_USER:$AGENT_USER" "$STATE_DIR" 2>/dev/null || true
|
|
fi
|
|
|
|
# Migrate secrets to Docker secrets if available
|
|
migrate_secrets_to_docker
|
|
|
|
echo -e "${GREEN}✓ Migration completed${NC}"
|
|
}
|
|
|
|
# Function to migrate secrets from filesystem to Docker secrets
|
|
migrate_secrets_to_docker() {
|
|
echo -e "${YELLOW}Checking for secrets migration...${NC}"
|
|
|
|
# Look for potential secret files in old locations
|
|
local secrets_found=false
|
|
|
|
# Check for common secret file patterns
|
|
for secret_pattern in "agent.key" "private_key" "secrets.json" ".env" "credentials.json"; do
|
|
if [ -f "$OLD_CONFIG_BACKUP/$secret_pattern" ] || [ -f "$OLD_STATE_BACKUP/$secret_pattern" ]; then
|
|
echo -e "${YELLOW}Found potential secret file: $secret_pattern${NC}"
|
|
secrets_found=true
|
|
fi
|
|
done
|
|
|
|
# Check for agent private keys or certificates
|
|
for key_path in "$OLD_CONFIG_BACKUP" "$OLD_STATE_BACKUP"; do
|
|
if [ -d "$key_path" ]; then
|
|
# Look for key files
|
|
find "$key_path" -type f \( -name "*.key" -o -name "*.pem" -o -name "*.crt" -o -name "id_*" \) 2>/dev/null | while read -r key_file; do
|
|
echo -e "${YELLOW}Found key file: $(basename "$key_file")${NC}"
|
|
secrets_found=true
|
|
done
|
|
fi
|
|
done
|
|
|
|
if [ "$secrets_found" = true ]; then
|
|
echo -e "${BLUE}Secrets migration available${NC}"
|
|
echo -e "${YELLOW}Note: Secrets will be migrated to Docker secrets when the agent starts${NC}"
|
|
echo -e "${YELLOW}The agent will automatically detect and migrate filesystem secrets to Docker storage${NC}"
|
|
|
|
# Create a migration marker for the agent to find
|
|
mkdir -p "$CONFIG_DIR"
|
|
echo '{"secrets_migration_required": true, "migration_timestamp": "'$(date -Iseconds)'"}' > "$CONFIG_DIR/secrets_migration.json"
|
|
chown "$AGENT_USER:$AGENT_USER" "$CONFIG_DIR/secrets_migration.json" 2>/dev/null || true
|
|
chmod 600 "$CONFIG_DIR/secrets_migration.json" 2>/dev/null || true
|
|
else
|
|
echo -e "${GREEN}No secrets requiring migration found${NC}"
|
|
fi
|
|
}
|
|
|
|
# Function to perform new installation using build orchestrator
|
|
perform_new_installation() {
|
|
echo ""
|
|
echo -e "${BLUE}=== New Agent Installation ===${NC}"
|
|
|
|
# Call build/new endpoint to get proper configuration and upgrade logic
|
|
echo -e "${YELLOW}Requesting agent build configuration...${NC}"
|
|
BUILD_RESPONSE=$(curl -s -X POST "${REDFLAG_SERVER}/api/v1/build/new" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"server_url": "'"${REDFLAG_SERVER}"'",
|
|
"environment": "production",
|
|
"agent_type": "linux-server",
|
|
"organization": "default",
|
|
"registration_token": "'"${REGISTRATION_TOKEN}"'"
|
|
}' 2>/dev/null)
|
|
|
|
if [ $? -ne 0 ] || [ -z "$BUILD_RESPONSE" ]; then
|
|
echo -e "${RED}✗ Failed to request agent build configuration${NC}"
|
|
exit 1
|
|
fi
|
|
|
|
# Extract agent ID from build response
|
|
AGENT_ID=$(echo "$BUILD_RESPONSE" | grep -o '"agent_id":"[^"]*"' | cut -d'"' -f4)
|
|
|
|
if [ -z "$AGENT_ID" ]; then
|
|
echo -e "${RED}✗ Invalid response from server${NC}"
|
|
exit 1
|
|
fi
|
|
|
|
echo -e "${GREEN}✓ Agent configuration created: ${AGENT_ID}${NC}"
|
|
|
|
# Download native agent binary
|
|
echo -e "${YELLOW}Downloading native signed agent binary...${NC}"
|
|
if curl -sL "${REDFLAG_SERVER}/api/v1/downloads/linux-${DOWNLOAD_ARCH}" -o "$AGENT_BINARY"; then
|
|
chmod 755 "$AGENT_BINARY"
|
|
chown root:root "$AGENT_BINARY"
|
|
echo -e "${GREEN}✓ Native signed agent binary installed${NC}"
|
|
else
|
|
echo -e "${RED}✗ Failed to download agent binary${NC}"
|
|
exit 1
|
|
fi
|
|
|
|
deploy_agent "$AGENT_ID" "$BUILD_RESPONSE" "new"
|
|
}
|
|
|
|
# Function to perform upgrade using build orchestrator
|
|
perform_upgrade() {
|
|
echo ""
|
|
echo -e "${BLUE}=== Agent Upgrade ===${NC}"
|
|
|
|
# Extract agent ID from detection
|
|
AGENT_ID=$(echo "$DETECTION_RESPONSE" | grep -o '"agent_id":"[^"]*"' | cut -d'"' -f4)
|
|
|
|
if [ -z "$AGENT_ID" ]; then
|
|
echo -e "${RED}✗ Could not extract agent ID for upgrade${NC}"
|
|
exit 1
|
|
fi
|
|
|
|
echo -e "${YELLOW}Requesting upgrade configuration for agent: ${AGENT_ID}${NC}"
|
|
|
|
# Call build/upgrade endpoint to get upgrade configuration
|
|
BUILD_RESPONSE=$(curl -s -X POST "${REDFLAG_SERVER}/api/v1/build/upgrade/${AGENT_ID}" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"server_url": "'"${REDFLAG_SERVER}"'",
|
|
"environment": "production",
|
|
"agent_type": "linux-server",
|
|
"preserve_existing": true
|
|
}' 2>/dev/null)
|
|
|
|
if [ $? -ne 0 ] || [ -z "$BUILD_RESPONSE" ]; then
|
|
echo -e "${RED}✗ Failed to request agent upgrade configuration${NC}"
|
|
exit 1
|
|
fi
|
|
|
|
echo -e "${GREEN}✓ Upgrade configuration prepared for agent: ${AGENT_ID}${NC}"
|
|
|
|
# STOP SERVICE BEFORE DOWNLOADING BINARY
|
|
echo -e "${YELLOW}Stopping agent service to allow binary replacement...${NC}"
|
|
if systemctl is-active --quiet redflag-agent 2>/dev/null; then
|
|
systemctl stop redflag-agent
|
|
# Wait for service to fully stop
|
|
local retry_count=0
|
|
while [ $retry_count -lt 10 ]; do
|
|
if ! systemctl is-active --quiet redflag-agent 2>/dev/null; then
|
|
echo -e "${GREEN}✓ Service stopped successfully${NC}"
|
|
break
|
|
fi
|
|
echo -e "${YELLOW}Waiting for service to stop... (attempt $((retry_count + 1))/10)${NC}"
|
|
sleep 1
|
|
retry_count=$((retry_count + 1))
|
|
done
|
|
|
|
if systemctl is-active --quiet redflag-agent 2>/dev/null; then
|
|
echo -e "${RED}✗ Failed to stop service, forcing...${NC}"
|
|
systemctl kill redflag-agent
|
|
sleep 2
|
|
fi
|
|
else
|
|
echo -e "${BLUE}✓ Service is already stopped${NC}"
|
|
fi
|
|
|
|
# Download updated native agent binary to temporary location first
|
|
echo -e "${YELLOW}Downloading updated native signed agent binary...${NC}"
|
|
TEMP_BINARY="${AGENT_BINARY}.new"
|
|
|
|
# Remove any existing temp binary
|
|
rm -f "$TEMP_BINARY"
|
|
|
|
if curl -sL "${REDFLAG_SERVER}/api/v1/downloads/linux-${DOWNLOAD_ARCH}" -o "$TEMP_BINARY"; then
|
|
# Verify the download
|
|
if [ -f "$TEMP_BINARY" ] && [ -s "$TEMP_BINARY" ]; then
|
|
chmod 755 "$TEMP_BINARY"
|
|
chown root:root "$TEMP_BINARY"
|
|
|
|
# Atomic move to replace binary
|
|
mv "$TEMP_BINARY" "$AGENT_BINARY"
|
|
|
|
# Verify the replacement
|
|
if [ -f "$AGENT_BINARY" ] && [ -s "$AGENT_BINARY" ]; then
|
|
echo -e "${GREEN}✓ Native signed agent binary updated successfully${NC}"
|
|
else
|
|
echo -e "${RED}✗ Binary replacement verification failed${NC}"
|
|
exit 1
|
|
fi
|
|
else
|
|
echo -e "${RED}✗ Downloaded binary is empty or missing${NC}"
|
|
rm -f "$TEMP_BINARY"
|
|
exit 1
|
|
fi
|
|
else
|
|
echo -e "${RED}✗ Failed to download agent binary${NC}"
|
|
rm -f "$TEMP_BINARY"
|
|
exit 1
|
|
fi
|
|
|
|
deploy_agent "$AGENT_ID" "$BUILD_RESPONSE" "upgrade"
|
|
}
|
|
|
|
# Function to deploy native agent with systemd
|
|
deploy_agent() {
|
|
local AGENT_ID="$1"
|
|
local BUILD_RESPONSE="$2"
|
|
local INSTALL_TYPE="$3"
|
|
|
|
echo ""
|
|
echo -e "${BLUE}=== Agent Deployment ===${NC}"
|
|
|
|
# Create agent user if it doesn't exist
|
|
if ! id "$AGENT_USER" &>/dev/null; then
|
|
echo -e "${YELLOW}Creating agent user: $AGENT_USER${NC}"
|
|
useradd -r -s /bin/false -d "$AGENT_HOME" -m "$AGENT_USER"
|
|
fi
|
|
|
|
# Note: Service is already stopped for upgrades, but check for new installations
|
|
if [ "$INSTALL_TYPE" = "new" ] && systemctl is-active --quiet redflag-agent 2>/dev/null; then
|
|
echo -e "${YELLOW}Stopping existing agent service...${NC}"
|
|
systemctl stop redflag-agent
|
|
sleep 2
|
|
fi
|
|
|
|
# Save build response for potential recovery and debugging
|
|
echo "$BUILD_RESPONSE" > "${CONFIG_DIR}/build_response.json"
|
|
chown "$AGENT_USER:$AGENT_USER" "${CONFIG_DIR}/build_response.json"
|
|
chmod 600 "${CONFIG_DIR}/build_response.json"
|
|
|
|
# Create directories
|
|
mkdir -p "$CONFIG_DIR" "$STATE_DIR"
|
|
|
|
# Install sudoers configuration if not exists
|
|
if [ ! -f "$SUDOERS_FILE" ]; then
|
|
echo -e "${YELLOW}Installing sudoers configuration...${NC}"
|
|
cat > "$SUDOERS_FILE" << 'SUDOERS_EOF'
|
|
# RedFlag Agent minimal sudo permissions
|
|
# Generated automatically during RedFlag agent installation
|
|
|
|
# APT package management commands (Debian/Ubuntu)
|
|
redflag-agent ALL=(root) NOPASSWD: /usr/bin/apt-get update
|
|
redflag-agent ALL=(root) NOPASSWD: /usr/bin/apt-get install -y *
|
|
redflag-agent ALL=(root) NOPASSWD: /usr/bin/apt-get upgrade -y *
|
|
redflag-agent ALL=(root) NOPASSWD: /usr/bin/apt-get install --dry-run --yes *
|
|
|
|
# DNF package management commands (RHEL/Fedora/Rocky/Alma)
|
|
redflag-agent ALL=(root) NOPASSWD: /usr/bin/dnf makecache
|
|
redflag-agent ALL=(root) NOPASSWD: /usr/bin/dnf install -y *
|
|
redflag-agent ALL=(root) NOPASSWD: /usr/bin/dnf upgrade -y *
|
|
redflag-agent ALL=(root) NOPASSWD: /usr/bin/dnf install --assumeno --downloadonly *
|
|
|
|
# Docker operations
|
|
redflag-agent ALL=(root) NOPASSWD: /usr/bin/docker pull *
|
|
redflag-agent ALL=(root) NOPASSWD: /usr/bin/docker image inspect *
|
|
redflag-agent ALL=(root) NOPASSWD: /usr/bin/docker manifest inspect *
|
|
|
|
# Directory operations for RedFlag
|
|
redflag-agent ALL=(root) NOPASSWD: /bin/mkdir -p /etc/redflag
|
|
redflag-agent ALL=(root) NOPASSWD: /bin/mkdir -p /var/lib/redflag
|
|
redflag-agent ALL=(root) NOPASSWD: /bin/chown redflag-agent:redflag-agent /etc/redflag
|
|
redflag-agent ALL=(root) NOPASSWD: /bin/chown redflag-agent:redflag-agent /var/lib/redflag
|
|
redflag-agent ALL=(root) NOPASSWD: /bin/chmod 755 /etc/redflag
|
|
redflag-agent ALL=(root) NOPASSWD: /bin/chmod 755 /var/lib/redflag
|
|
|
|
# Migration operations (for existing installations)
|
|
redflag-agent ALL=(root) NOPASSWD: /bin/mv /etc/aggregator /etc/redflag.backup.*
|
|
redflag-agent ALL=(root) NOPASSWD: /bin/mv /var/lib/aggregator/* /var/lib/redflag/
|
|
redflag-agent ALL=(root) NOPASSWD: /bin/rmdir /var/lib/aggregator 2>/dev/null || true
|
|
redflag-agent ALL=(root) NOPASSWD: /bin/rmdir /etc/aggregator 2>/dev/null || true
|
|
SUDOERS_EOF
|
|
|
|
chmod 440 "$SUDOERS_FILE"
|
|
|
|
# Validate sudoers file
|
|
if visudo -c -f "$SUDOERS_FILE" &>/dev/null; then
|
|
echo -e "${GREEN}✓ Sudoers configuration installed${NC}"
|
|
else
|
|
echo -e "${RED}✗ Invalid sudoers configuration${NC}"
|
|
rm -f "$SUDOERS_FILE"
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
# Install/update systemd service
|
|
echo -e "${YELLOW}Installing systemd service...${NC}"
|
|
cat > "$SERVICE_FILE" << EOF
|
|
[Unit]
|
|
Description=RedFlag Update Agent
|
|
After=network.target
|
|
Documentation=https://github.com/Fimeg/RedFlag
|
|
|
|
[Service]
|
|
Type=simple
|
|
User=$AGENT_USER
|
|
Group=$AGENT_USER
|
|
WorkingDirectory=$AGENT_HOME
|
|
ExecStart=$AGENT_BINARY
|
|
Restart=always
|
|
RestartSec=30
|
|
|
|
# Security hardening
|
|
ProtectSystem=strict
|
|
ProtectHome=true
|
|
ReadWritePaths=$AGENT_HOME /var/log $CONFIG_DIR $STATE_DIR
|
|
PrivateTmp=true
|
|
|
|
# Logging
|
|
StandardOutput=journal
|
|
StandardError=journal
|
|
SyslogIdentifier=redflag-agent
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
EOF
|
|
|
|
chmod 644 "$SERVICE_FILE"
|
|
systemctl daemon-reload
|
|
|
|
# Set directory permissions
|
|
chown "$AGENT_USER:$AGENT_USER" "$CONFIG_DIR" "$STATE_DIR"
|
|
chmod 755 "$CONFIG_DIR" "$STATE_DIR"
|
|
|
|
# Start and enable service
|
|
systemctl enable redflag-agent
|
|
systemctl restart redflag-agent
|
|
|
|
# Wait for service to start
|
|
sleep 3
|
|
|
|
# Verify deployment
|
|
if systemctl is-active --quiet redflag-agent; then
|
|
echo -e "${GREEN}✓ Native agent deployed successfully${NC}"
|
|
|
|
# Check logs briefly
|
|
echo -e "${BLUE}Agent status:${NC}"
|
|
systemctl status redflag-agent --no-pager -l | head -n 10
|
|
|
|
echo ""
|
|
echo -e "${GREEN}=== Installation Complete ===${NC}"
|
|
echo -e "${BLUE}Agent Details:${NC}"
|
|
echo -e " • Agent ID: ${AGENT_ID}"
|
|
echo -e " • Binary: ${AGENT_BINARY}"
|
|
echo -e " • Service: redflag-agent"
|
|
echo -e " • Config: ${CONFIG_DIR}/config.json"
|
|
echo -e " • Build Response: ${CONFIG_DIR}/build_response.json"
|
|
if [ "$INSTALL_TYPE" = "upgrade" ]; then
|
|
echo -e " • ${GREEN}Seat preserved: No additional license consumed${NC}"
|
|
else
|
|
echo -e " • ${GREEN}Seat allocated: One license consumed${NC}"
|
|
fi
|
|
echo ""
|
|
echo -e "${BLUE}Management Commands:${NC}"
|
|
echo -e " • Status: systemctl status redflag-agent"
|
|
echo -e " • Logs: journalctl -u redflag-agent -f"
|
|
echo -e " • Restart: systemctl restart redflag-agent"
|
|
echo -e " • Update: Re-run this installer script"
|
|
echo ""
|
|
else
|
|
echo -e "${RED}✗ Failed to start agent service${NC}"
|
|
echo -e "${YELLOW}Troubleshooting:${NC}"
|
|
echo -e " • Check logs: journalctl -u redflag-agent -n 50"
|
|
echo -e " • Check binary: ls -la ${AGENT_BINARY}"
|
|
echo -e " • Check service: systemctl status redflag-agent"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# Main execution
|
|
echo -e "${BLUE}Starting smart installation process...${NC}"
|
|
|
|
# Detect existing installation using our sophisticated system
|
|
if detect_existing_agent; then
|
|
# Check if migration is needed by looking for old directories
|
|
if [ -d "$OLD_CONFIG_DIR" ] || [ -d "$OLD_STATE_DIR" ]; then
|
|
perform_migration
|
|
fi
|
|
# Upgrade path
|
|
perform_upgrade
|
|
else
|
|
# Check if migration is needed for new install
|
|
if [ -d "$OLD_CONFIG_DIR" ] || [ -d "$OLD_STATE_DIR" ]; then
|
|
perform_migration
|
|
fi
|
|
# New installation path
|
|
perform_new_installation
|
|
fi
|
|
|
|
echo ""
|
|
echo -e "${GREEN}=== Smart Installer Complete ===${NC}"
|
|
echo -e "${BLUE}Thank you for using RedFlag!${NC}"
|
|
`, baseURL)
|
|
}
|
|
|
|
func (h *DownloadHandler) generateWindowsScript(baseURL string) string {
|
|
return fmt.Sprintf(`@echo off
|
|
REM RedFlag Agent Installation Script for Windows
|
|
REM This script downloads the agent and sets up Windows service
|
|
REM
|
|
REM Usage:
|
|
REM install.bat - Interactive mode (prompts for token)
|
|
REM install.bat YOUR_TOKEN_HERE - Automatic mode (uses provided token)
|
|
|
|
set REDFLAG_SERVER=%s
|
|
set AGENT_DIR=%%ProgramFiles%%\RedFlag
|
|
set AGENT_BINARY=%%AGENT_DIR%%\redflag-agent.exe
|
|
set CONFIG_DIR=%%ProgramData%%\RedFlag
|
|
|
|
echo === RedFlag Agent Installation ===
|
|
echo.
|
|
|
|
REM Check for admin privileges
|
|
net session >nul 2>&1
|
|
if %%errorLevel%% neq 0 (
|
|
echo ERROR: This script must be run as Administrator
|
|
echo Right-click and select "Run as administrator"
|
|
pause
|
|
exit /b 1
|
|
)
|
|
|
|
REM Detect architecture
|
|
if "%%PROCESSOR_ARCHITECTURE%%"=="AMD64" (
|
|
set DOWNLOAD_ARCH=amd64
|
|
) else if "%%PROCESSOR_ARCHITECTURE%%"=="ARM64" (
|
|
set DOWNLOAD_ARCH=arm64
|
|
) else (
|
|
echo ERROR: Unsupported architecture: %%PROCESSOR_ARCHITECTURE%%
|
|
echo Supported: AMD64, ARM64
|
|
pause
|
|
exit /b 1
|
|
)
|
|
|
|
echo Detected architecture: %%PROCESSOR_ARCHITECTURE%% (using windows-%%DOWNLOAD_ARCH%%)
|
|
echo.
|
|
|
|
REM Create installation directory
|
|
echo Creating installation directory...
|
|
if not exist "%%AGENT_DIR%%" mkdir "%%AGENT_DIR%%"
|
|
echo [OK] Installation directory created
|
|
|
|
REM Create config directory
|
|
if not exist "%%CONFIG_DIR%%" mkdir "%%CONFIG_DIR%%"
|
|
echo [OK] Configuration directory created
|
|
|
|
REM Grant full permissions to SYSTEM and Administrators on config directory
|
|
echo Setting permissions on configuration directory...
|
|
icacls "%%CONFIG_DIR%%" /grant "SYSTEM:(OI)(CI)F"
|
|
icacls "%%CONFIGDIR%%" /grant "Administrators:(OI)(CI)F"
|
|
echo [OK] Permissions set
|
|
echo.
|
|
|
|
REM Stop existing service if running (to allow binary update)
|
|
sc query RedFlagAgent >nul 2>&1
|
|
if %%errorLevel%% equ 0 (
|
|
echo Existing service detected - stopping to allow update...
|
|
sc stop RedFlagAgent >nul 2>&1
|
|
timeout /t 3 /nobreak >nul
|
|
echo [OK] Service stopped
|
|
)
|
|
|
|
REM Download agent binary
|
|
echo Downloading agent binary...
|
|
echo From: %%REDFLAG_SERVER%%/api/v1/downloads/windows-%%DOWNLOAD_ARCH%%
|
|
curl -sfL "%%REDFLAG_SERVER%%/api/v1/downloads/windows-%%DOWNLOAD_ARCH%%" -o "%%AGENT_BINARY%%"
|
|
if %%errorLevel%% neq 0 (
|
|
echo ERROR: Failed to download agent binary
|
|
echo Please ensure %%REDFLAG_SERVER%% is accessible
|
|
pause
|
|
exit /b 1
|
|
)
|
|
echo [OK] Agent binary downloaded
|
|
echo.
|
|
|
|
REM Agent registration
|
|
echo === Agent Registration ===
|
|
echo.
|
|
|
|
REM Check if token was provided as command-line argument
|
|
if not "%%1"=="" (
|
|
set TOKEN=%%1
|
|
echo Using provided registration token
|
|
) else (
|
|
echo IMPORTANT: You need a registration token to enroll this agent.
|
|
echo.
|
|
echo To get a token:
|
|
echo 1. Visit: %%REDFLAG_SERVER%%/settings/tokens
|
|
echo 2. Create a new registration token
|
|
echo 3. Copy the token
|
|
echo.
|
|
set /p TOKEN="Enter registration token (or press Enter to skip): "
|
|
)
|
|
|
|
REM Check if agent is already registered
|
|
if exist "%%CONFIG_DIR%%\config.json" (
|
|
echo.
|
|
echo [INFO] Agent already registered - configuration file exists
|
|
echo [INFO] Skipping registration to preserve agent history
|
|
echo [INFO] If you need to re-register, delete: %%CONFIG_DIR%%\config.json
|
|
echo.
|
|
) else if not "%%TOKEN%%"=="" (
|
|
echo.
|
|
echo === Registering Agent ===
|
|
echo.
|
|
|
|
REM Attempt registration
|
|
"%%AGENT_BINARY%%" --server "%%REDFLAG_SERVER%%" --token "%%TOKEN%%" --register
|
|
|
|
REM Check exit code
|
|
if %%errorLevel%% equ 0 (
|
|
echo [OK] Agent registered successfully
|
|
echo [OK] Configuration saved to: %%CONFIG_DIR%%\config.json
|
|
echo.
|
|
) else (
|
|
echo.
|
|
echo [ERROR] Registration failed
|
|
echo.
|
|
echo Please check:
|
|
echo 1. Server is accessible: %%REDFLAG_SERVER%%
|
|
echo 2. Registration token is valid and not expired
|
|
echo 3. Token has available seats remaining
|
|
echo.
|
|
echo To try again:
|
|
echo "%%AGENT_BINARY%%" --server "%%REDFLAG_SERVER%%" --token "%%TOKEN%%" --register
|
|
echo.
|
|
pause
|
|
exit /b 1
|
|
)
|
|
) else (
|
|
echo.
|
|
echo [INFO] No registration token provided - skipping registration
|
|
echo.
|
|
echo To register later:
|
|
echo "%%AGENT_BINARY%%" --server "%%REDFLAG_SERVER%%" --token YOUR_TOKEN --register
|
|
)
|
|
|
|
REM Check if service already exists
|
|
echo.
|
|
echo === Configuring Windows Service ===
|
|
echo.
|
|
|
|
sc query RedFlagAgent >nul 2>&1
|
|
if %%errorLevel%% equ 0 (
|
|
echo [INFO] RedFlag Agent service already installed
|
|
echo [INFO] Service will be restarted with updated binary
|
|
echo.
|
|
) else (
|
|
echo Installing RedFlag Agent service...
|
|
"%%AGENT_BINARY%%" -install-service
|
|
if %%errorLevel%% equ 0 (
|
|
echo [OK] Service installed successfully
|
|
echo.
|
|
|
|
REM Give Windows SCM time to register the service
|
|
timeout /t 2 /nobreak >nul
|
|
) else (
|
|
echo [ERROR] Failed to install service
|
|
echo.
|
|
pause
|
|
exit /b 1
|
|
)
|
|
)
|
|
|
|
REM Start the service if agent is registered
|
|
if exist "%%CONFIG_DIR%%\config.json" (
|
|
echo Starting RedFlag Agent service...
|
|
"%%AGENT_BINARY%%" -start-service
|
|
if %%errorLevel%% equ 0 (
|
|
echo [OK] RedFlag Agent service started
|
|
echo.
|
|
echo Agent is now running as a Windows service in the background.
|
|
echo You can verify it is working by checking the agent status in the web UI.
|
|
) else (
|
|
echo [WARNING] Failed to start service. You can start it manually:
|
|
echo "%%AGENT_BINARY%%" -start-service
|
|
echo Or use Windows Services: services.msc
|
|
)
|
|
) else (
|
|
echo [WARNING] Service not started (agent not registered)
|
|
echo To register and start the service:
|
|
echo 1. Register: "%%AGENT_BINARY%%" --server "%%REDFLAGSERVER%%" --token YOUR_TOKEN --register
|
|
echo 2. Start: "%%AGENT_BINARY%%" -start-service
|
|
)
|
|
|
|
echo.
|
|
echo === Installation Complete ===
|
|
echo.
|
|
echo The RedFlag agent has been installed as a Windows service.
|
|
echo Configuration file: %%CONFIG_DIR%%\config.json
|
|
echo Agent binary: %%AGENT_BINARY%%
|
|
echo.
|
|
|
|
echo Managing the RedFlag Agent service:
|
|
echo Check status: "%%AGENT_BINARY%%" -service-status
|
|
echo Start manually: "%%AGENT_BINARY%%" -start-service
|
|
echo Stop service: "%%AGENT_BINARY%%" -stop-service
|
|
echo Remove service: "%%AGENT_BINARY%%" -remove-service
|
|
echo.
|
|
|
|
echo Alternative management with Windows Services:
|
|
echo Open services.msc and look for "RedFlag Update Agent"
|
|
echo.
|
|
|
|
echo To run the agent directly (for debugging):
|
|
echo "%%AGENT_BINARY%%"
|
|
echo.
|
|
|
|
echo To verify the agent is working:
|
|
echo 1. Check the web UI for the agent status
|
|
echo 2. Look for recent check-ins from this machine
|
|
echo.
|
|
|
|
pause
|
|
`, baseURL)
|
|
} |