diff --git a/app/templates/index.html b/app/templates/index.html new file mode 100644 index 0000000..3e1a5f9 --- /dev/null +++ b/app/templates/index.html @@ -0,0 +1,34 @@ +{{ define "title" }}Honeypot Dashboard{{ end }} +{{ define "content" }} +
+

Honeypot Overview

+
+
+
Total IPs
+
{{ index .Stats "total_ips" }}
+
+
+
Blacklisted
+
{{ index .Stats "blacklisted_ips" }}
+
+
+
Connections
+
{{ index .Stats "total_connections" }}
+
+
+
Auth Attempts
+
{{ index .Stats "total_auth_attempts" }}
+
+
+
+

Quick Actions

+ +
+
+{{ end }} +{{ define "index" }}{{ template "layout.html" . }}{{ end }} diff --git a/app/templates/layout.html b/app/templates/layout.html new file mode 100644 index 0000000..7b6e93a --- /dev/null +++ b/app/templates/layout.html @@ -0,0 +1,46 @@ + + + + + + {{ block "title" . }}Honeypot Dashboard{{ end }} + + + + +
+ +
+ {{ block "content" . }}{{ end }} +
+ +
+ + diff --git a/app/templates/logs.html b/app/templates/logs.html new file mode 100644 index 0000000..1989d90 --- /dev/null +++ b/app/templates/logs.html @@ -0,0 +1,29 @@ +{{ define "title" }}Recent Logs{{ end }} +{{ define "content" }} +

Recent Logs

+
+ + + + + + + + + + + + {{ range .Rows }} + + + + + + + + {{ end }} + +
TimeRemoteServiceDetailsPayload
{{ .Timestamp.Format "2006-01-02 15:04:05" }}{{ .RemoteAddr }}:{{ .RemotePort }}{{ .Service }}
{{ .Details | toJSON }}
{{ .RawPayload }}
+
+{{ end }} +{{ define "logs" }}{{ template "layout.html" . }}{{ end }} diff --git a/app/web.go b/app/web.go index 0a2e07e..e522644 100644 --- a/app/web.go +++ b/app/web.go @@ -1,78 +1,60 @@ package app import ( - "encoding/json" - "fmt" - "html/template" - "log" - "net/http" - "os" - "strings" - "time" + "embed" + "encoding/json" + "fmt" + "html/template" + "log" + "net/http" + "os" + "strings" + "time" ) -var tpl = template.Must(template.New("base").Parse(` - - - - - Honeypot Dashboard - - - -

🍯 Honeypot Dashboard

- -{{ .Body }} - - -`)) +//go:embed templates/*.html +var templatesFS embed.FS + +var templates *template.Template + +func initTemplates() error { + funcMap := template.FuncMap{ + "toJSON": func(v any) string { + b, _ := json.Marshal(v) + return string(b) + }, + } + // Parse layout first, then pages + t, err := template.New("layout.html").Funcs(funcMap).ParseFS(templatesFS, "templates/layout.html", "templates/index.html", "templates/logs.html") + if err != nil { return err } + templates = t + return nil +} + func (a *App) startWeb() { bind := a.cfg.Web.Bind port := a.cfg.Web.Port addr := fmt.Sprintf("%s:%d", bind, port) mux := http.NewServeMux() - mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { - var sb strings.Builder - - // Get basic stats - if a.threatIntel != nil { - stats := a.threatIntel.GetStats() - sb.WriteString("
") - sb.WriteString(fmt.Sprintf("
%v
Total IPs
", stats["total_ips"])) - sb.WriteString(fmt.Sprintf("
%v
Blacklisted
", stats["blacklisted_ips"])) - sb.WriteString(fmt.Sprintf("
%v
Connections
", stats["total_connections"])) - sb.WriteString(fmt.Sprintf("
%v
Auth Attempts
", stats["total_auth_attempts"])) - sb.WriteString("
") + if templates == nil { + if err := initTemplates(); err != nil { + log.Printf("template init error: %v", err) } - - sb.WriteString("

Quick Actions

") - sb.WriteString("

📋 View Recent Logs

") - sb.WriteString("

⚠️ View Top Threats

") - sb.WriteString("

🚫 Manage Blacklist

") - sb.WriteString("

📊 Detailed Statistics

") - tpl.Execute(w, map[string]interface{}{"Body": template.HTML(sb.String())}) + } + mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + stats := map[string]any{} + if a.threatIntel != nil { + stats = a.threatIntel.GetStats() + } + data := map[string]any{ + "Now": time.Now().Format("2006-01-02 15:04:05 MST"), + "Stats": stats, + } + if templates != nil { + _ = templates.ExecuteTemplate(w, "index", data) + return + } + http.Error(w, "templates not loaded", 500) }) mux.HandleFunc("/logs", func(w http.ResponseWriter, r *http.Request) { // display last 200 logs @@ -117,15 +99,15 @@ func (a *App) startWeb() { } } - // render simple table - var sb strings.Builder - sb.WriteString("") - for _, r := range rows { - detB, _ := json.Marshal(r.Details) - sb.WriteString(fmt.Sprintf("", r.Timestamp.Format("2006-01-02 15:04:05"), r.RemoteAddr, r.RemotePort, r.Service, template.HTMLEscapeString(string(detB)), template.HTMLEscapeString(r.RawPayload))) + data := map[string]any{ + "Now": time.Now().Format("2006-01-02 15:04:05 MST"), + "Rows": rows, } - sb.WriteString("
TimeRemoteServiceDetailsPayload
%s%s:%s%s%s
%s
") - tpl.Execute(w, map[string]interface{}{"Body": template.HTML(sb.String())}) + if templates != nil { + _ = templates.ExecuteTemplate(w, "logs", data) + return + } + http.Error(w, "templates not loaded", 500) }) srv := &http.Server{Addr: addr, Handler: mux}