bugfixing
This commit is contained in:
		
							parent
							
								
									6ea4d31109
								
							
						
					
					
						commit
						2056479224
					
				
							
								
								
									
										105
									
								
								main.go
								
								
								
								
							
							
						
						
									
										105
									
								
								main.go
								
								
								
								
							| 
						 | 
				
			
			@ -2,22 +2,23 @@ package main
 | 
			
		|||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"os"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"database/sql"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"html/template"
 | 
			
		||||
	"log"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"sync"
 | 
			
		||||
	"syscall"
 | 
			
		||||
 | 
			
		||||
	"gontrol/src/randomname"
 | 
			
		||||
	"gontrol/src/server/database"
 | 
			
		||||
	"gontrol/src/logger"
 | 
			
		||||
	"gontrol/src/randomname"
 | 
			
		||||
	api "gontrol/src/server/api"
 | 
			
		||||
	"gontrol/src/server/database"
 | 
			
		||||
	websocketserver "gontrol/src/server/websocket"
 | 
			
		||||
 | 
			
		||||
	"os/signal"
 | 
			
		||||
| 
						 | 
				
			
			@ -31,6 +32,8 @@ var (
 | 
			
		|||
	db 	 *sql.DB
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
type Config struct {
 | 
			
		||||
	Database struct {
 | 
			
		||||
		Username string `envconfig:"DB_USERNAME"`
 | 
			
		||||
| 
						 | 
				
			
			@ -55,22 +58,14 @@ func processError(err error) {
 | 
			
		|||
 | 
			
		||||
func init() {
 | 
			
		||||
	tmpl, _ = template.ParseGlob("templates/*.html")
 | 
			
		||||
 | 
			
		||||
	// Sqlite3
 | 
			
		||||
	err := logger.InitDB("/tmp/gontrol_logs.db")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// func initDB (dbUser string, dbPassword string, dbHost string, dbPort int16, dbName string ) {
 | 
			
		||||
// 	var err  error
 | 
			
		||||
// 	dbOpen := fmt.Sprintf("%s:%s@(%s:%d)/%s?parseTime=true", dbUser,dbPassword, dbHost, dbPort, dbName)
 | 
			
		||||
// 	db, err = sql.Open("mysql", dbOpen)
 | 
			
		||||
// 	if err != nil {
 | 
			
		||||
// 		log.Fatal(err)
 | 
			
		||||
// 	}
 | 
			
		||||
 | 
			
		||||
// 	if err = db.Ping(); err != nil {
 | 
			
		||||
// 		log.Fatal(err)
 | 
			
		||||
// 	}
 | 
			
		||||
// 	log.Println("Connected to database")
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
func renderTemplate(w http.ResponseWriter, tmpl string, data interface{}) {
 | 
			
		||||
	t, err := template.ParseFiles(tmpl)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
| 
						 | 
				
			
			@ -119,7 +114,24 @@ func getHomepage(w http.ResponseWriter, r *http.Request) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
func listAgents(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	var agents []api.Agent
 | 
			
		||||
	agents, err := api.GetAgents(db)
 | 
			
		||||
	currentAgents := getAgentsStatus()
 | 
			
		||||
 | 
			
		||||
	for _, currAgent := range currentAgents {
 | 
			
		||||
		for i, agent := range agents {
 | 
			
		||||
			if currAgent ==  agent.AgentName {
 | 
			
		||||
				// log.Printf("%s online", agent.AgentName)
 | 
			
		||||
				// logger.InsertLog(logger.Debug, fmt.Sprintf("%s online after page refresh", agent.AgentName))
 | 
			
		||||
				// agents[i].Status = fmt.Sprint("<span class=\"badge bg-success\">Connected</span>")
 | 
			
		||||
				agents[i].Status = "Connected"
 | 
			
		||||
			} else {
 | 
			
		||||
				// agent.Status = fmt.Sprintf("<span class=\"badge bg-danger\">Disconnected</span>")
 | 
			
		||||
				agents[i].Status = "Disconnected"
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		http.Error(w, "Failed to fetch agents", http.StatusInternalServerError)
 | 
			
		||||
		return
 | 
			
		||||
| 
						 | 
				
			
			@ -128,6 +140,23 @@ func listAgents(w http.ResponseWriter, r *http.Request) {
 | 
			
		|||
	renderTemplate(w, "templates/partials/agent_list.html", agents)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getAgentsStatus() []string {
 | 
			
		||||
	resp, err := http.Get("http://localhost:5555/agentNames")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Println("Error fetching agent names:", err)
 | 
			
		||||
		logger.InsertLog(logger.Error, "Error fetching agent names from websocketServer")
 | 
			
		||||
	}
 | 
			
		||||
	defer resp.Body.Close()
 | 
			
		||||
 | 
			
		||||
	var agentNames []string
 | 
			
		||||
	if err := json.NewDecoder(resp.Body).Decode(&agentNames); err != nil {
 | 
			
		||||
		log.Println("Error decoding response:", err)
 | 
			
		||||
		return []string{}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return agentNames
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getAgentNames(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	api.GetAgentNames(db, w, r)
 | 
			
		||||
	return
 | 
			
		||||
| 
						 | 
				
			
			@ -139,25 +168,38 @@ func getAgentIds(w http.ResponseWriter, r *http.Request) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
func logsHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
 | 
			
		||||
	var logs[] logger.LogEntry
 | 
			
		||||
	logs, err := logger.FetchLogs(10)
 | 
			
		||||
 | 
			
		||||
	// for i, logLine := range logs {
 | 
			
		||||
	// 	logs[i].Message = strings.ReplaceAll(logLine.Message, `"`, `\"`)
 | 
			
		||||
	// }
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		http.Error(w, "Error fetching logs", http.StatusInternalServerError)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fmt.Fprintf(w, "<div>")
 | 
			
		||||
	// for _, logEntry := range logsToSend {
 | 
			
		||||
	for _, logEntry := range logs {
 | 
			
		||||
		fmt.Fprintf(w, "<p><strong>[%s] [%s]</strong> %s</p>", logEntry.Timestamp, logEntry.Level, logEntry.Message)
 | 
			
		||||
	}
 | 
			
		||||
	fmt.Fprintf(w, "</div>")
 | 
			
		||||
 | 
			
		||||
	renderTemplate(w, "templates/partials/logs_partial.html", logs)
 | 
			
		||||
 | 
			
		||||
// 	fmt.Fprintf(w, "<div>")
 | 
			
		||||
// 	// for _, logEntry := range logsToSend {
 | 
			
		||||
// 	for _, logEntry := range logs {
 | 
			
		||||
// 		fmt.Fprintf(w, "<p><strong>[%s] [%s]</strong> %s</p>", logEntry.Timestamp, logEntry.Level, logEntry.Message)
 | 
			
		||||
// 	}
 | 
			
		||||
// 	fmt.Fprintf(w, "</div>")
 | 
			
		||||
 | 
			
		||||
	// w.Header().Set("Content-Type", "application/json")
 | 
			
		||||
	// json.NewEncoder(w).Encode(logs)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
 | 
			
		||||
	// sqlite3 has been initialized in init()
 | 
			
		||||
	defer logger.CloseDB()
 | 
			
		||||
 | 
			
		||||
	var cfg Config
 | 
			
		||||
	readEnv(&cfg)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -176,18 +218,11 @@ func main() {
 | 
			
		|||
	webMux.HandleFunc("/agents/{agentId}", agentsHandler)
 | 
			
		||||
	webMux.HandleFunc("/logs", logsHandler)
 | 
			
		||||
 | 
			
		||||
	// Sqlite3
 | 
			
		||||
	err := logger.InitDB("/tmp/gontrol_logs.db")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	defer logger.CloseDB()
 | 
			
		||||
	// initDB (cfg.Database.Username, cfg.Database.Password, cfg.Database.Host, cfg.Database.Port, cfg.Database.Name)
 | 
			
		||||
	// mysql
 | 
			
		||||
	db = database.InitDB (cfg.Database.Username, cfg.Database.Password, cfg.Database.Host, cfg.Database.Port, cfg.Database.Name)
 | 
			
		||||
	defer db.Close()
 | 
			
		||||
 | 
			
		||||
	name := randomname.GenerateRandomName()
 | 
			
		||||
	fmt.Println(name)
 | 
			
		||||
	fmt.Sprintf("Server instance: %s", name)
 | 
			
		||||
 | 
			
		||||
	webServer := &http.Server {
 | 
			
		||||
		Addr: ":3333",
 | 
			
		||||
| 
						 | 
				
			
			@ -202,7 +237,7 @@ func main() {
 | 
			
		|||
		if err := websocketServer.ListenAndServe(); err != http.ErrServerClosed {
 | 
			
		||||
			log.Fatalf("Websocket server failed: %s", err)
 | 
			
		||||
		}
 | 
			
		||||
		err = logger.InsertLog(logger.Info, logLine)
 | 
			
		||||
		err := logger.InsertLog(logger.Info, logLine)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			log.Println("Error inserting log:", err)
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -218,7 +253,7 @@ func main() {
 | 
			
		|||
			log.Fatalf("Web server failed: %s", err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		err = logger.InsertLog(logger.Info, logLine)
 | 
			
		||||
		err := logger.InsertLog(logger.Info, logLine)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			log.Println("Error inserting log:", err)
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,6 +5,7 @@ import (
 | 
			
		|||
	"fmt"
 | 
			
		||||
	"log"
 | 
			
		||||
	// "net/http"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"sync"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -17,16 +18,16 @@ var (
 | 
			
		|||
	lite_dbMutex sync.Mutex
 | 
			
		||||
 | 
			
		||||
	logMutex sync.Mutex
 | 
			
		||||
	logLimit = 10
 | 
			
		||||
	logLimit = 100
 | 
			
		||||
	// LogEntries []string
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
    Debug   LogLevel = "DEBUG"
 | 
			
		||||
    Info    LogLevel = "INFO"
 | 
			
		||||
    Warning LogLevel = "WARNING"
 | 
			
		||||
    Error   LogLevel = "ERROR"
 | 
			
		||||
    Fatal   LogLevel = "FATAL"
 | 
			
		||||
    Debug   LogLevel = "debug"
 | 
			
		||||
    Info    LogLevel = "info"
 | 
			
		||||
    Warning LogLevel = "warning"
 | 
			
		||||
    Error   LogLevel = "error"
 | 
			
		||||
    Fatal   LogLevel = "fatal"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type LogLevel string
 | 
			
		||||
| 
						 | 
				
			
			@ -74,6 +75,8 @@ func InsertLog(level LogLevel, message string) error {
 | 
			
		|||
		return fmt.Errorf("Error starting transaction: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	message = strings.ReplaceAll(message, `"`, `\"`)
 | 
			
		||||
 | 
			
		||||
	// insertQuery := `INSERT INTO logs (message) VALUES (?)`
 | 
			
		||||
	insertQuery := `INSERT INTO logs (message, level) VALUES (?, ?)`
 | 
			
		||||
	// _, err := Lite_db.Exec(insertQuery, message, level)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -60,21 +60,22 @@ func registerAgent(agentName, agentId, agentIp, agentType string) error {
 | 
			
		|||
	resp, err := http.PostForm(registerURL, form)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Printf("Error registering agent: %v", err)
 | 
			
		||||
		logger.InsertLog(logger.Error, fmt.Sprintf("Error registering agent: %v", err))
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	defer resp.Body.Close()
 | 
			
		||||
 | 
			
		||||
	if resp.StatusCode == http.StatusCreated {
 | 
			
		||||
		logLine := fmt.Sprintf("Agent %s successfully registered.", agentName)
 | 
			
		||||
		log.Printf(logLine)
 | 
			
		||||
		// logLine = logger.ToLog(logLine)
 | 
			
		||||
		logger.InsertLog(logger.Info, logLine)
 | 
			
		||||
		log.Printf("Agent %s successfully registered.", agentName)
 | 
			
		||||
		logger.InsertLog(logger.Info, fmt.Sprintf("Agent %s successfully registered.", agentName))
 | 
			
		||||
		return nil
 | 
			
		||||
	} else if resp.StatusCode == http.StatusOK {
 | 
			
		||||
		log.Printf("Agent %s already registered.", agentName)
 | 
			
		||||
		logger.InsertLog(logger.Info, fmt.Sprintf("Agent %s already registered.", agentName))
 | 
			
		||||
		return nil
 | 
			
		||||
	} else {
 | 
			
		||||
		log.Printf("Failed to register agent, status: %v", resp.Status)
 | 
			
		||||
		logger.InsertLog(logger.Error, fmt.Sprintf("Failed to register agent, status: %v", resp.Status))
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -87,6 +88,7 @@ func getAgentDetails(agentId string) (*api.Agent, error) {
 | 
			
		|||
	resp, err := http.Get(agentURL)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Printf("Failed to make GET request: %s", err)
 | 
			
		||||
		logger.InsertLog(logger.Error, fmt.Sprintf("Failed to make GET request: %s", err))
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	defer resp.Body.Close()
 | 
			
		||||
| 
						 | 
				
			
			@ -94,6 +96,7 @@ func getAgentDetails(agentId string) (*api.Agent, error) {
 | 
			
		|||
	doc, err := goquery.NewDocumentFromReader(resp.Body)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Printf("Failed to parse HTML: %s", err)
 | 
			
		||||
		logger.InsertLog(logger.Error, fmt.Sprintf("Failed to parse HTML: %s", err))
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -104,6 +107,7 @@ func getAgentDetails(agentId string) (*api.Agent, error) {
 | 
			
		|||
			agent.AgentID, err = strconv.Atoi(strings.TrimSpace(strings.TrimPrefix(text, "ID:")))
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				log.Printf("Converting string to integer failed in getAgentDetails(): %s", err)
 | 
			
		||||
				logger.InsertLog(logger.Error, fmt.Sprintf("Converting string to integer failed in getAgentDetails(): %s", err))
 | 
			
		||||
			}
 | 
			
		||||
		} else if strings.HasPrefix(text, "Name:") {
 | 
			
		||||
			agent.AgentName = strings.TrimSpace(strings.TrimPrefix(text, "Name:"))
 | 
			
		||||
| 
						 | 
				
			
			@ -130,24 +134,28 @@ func getAgentIds() ([]string, error) {
 | 
			
		|||
	resp, err := http.Get(idURL)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Printf("Failed to make GET request: %s", err)
 | 
			
		||||
		logger.InsertLog(logger.Error, fmt.Sprintf("Failed to make GET request: %s", err))
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	defer resp.Body.Close()
 | 
			
		||||
 | 
			
		||||
	if resp.StatusCode != http.StatusOK {
 | 
			
		||||
		log.Printf("Unexpected status code: %d", resp.StatusCode)
 | 
			
		||||
		logger.InsertLog(logger.Info, fmt.Sprintf("Unexpected status code: %d", resp.StatusCode))
 | 
			
		||||
		return nil, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	body, err := io.ReadAll(resp.Body)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Printf("Failed to read response body: %s", err)
 | 
			
		||||
		logger.InsertLog(logger.Error, fmt.Sprintf("Failed to read response body: %s", err))
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var agentIds []string
 | 
			
		||||
	if err := json.Unmarshal(body, &agentIds); err != nil {
 | 
			
		||||
		log.Printf("Failed to parse JSON response: %s", err)
 | 
			
		||||
		logger.InsertLog(logger.Error, fmt.Sprintf("Failed to parse JSON response: %s", err))
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -159,6 +167,7 @@ func (wsh webSocketHandler) ServeHTTP(w http.ResponseWriter, r *http.Request){
 | 
			
		|||
	c, err := wsh.upgrader.Upgrade(w, r, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Printf("Error %s when upgrading connection to websocket", err)
 | 
			
		||||
		logger.InsertLog(logger.Error, fmt.Sprintf("Error %s when upgrading connection to websocket", err))
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -183,13 +192,13 @@ func (wsh webSocketHandler) ServeHTTP(w http.ResponseWriter, r *http.Request){
 | 
			
		|||
 | 
			
		||||
	if agentName == "" || agentIP == "" {
 | 
			
		||||
		log.Printf("Missing agentName or IPv4Address in query parameters")
 | 
			
		||||
		logger.InsertLog(logger.Info, fmt.Sprintf("Missing agentName or IPv4Address in query parameters"))
 | 
			
		||||
		c.Close()
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	logLine := fmt.Sprintf("Agent %s connected: %s (%s)", agentId, agentName, agentIP)
 | 
			
		||||
	log.Printf(logLine)
 | 
			
		||||
	logger.InsertLog(logger.Info, logLine)
 | 
			
		||||
	log.Printf("Agent %s connected: %s (%s)", agentId, agentName, agentIP)
 | 
			
		||||
	logger.InsertLog(logger.Info, fmt.Sprintf("Agent %s connected: %s (%s)", agentId, agentName, agentIP))
 | 
			
		||||
 | 
			
		||||
	agentSocketsMutex.Lock()
 | 
			
		||||
	agentSockets[agentName] = c
 | 
			
		||||
| 
						 | 
				
			
			@ -200,22 +209,19 @@ func (wsh webSocketHandler) ServeHTTP(w http.ResponseWriter, r *http.Request){
 | 
			
		|||
		delete(agentSockets, agentName)
 | 
			
		||||
		agentSocketsMutex.Unlock()
 | 
			
		||||
		c.Close()
 | 
			
		||||
		logLine := fmt.Sprintf("Agent disconnected: %s (%s)", agentName, agentIP)
 | 
			
		||||
		log.Printf(logLine)
 | 
			
		||||
		logger.InsertLog(logger.Info, logLine)
 | 
			
		||||
		log.Printf("Agent disconnected: %s (%s)", agentName, agentIP)
 | 
			
		||||
		logger.InsertLog(logger.Info, fmt.Sprintf("Agent disconnected: %s (%s)", agentName, agentIP))
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	for {
 | 
			
		||||
		_, message, err := c.ReadMessage()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			logLine := fmt.Sprintf("Error reading from agent %s: %v", agentName, err)
 | 
			
		||||
			log.Printf(logLine)
 | 
			
		||||
			logger.InsertLog(logger.Error, logLine)
 | 
			
		||||
			log.Printf("Error reading from agent %s: %v", agentName, err)
 | 
			
		||||
			logger.InsertLog(logger.Error, fmt.Sprintf("Error reading from agent %s: %v", agentName, err))
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
		logLine := fmt.Sprintf("Message from agent %s: %s", agentName, message)
 | 
			
		||||
		log.Printf(logLine)
 | 
			
		||||
		logger.InsertLog(logger.Debug, logLine)
 | 
			
		||||
		log.Printf("Message from agent %s: %s", agentName, message)
 | 
			
		||||
		logger.InsertLog(logger.Info, fmt.Sprintf("Message from agent %s: %s", agentName, message))
 | 
			
		||||
 | 
			
		||||
		if ch, ok := responseChannels.Load(agentName); ok {
 | 
			
		||||
			responseChan := ch.(chan string)
 | 
			
		||||
| 
						 | 
				
			
			@ -233,6 +239,7 @@ var executeCommand http.HandlerFunc = func(w http.ResponseWriter, r *http.Reques
 | 
			
		|||
	err := r.ParseForm()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		http.Error(w, "Invalid form data", http.StatusBadRequest)
 | 
			
		||||
		logger.InsertLog(logger.Info, "Invalid form data")
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -245,6 +252,7 @@ var executeCommand http.HandlerFunc = func(w http.ResponseWriter, r *http.Reques
 | 
			
		|||
 | 
			
		||||
	if !ok {
 | 
			
		||||
		http.Error(w, "Agent not connected", http.StatusNotFound)
 | 
			
		||||
		logger.InsertLog(logger.Info, "Agent not connected")
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -262,6 +270,7 @@ var executeCommand http.HandlerFunc = func(w http.ResponseWriter, r *http.Reques
 | 
			
		|||
	err = conn.WriteMessage(websocket.TextMessage, messageBytes)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		http.Error(w, "Failed to send command to the agent", http.StatusInternalServerError)
 | 
			
		||||
		logger.InsertLog(logger.Error, "Failed to send command to the agent")
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -275,13 +284,15 @@ var executeCommand http.HandlerFunc = func(w http.ResponseWriter, r *http.Reques
 | 
			
		|||
		payload, ok := parsedResponse["payload"]
 | 
			
		||||
		if !ok {
 | 
			
		||||
			http.Error(w, "Invalid response structure", http.StatusInternalServerError)
 | 
			
		||||
			logger.InsertLog(logger.Error, "Invalid response structure")
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		w.WriteHeader(http.StatusOK)
 | 
			
		||||
		w.Header().Set("Content-Type", "text/plain")
 | 
			
		||||
		w.Write([]byte(payload))
 | 
			
		||||
	case <- time.After(10 * time.Second):
 | 
			
		||||
			http.Error(w, "Agent repsonse timed out", http.StatusGatewayTimeout)
 | 
			
		||||
			http.Error(w, "Agent response timed out", http.StatusGatewayTimeout)
 | 
			
		||||
			logger.InsertLog(logger.Info, "Agent response timed out")
 | 
			
		||||
		}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,45 +11,119 @@
 | 
			
		|||
    <title>g2: gommand & gontrol</title>
 | 
			
		||||
    <script>
 | 
			
		||||
    // Query Agents for the Dropdown Menu
 | 
			
		||||
    <!-- document.addEventListener('DOMContentLoaded', () => { -->
 | 
			
		||||
    <!--     fetch('/agentNames') -->
 | 
			
		||||
    <!--         .then(response => response.json()) -->
 | 
			
		||||
    <!--         .then(agentNames => { -->
 | 
			
		||||
    <!--             const dropdown = document.getElementById('agentName'); -->
 | 
			
		||||
    <!--             agentNames.forEach(name => { -->
 | 
			
		||||
    <!--                 const option = document.createElement('option'); -->
 | 
			
		||||
    <!--                 option.value = name; -->
 | 
			
		||||
    <!--                 option.textContent = name; -->
 | 
			
		||||
    <!--                 dropdown.appendChild(option); -->
 | 
			
		||||
    <!--             }); -->
 | 
			
		||||
    <!--         }) -->
 | 
			
		||||
    <!--         .catch(error => console.error('Error fetching agent names:', error)); -->
 | 
			
		||||
    <!-- }); -->
 | 
			
		||||
    <!-- // Query agents currently connected to the websocket and put status into the table -->
 | 
			
		||||
    <!--     const updateAgentStatuses = () => { -->
 | 
			
		||||
    <!--     fetch('http://localhost:5555/agentNames') -->
 | 
			
		||||
    <!--         .then(response => response.json()) -->
 | 
			
		||||
    <!--         .then(agentNames => { -->
 | 
			
		||||
    <!--             console.log("Agent names fetched:", agentNames); -->
 | 
			
		||||
    <!--             const tableRows = document.querySelectorAll('#agentList table tbody tr'); -->
 | 
			
		||||
    <!--             tableRows.forEach(row => { -->
 | 
			
		||||
    <!--                 const nameCell = row.querySelector('td:nth-child(2)'); -->
 | 
			
		||||
    <!--                 const statusCell = row.querySelector('td:nth-child(5)'); -->
 | 
			
		||||
    <!--                 if (nameCell && statusCell) { -->
 | 
			
		||||
    <!--                     const agentName = nameCell.textContent.trim(); -->
 | 
			
		||||
    <!--                     if (agentNames.includes(agentName)) { -->
 | 
			
		||||
    <!--                         statusCell.innerHTML = '<span class="badge bg-success">Connected</span>'; -->
 | 
			
		||||
    <!--                     } else { -->
 | 
			
		||||
    <!--                         statusCell.innerHTML = '<span class="badge bg-danger">Disconnected</span>'; -->
 | 
			
		||||
    <!--                     } -->
 | 
			
		||||
    <!--                 } -->
 | 
			
		||||
    <!--             }); -->
 | 
			
		||||
    <!--         }) -->
 | 
			
		||||
    <!--         .catch(error => console.error('Error fetching agent names:', error)); -->
 | 
			
		||||
    <!-- }; -->
 | 
			
		||||
    <!-- updateAgentStatuses(); -->
 | 
			
		||||
    <!-- setInterval(updateAgentStatuses, 5000); -->
 | 
			
		||||
 | 
			
		||||
    <!-- document.body.addEventListener('htmx:afterSwap', function(evt) { -->
 | 
			
		||||
    <!--     if (evt.detail.xhr.status === 200) { -->
 | 
			
		||||
    <!--         const tableRows = document.querySelectorAll('#agentList table tbody tr'); -->
 | 
			
		||||
    <!--         tableRows.forEach(row => { -->
 | 
			
		||||
    <!--             const nameCell = row.querySelector('td:nth-child(2)'); -->
 | 
			
		||||
    <!--             const statusCell = row.querySelector('td:nth-child(5)'); -->
 | 
			
		||||
    <!--             if (nameCell && statusCell) { -->
 | 
			
		||||
    <!--                 const agentName = nameCell.textContent.trim(); -->
 | 
			
		||||
    <!--                 if ("Connected" === statusCell.innerHTML) { -->
 | 
			
		||||
    <!--                     statusCell.innerHTML = '<span class="badge bg-success">Connected</span>'; -->
 | 
			
		||||
    <!--                 } else { -->
 | 
			
		||||
    <!--                     statusCell.innerHTML = '<span class="badge bg-danger">Disconnected</span>'; -->
 | 
			
		||||
    <!--                 } -->
 | 
			
		||||
    <!--             } -->
 | 
			
		||||
    <!--         } -->
 | 
			
		||||
    <!--     } -->
 | 
			
		||||
    <!-- }); -->
 | 
			
		||||
 | 
			
		||||
    document.addEventListener('DOMContentLoaded', () => {
 | 
			
		||||
        fetch('/agentNames')
 | 
			
		||||
            .then(response => response.json())
 | 
			
		||||
            .then(agentNames => {
 | 
			
		||||
                const dropdown = document.getElementById('agentName');
 | 
			
		||||
                agentNames.forEach(name => {
 | 
			
		||||
                    const option = document.createElement('option');
 | 
			
		||||
                    option.value = name;
 | 
			
		||||
                    option.textContent = name;
 | 
			
		||||
                    dropdown.appendChild(option);
 | 
			
		||||
                });
 | 
			
		||||
            })
 | 
			
		||||
            .catch(error => console.error('Error fetching agent names:', error));
 | 
			
		||||
    });
 | 
			
		||||
    // Query agents currently connected to the websocket and put status into the table
 | 
			
		||||
        const updateAgentStatuses = () => {
 | 
			
		||||
        fetch('http://localhost:5555/agentNames')
 | 
			
		||||
            .then(response => response.json())
 | 
			
		||||
            .then(agentNames => {
 | 
			
		||||
                console.log("Agent names fetched:", agentNames);
 | 
			
		||||
                const tableRows = document.querySelectorAll('#agentList table tbody tr');
 | 
			
		||||
                tableRows.forEach(row => {
 | 
			
		||||
                    const nameCell = row.querySelector('td:nth-child(2)');
 | 
			
		||||
                    const statusCell = row.querySelector('td:nth-child(5)');
 | 
			
		||||
                    if (nameCell && statusCell) {
 | 
			
		||||
                        const agentName = nameCell.textContent.trim();
 | 
			
		||||
                        if (agentNames.includes(agentName)) {
 | 
			
		||||
                            statusCell.innerHTML = '<span class="badge bg-success">Connected</span>';
 | 
			
		||||
                        } else {
 | 
			
		||||
                            statusCell.innerHTML = '<span class="badge bg-danger">Disconnected</span>';
 | 
			
		||||
                        }
 | 
			
		||||
        document.body.addEventListener('htmx:afterSwap', function(event) {
 | 
			
		||||
            if (event.target.id === "agentList") {
 | 
			
		||||
                updateAgentDropdown();
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        function updateAgentDropdown() {
 | 
			
		||||
            const select = document.getElementById("agentName");
 | 
			
		||||
            const optionValues = Array.from(select.options).map(opt => opt.value);
 | 
			
		||||
            const rows = document.querySelectorAll("#agentList tbody tr");
 | 
			
		||||
 | 
			
		||||
            rows.forEach(row => {
 | 
			
		||||
                const status = row.cells[4].textContent.trim();
 | 
			
		||||
                const name = row.cells[1].textContent.trim();
 | 
			
		||||
 | 
			
		||||
                if (status === "Connected") {
 | 
			
		||||
                    row.cells[4].innerHTML = '<span class="badge bg-success">Connected</span>';
 | 
			
		||||
                    const option = document.createElement("option");
 | 
			
		||||
                    if (!(optionValues.includes(name))) {
 | 
			
		||||
                        option.value = name;
 | 
			
		||||
                        option.textContent = name;
 | 
			
		||||
                        select.appendChild(option);
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
            })
 | 
			
		||||
            .catch(error => console.error('Error fetching agent names:', error));
 | 
			
		||||
    };
 | 
			
		||||
    updateAgentStatuses();
 | 
			
		||||
    setInterval(updateAgentStatuses, 1000);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (status === "Disconnected") {
 | 
			
		||||
                    row.cells[4].innerHTML = '<span class="badge bg-danger">Disconnected</span>';
 | 
			
		||||
                    const option = Array.from(select.options).find(opt => opt.value === name);
 | 
			
		||||
                    if(option) {
 | 
			
		||||
                        select.removeChild(option);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    </script>
 | 
			
		||||
    <style>
 | 
			
		||||
        .log-info {
 | 
			
		||||
            color: green;
 | 
			
		||||
        }
 | 
			
		||||
        .log-warning {
 | 
			
		||||
            color: orange;
 | 
			
		||||
        }
 | 
			
		||||
        .log-error {
 | 
			
		||||
            color: red;
 | 
			
		||||
        }
 | 
			
		||||
        .log-fatal {
 | 
			
		||||
            color: blue;
 | 
			
		||||
        }
 | 
			
		||||
        .log-debug {
 | 
			
		||||
            color: violet;
 | 
			
		||||
        }
 | 
			
		||||
    </style>
 | 
			
		||||
 | 
			
		||||
</head>
 | 
			
		||||
<body>
 | 
			
		||||
    <div class="container">
 | 
			
		||||
| 
						 | 
				
			
			@ -58,15 +132,17 @@
 | 
			
		|||
                <h2>Agents</h2>
 | 
			
		||||
 | 
			
		||||
                <!-- Agent List -->
 | 
			
		||||
                <!-- <div id="agentList" hx-get="/agents" hx-trigger="load, every 2s" hx-swap="innerHTML"></div> -->
 | 
			
		||||
                <div id="agentList" hx-get="/agents" hx-trigger="load" hx-swap="innerHTML"></div>
 | 
			
		||||
                <div id="agentList" hx-get="/agents" hx-trigger="load, every 2s" hx-swap="innerHTML"></div>
 | 
			
		||||
                <!-- <div id="agentList" hx-get="/agents" hx-trigger="load" hx-swap="innerHTML"></div> -->
 | 
			
		||||
                <!-- Agent Commands -->
 | 
			
		||||
                <div id="agentCommands">
 | 
			
		||||
                    <h3>Command Execution</h3>
 | 
			
		||||
                    <form hx-post="http://localhost:5555/executeCommand" hx-target="#commandOutput" hx-encoding="application/x-www-form-urlencoded"  hx-swap="innerHTML">
 | 
			
		||||
                        <div class="mb-3">
 | 
			
		||||
                            <label for="agentName" class="form-label">Agent Name</label>
 | 
			
		||||
                            <select class="form-select" id="agentName" name="agentName" required>
 | 
			
		||||
                            <!-- <select class="form-select" id="agentName" name="agentName" required> -->
 | 
			
		||||
                            <select id="agentName" class="form-select" name="agentName" hx-on="htmx:afterSwap:updateAgentDropdown" required>
 | 
			
		||||
                                <option value="" disabled selected>Select an Agent</option>
 | 
			
		||||
                                <!-- Dynamically populated with agent names -->
 | 
			
		||||
                            </select>
 | 
			
		||||
                        </div>
 | 
			
		||||
| 
						 | 
				
			
			@ -80,33 +156,46 @@
 | 
			
		|||
                </div>
 | 
			
		||||
 | 
			
		||||
                <!-- Add Agent Form -->
 | 
			
		||||
                <button class="btn btn-primary mt-3" data-bs-toggle="collapse" data-bs-target="#addAgentForm">Add Agent</button>
 | 
			
		||||
                <div id="addAgentForm" class="collapse mt-2">
 | 
			
		||||
                    <form hx-post="/agents" hx-target="#agentList" hx-swap="innerHTML">
 | 
			
		||||
                        <div class="mb-3">
 | 
			
		||||
                            <label for="agentId" class="form-label">Agent Id</label>
 | 
			
		||||
                            <input type="text" class="form-control" id="agentId" name="agentId" required>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <div class="mb-3">
 | 
			
		||||
                            <label for="agentName" class="form-label">Agent Name</label>
 | 
			
		||||
                            <input type="text" class="form-control" id="agentName" name="agentName" required>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <div class="mb-3">
 | 
			
		||||
                            <label for="IPv4Address" class="form-label">IPv4 Address</label>
 | 
			
		||||
                            <input type="text" class="form-control" id="IPv4Address" name="IPv4Address" required>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <div class="mb-3">
 | 
			
		||||
                            <label for="initialContact" class="form-label">Initial Contact</label>
 | 
			
		||||
                            <input type="datetime-local" class="form-control" id="initialContact" name="initialContact" required>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <div class="mb-3">
 | 
			
		||||
                            <label for="lastContact" class="form-label">Last Contact</label>
 | 
			
		||||
                            <input type="datetime-local" class="form-control" id="lastContact" name="lastContact" required>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <button type="submit" class="btn btn-success">Add Agent</button>
 | 
			
		||||
                    </form>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
                <!-- <button class="btn btn-primary mt-3" data-bs-toggle="collapse" data-bs-target="#addAgentForm">Add Agent</button> -->
 | 
			
		||||
                <!-- <div id="addAgentForm" class="collapse mt-2"> -->
 | 
			
		||||
                <!--     <form hx-post="/agents" hx-target="#agentList" hx-swap="innerHTML"> -->
 | 
			
		||||
                <!--         <div class="mb-3"> -->
 | 
			
		||||
                <!--             <label for="agentId" class="form-label">Agent Id</label> -->
 | 
			
		||||
                <!--             <input type="text" class="form-control" id="agentId" name="agentId" required> -->
 | 
			
		||||
                <!--         </div> -->
 | 
			
		||||
                <!--         <div class="mb-3"> -->
 | 
			
		||||
                <!--             <label for="agentName" class="form-label">Agent Name</label> -->
 | 
			
		||||
                <!--             <input type="text" class="form-control" id="agentName" name="agentName" required> -->
 | 
			
		||||
                <!--         </div> -->
 | 
			
		||||
                <!--         <div class="mb-3"> -->
 | 
			
		||||
                <!--             <label for="IPv4Address" class="form-label">IPv4 Address</label> -->
 | 
			
		||||
                <!--             <input type="text" class="form-control" id="IPv4Address" name="IPv4Address" required> -->
 | 
			
		||||
                <!--         </div> -->
 | 
			
		||||
                <!--         <div class="mb-3"> -->
 | 
			
		||||
                <!--             <label for="initialContact" class="form-label">Initial Contact</label> -->
 | 
			
		||||
                <!--             <input type="datetime-local" class="form-control" id="initialContact" name="initialContact" required> -->
 | 
			
		||||
                <!--         </div> -->
 | 
			
		||||
                <!--         <div class="mb-3"> -->
 | 
			
		||||
                <!--             <label for="lastContact" class="form-label">Last Contact</label> -->
 | 
			
		||||
                <!--             <input type="datetime-local" class="form-control" id="lastContact" name="lastContact" required> -->
 | 
			
		||||
                <!--         </div> -->
 | 
			
		||||
                <!--         <button type="submit" class="btn btn-success">Add Agent</button> -->
 | 
			
		||||
                <!--     </form> -->
 | 
			
		||||
                <!-- </div> -->
 | 
			
		||||
            <!-- </div> -->
 | 
			
		||||
 | 
			
		||||
                            <!-- Logs Section -->
 | 
			
		||||
                <h3>Logs</h3>
 | 
			
		||||
                <div id="logs-container" hx-get="/logs" hx-target="#logs-container" hx-swap="innerHTML" hx-trigger="every 3s">
 | 
			
		||||
                    <!-- Logs will be injected here -->
 | 
			
		||||
                <!-- </div> -->
 | 
			
		||||
                <!-- <button hx-get="/logs" hx-target="#logs-container" hx-swap="innerHTML"> -->
 | 
			
		||||
                <!--     Load Logs -->
 | 
			
		||||
                <!-- </button> -->
 | 
			
		||||
                <!-- <button hx-get="/logs" hx-target="#logs-container" hx-swap="innerHTML" hx-trigger="every 8s"> -->
 | 
			
		||||
                <!--     Auto-Refresh Logs -->
 | 
			
		||||
                <!-- </button> -->
 | 
			
		||||
            <!-- </div> -->
 | 
			
		||||
 | 
			
		||||
            <!-- Agent Details -->
 | 
			
		||||
            <div class="col" id="agentDetails">
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,6 +5,23 @@
 | 
			
		|||
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
 | 
			
		||||
    <title>Web Server Logs</title>
 | 
			
		||||
    <script src="https://unpkg.com/htmx.org@1.8.5"></script>
 | 
			
		||||
    <style>
 | 
			
		||||
        .log-info {
 | 
			
		||||
            color: green;
 | 
			
		||||
        }
 | 
			
		||||
        .log-warning {
 | 
			
		||||
            color: orange;
 | 
			
		||||
        }
 | 
			
		||||
        .log-error {
 | 
			
		||||
            color: red;
 | 
			
		||||
        }
 | 
			
		||||
        .log-fatal {
 | 
			
		||||
            color: blue;
 | 
			
		||||
        }
 | 
			
		||||
        .log-debug {
 | 
			
		||||
            color: violet;
 | 
			
		||||
        }
 | 
			
		||||
    </style>
 | 
			
		||||
</head>
 | 
			
		||||
<body>
 | 
			
		||||
    <h1>Web Server Logs</h1>
 | 
			
		||||
| 
						 | 
				
			
			@ -13,12 +30,51 @@
 | 
			
		|||
        <!-- Logs will be injected here -->
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <button hx-get="/logs" hx-target="#logs-container" hx-swap="outerHTML">
 | 
			
		||||
    <button hx-get="/logs" hx-target="#logs-container" hx-swap="innerHTML">
 | 
			
		||||
        Load Logs
 | 
			
		||||
    </button>
 | 
			
		||||
 | 
			
		||||
    <button hx-get="/logs" hx-target="#logs-container" hx-swap="outerHTML" hx-trigger="every 2s">
 | 
			
		||||
    <button hx-get="/logs" hx-target="#logs-container" hx-swap="innerHTML" hx-trigger="every 2s">
 | 
			
		||||
        Auto-Refresh Logs
 | 
			
		||||
    </button>
 | 
			
		||||
 | 
			
		||||
    <script>
 | 
			
		||||
        function renderLogs(logs) {
 | 
			
		||||
            const container = document.getElementById('logs-container');
 | 
			
		||||
            container.innerHTML = '';
 | 
			
		||||
 | 
			
		||||
            logs.forEarch(log => {
 | 
			
		||||
                const logElement = document.createElement('p');
 | 
			
		||||
                logElement.innerHTML = `<strong>ts=${log.timestamp} level=${log.level}</strong> msg=${log.message}`;
 | 
			
		||||
 | 
			
		||||
            if (log.level ==== 'INFO') {
 | 
			
		||||
                logElement.classList.add('log-info');
 | 
			
		||||
            } else if (log.level === 'WARNING') {
 | 
			
		||||
                logElement.classList.add('log'warning);
 | 
			
		||||
            } else if (log.level === 'ERROR') {
 | 
			
		||||
                logElement.classList.add('log-warning');
 | 
			
		||||
            } else if (log.level === 'FATAL') {
 | 
			
		||||
                logElement.classList.add('log-fatal');
 | 
			
		||||
            } else if (log.level === 'DEBUG') {
 | 
			
		||||
                logElement.classList.add('log-debug');
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            container.appendChild(logElement);
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        function fetchLogs() {
 | 
			
		||||
            fetch('/logs')
 | 
			
		||||
                .then(response -> response.json())
 | 
			
		||||
                .then(data => renderLogs(data))
 | 
			
		||||
                .catch(error -> console.error('Error fetching logs:', error));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        document.body.addEventListener('htmx:afterSwap', function(event){
 | 
			
		||||
            if (event.target.id === 'logs-container') {
 | 
			
		||||
                fetchLogs();
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    </script>
 | 
			
		||||
</body>
 | 
			
		||||
</html>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,7 +22,7 @@
 | 
			
		|||
            <!-- <td>{{.LastContact}}</td> -->
 | 
			
		||||
            <!-- <td><span class="badge bg-success">Connected</span></td> -->
 | 
			
		||||
            <!-- <td><span class="badge bg-danger">Disconnected</span></td> -->
 | 
			
		||||
            <td></td>
 | 
			
		||||
            <td>{{.Status}}</td>
 | 
			
		||||
            <td>
 | 
			
		||||
                <button class="btn btn-warning" hx-get="/agents/{{.AgentID}}" hx-target="#agentDetails" hx-swap="innerHTML">View</button>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,5 @@
 | 
			
		|||
{{range .}}
 | 
			
		||||
    <p class="log-{{.Level}}">
 | 
			
		||||
        <strong>ts={{.Timestamp}} level={{.Level}}</strong> msg="{{.Message}}"
 | 
			
		||||
    </p>
 | 
			
		||||
{{end}}
 | 
			
		||||
		Loading…
	
		Reference in New Issue