diff --git a/main.go b/main.go index 2b96b45..a56ef43 100644 --- a/main.go +++ b/main.go @@ -1,17 +1,17 @@ package main import ( - "os" + "crypto/rand" + "encoding/json" + "html/template" + "log" "net" - "time" + "net/http" + "os" "strconv" "strings" "sync" - "crypto/rand" - "html/template" - "log" - "net/http" - "encoding/json" + "time" ) const ( @@ -20,74 +20,70 @@ const ( ) var ( - debug = false - templates = make(map[string]*template.Template) - AppVersion = "development" + debug = false + templates = make(map[string]*template.Template) + AppVersion = "development" counterFile = "/data/counter.txt" - mu sync.Mutex + mu sync.Mutex ) type responseWriter struct { - http.ResponseWriter - statusCode int + http.ResponseWriter + statusCode int } func (rw *responseWriter) WriteHeader(code int) { - rw.statusCode = code - rw.ResponseWriter.WriteHeader(code) + rw.statusCode = code + rw.ResponseWriter.WriteHeader(code) } func newResponseWriter(w http.ResponseWriter) *responseWriter { - return &responseWriter{w, http.StatusOK} // Default 200 OK + return &responseWriter{w, http.StatusOK} // Default 200 OK } func LoggingMiddleware(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - start := time.Now() - - // ResponseWriter einpacken - rw := newResponseWriter(w) - - // Den nächsten Handler ausführen - next.ServeHTTP(rw, r) - - // Log-Daten sammeln - duration := time.Since(start) - clientIP := getClientIP(r) // Deine Funktion von vorhin - - // Format: IP - - [Datum] "Method Path Proto" Status Duration - log.Printf("%s - - [%s] \"%s %s %s\" %d %v\n", - clientIP, - time.Now().Format("02/Jan/2006:15:04:05 -0700"), - r.Method, - r.URL.Path, - r.Proto, - rw.statusCode, - duration, - ) - }) + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + start := time.Now() + rw := newResponseWriter(w) + next.ServeHTTP(rw, r) + duration := time.Since(start) + clientIP := getClientIP(r) + userAgent := r.UserAgent() + // Format: IP - - [Datum] "Method Path Proto" Status Duration User-Agent + // "Combined Log Format" + log.Printf("%s - - [%s] \"%s %s %s\" %d %v\n", + clientIP, + time.Now().Format("02/Jan/2006:15:04:05 -0700"), + r.Method, + r.URL.Path, + r.Proto, + rw.statusCode, + duration, + userAgent, + ) + }) } func getClientIP(r *http.Request) string { - // 1. Prüfe den X-Forwarded-For Header (Standard für Proxies) - xForwardedFor := r.Header.Get("X-Forwarded-For") - if xForwardedFor != "" { - // Der Header kann eine Liste von IPs sein (Client, Proxy1, Proxy2) - // Die erste IP in der Liste ist die echte Client-IP - ips := strings.Split(xForwardedFor, ",") - return strings.TrimSpace(ips[0]) - } + // 1. Prüfe den X-Forwarded-For Header (Standard für Proxies) + xForwardedFor := r.Header.Get("X-Forwarded-For") + if xForwardedFor != "" { + // Der Header kann eine Liste von IPs sein (Client, Proxy1, Proxy2) + // Die erste IP in der Liste ist die echte Client-IP + ips := strings.Split(xForwardedFor, ",") + return strings.TrimSpace(ips[0]) + } - // 2. Fallback auf X-Real-IP (oft von Traefik/Nginx gesetzt) - xRealIP := r.Header.Get("X-Real-IP") - if xRealIP != "" { - return xRealIP - } + // 2. Fallback auf X-Real-IP (oft von Traefik/Nginx gesetzt) + xRealIP := r.Header.Get("X-Real-IP") + if xRealIP != "" { + return xRealIP + } - // 3. Letzter Ausweg: Die direkte IP (wird in deinem Fall die Traefik-IP sein) - // RemoteAddr enthält oft auch den Port (z.B. "127.0.0.1:1234") - ip, _, _ := net.SplitHostPort(r.RemoteAddr) - return ip + // 3. Letzter Ausweg: Die direkte IP (wird in deinem Fall die Traefik-IP sein) + // RemoteAddr enthält oft auch den Port (z.B. "127.0.0.1:1234") + ip, _, _ := net.SplitHostPort(r.RemoteAddr) + return ip } // Diese Funktion wird nur intern aufgerufen, wenn der Mutex bereits gesperrt ist @@ -112,37 +108,39 @@ func IncrementPasswordCount() { mu.Lock() defer mu.Unlock() - // Wir rufen jetzt die interne Funktion auf, die NICHT versucht, + // Wir rufen jetzt die interne Funktion auf, die NICHT versucht, // den Mutex erneut zu sperren - count := getCount() + count := getCount() count++ os.WriteFile(counterFile, []byte(strconv.Itoa(count)), 0644) } func loadTemplates() { - // 1. FuncMap definieren - funcMap := template.FuncMap{ - "getAppVersion": func() string { return AppVersion }, - "getPassCount": func() int { return GetPasswordCount() }, - } + // 1. FuncMap definieren + funcMap := template.FuncMap{ + "getAppVersion": func() string { return AppVersion }, + "getPassCount": func() int { return GetPasswordCount() }, + } - // 2. Templates mit FuncMap laden - // Wir nutzen New("base.html"), da base.html meist das Haupt-Layout definiert - templates["index.html"] = template.Must(template.New("base.html").Funcs(funcMap).ParseFiles( - "templates/base.html", - "templates/index.html", - )) + // 2. Templates mit FuncMap laden + // Wir nutzen New("base.html"), da base.html meist das Haupt-Layout definiert + templates["index.html"] = template.Must(template.New("base.html").Funcs(funcMap).ParseFiles( + "templates/base.html", + "templates/index.html", + )) - templates["help.html"] = template.Must(template.New("base.html").Funcs(funcMap).ParseFiles( - "templates/base.html", - "templates/help.html", - )) + templates["help.html"] = template.Must(template.New("base.html").Funcs(funcMap).ParseFiles( + "templates/base.html", + "templates/help.html", + )) - log.Printf("Alle Templates erfolgreich geladen") + log.Printf("Alle Templates erfolgreich geladen") } func generatePassword() string { - if debug { log.Printf("called generatePassword\n") } + if debug { + log.Printf("called generatePassword\n") + } password := make([]byte, passwordLength) _, err := rand.Read(password) if err != nil { @@ -156,31 +154,37 @@ func generatePassword() string { } func passwordHandler(w http.ResponseWriter, r *http.Request) { - if debug { log.Printf("called passwordHandler\n") } - password := generatePassword() - currentCount := GetPasswordCount() - response := map[string]interface{}{ - "password": password, - "count": currentCount, - } - w.Header().Set("Content-Type", "application/json") - err := json.NewEncoder(w).Encode(response) - if err != nil { - log.Printf("Fehler beim Senden des JSON: %v", err) - http.Error(w, "Interner Fehler", http.StatusInternalServerError) - return - } + if debug { + log.Printf("called passwordHandler\n") + } + password := generatePassword() + currentCount := GetPasswordCount() + response := map[string]interface{}{ + "password": password, + "count": currentCount, + } + w.Header().Set("Content-Type", "application/json") + err := json.NewEncoder(w).Encode(response) + if err != nil { + log.Printf("Fehler beim Senden des JSON: %v", err) + http.Error(w, "Interner Fehler", http.StatusInternalServerError) + return + } } func passwordAPIHandler(w http.ResponseWriter, r *http.Request) { - if debug { log.Printf("called passwordHandler\n") } + if debug { + log.Printf("called passwordHandler\n") + } password := generatePassword() w.Header().Set("Content-Type", "text/plain") w.Write([]byte(password)) } func indexHandler(w http.ResponseWriter, r *http.Request) { - if debug { log.Printf("call indexHandler: Request %s %s\n", r.Method, r.URL) } + if debug { + log.Printf("call indexHandler: Request %s %s\n", r.Method, r.URL) + } password := generatePassword() //password := "load..." data := struct { @@ -188,7 +192,9 @@ func indexHandler(w http.ResponseWriter, r *http.Request) { }{ Password: password, } - if debug { log.Printf("prepare template for index\n") } + if debug { + log.Printf("prepare template for index\n") + } err := templates["index.html"].ExecuteTemplate(w, "base.html", data) if err != nil { log.Printf("Fehler beim Rendern des Templates: %v", err) @@ -197,7 +203,9 @@ func indexHandler(w http.ResponseWriter, r *http.Request) { } func helpHandler(w http.ResponseWriter, r *http.Request) { - if debug { log.Printf("call helpHandler\n") } + if debug { + log.Printf("call helpHandler\n") + } err := templates["help.html"].ExecuteTemplate(w, "base.html", nil) if err != nil { log.Printf("Fehler beim Rendern des Templates: %v", err) @@ -206,20 +214,20 @@ func helpHandler(w http.ResponseWriter, r *http.Request) { } func main() { - loadTemplates() - mux := http.NewServeMux() - - fs := http.FileServer(http.Dir("static")) - mux.Handle("/static/", http.StripPrefix("/static/", fs)) + loadTemplates() + mux := http.NewServeMux() - mux.HandleFunc("/", indexHandler) - mux.HandleFunc("/api/password", passwordAPIHandler) - mux.HandleFunc("/json/password", passwordHandler) - mux.HandleFunc("/help", helpHandler) + fs := http.FileServer(http.Dir("static")) + mux.Handle("/static/", http.StripPrefix("/static/", fs)) - loggingRouter := LoggingMiddleware(mux) + mux.HandleFunc("/", indexHandler) + mux.HandleFunc("/api/password", passwordAPIHandler) + mux.HandleFunc("/json/password", passwordHandler) + mux.HandleFunc("/help", helpHandler) - log.Println("Server läuft auf http://localhost:8080") - - log.Fatal(http.ListenAndServe(":8080", loggingRouter)) + loggingRouter := LoggingMiddleware(mux) + + log.Println("Server läuft auf http://localhost:8080") + + log.Fatal(http.ListenAndServe(":8080", loggingRouter)) }