package main import ( "fmt" "html/template" "log" "net/http" "os" "strings" ) type ServerConfig struct { listen string } func main() { config := ServerConfig{ listen: getEnvOr("IP_CHECKER_LISTEN", ":8080"), } tmpl := template.Must(template.ParseFiles("assets/index.html")) http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("./assets/static")))) http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { handleRequest(w, r, tmpl) }) log.Printf("Starting server on %s", config.listen) log.Fatal(http.ListenAndServe(config.listen, nil)) } func handleRequest(w http.ResponseWriter, r *http.Request, tmpl *template.Template) { sourceIP := strings.Split(r.RemoteAddr, ":")[0] isHeadless := strings.HasPrefix(r.Header.Get("User-Agent"), "curl/") log.Printf("r.URL.Path: %s, sourceIP: %s, isHeadless: %t, User-Agent: %s", r.URL.Path, sourceIP, isHeadless, r.Header.Get("User-Agent")) // TODO: /favicon.ico switch r.URL.Path { case "/": if isHeadless { fmt.Fprintf(w, "%s\n", sourceIP) } else { csp := []string{ "default-src 'none'", "img-src 'self'", "script-src-elem 'self'", "style-src-elem 'self' fonts.googleapis.com", "font-src fonts.gstatic.com", "connect-src api.ip.sb api-v3.speedtest.cn api.ipapi.is", } w.Header().Set("Content-Security-Policy", strings.Join(csp, "; ")) data := map[string]string{ "sourceIP": sourceIP, } err := tmpl.Execute(w, data) if err != nil { http.Error(w, "Unable to load template", http.StatusInternalServerError) log.Printf("Template execution error: %v", err) return } } case "/robots.txt": fmt.Fprintf(w, `User-Agent: * Disallow: /harming/humans Disallow: /ignoring/human/orders Disallow: /harm/to/self `) default: http.NotFound(w, r) } } func getEnvOr(key, defaultValue string) string { if value, exists := os.LookupEnv(key); exists { return value } return defaultValue }