package api import ( "encoding/json" "fmt" "io" "net/http" "net" "strings" "regexp" "time" ) var fs http.Handler func init() { fs = http.FileServer(http.Dir("static")) } const LogLength = 100 type accessLog struct { ClientAddr string `json:"clientAddr"` RequestedPath string `json:"requestedPath"` RequestTime time.Time `json:"requestTime"` HttpMethod string `json:"httpMethod"` } func CreateFilesHandler(logs *[LogLength]string, n *int, logChan chan string) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { jsonData, _ := json.Marshal(accessLog{ ClientAddr: redactIP(r.RemoteAddr), RequestedPath: r.URL.Path, RequestTime: time.Now().UTC(), HttpMethod: r.Method, }) addRotLog(logs, n, logChan, string(jsonData)) // Serve the index.html file from the static directory http.StripPrefix("/", fs).ServeHTTP(w, r) } } func CreateGetLogs(logs *[LogLength]string) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { for _, s := range logs { fmt.Fprintln(w, s) } } } func CreateLoginHandler(logs *[LogLength]string, n *int, logChan chan string) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { body, err := io.ReadAll(r.Body) if err != nil { http.Error(w, "Bad Request", http.StatusBadRequest) return } defer r.Body.Close() var data map[string]any if json.Unmarshal(body, &data) != nil { addRotLog(logs, n, logChan, fmt.Sprintf(`{"authRequest": %s}`, string(body))) http.Error(w, `{"message": "Unauthorized"}`, http.StatusUnauthorized) return } if email, ok := data["email"].(string); ok { if rememberMe, ok := data["rememberMe"].(bool); ok { addRotLog(logs, n, logChan, fmt.Sprintf(`{"authRequest": {"email": "%s", "password": "XXXXXXXX", "loginTime": "%s", "success": false, "rememberMe": %t}}`, email, time.Now().UTC(), rememberMe)) } } http.Error(w, `{"message": "Unauthorized"}`, http.StatusUnauthorized) } } const ( StatusOperational = "operational" StatusDegraded = "degraded" StatusDown = "down" ) const ( IconAPIGateway = "🔗" IconWeb = "🌐" IconAuth = "🔐" IconDB = "🗄️" IconStorage = "📁" IconNotifications = "📧" IconSearch = "🔍" IconAnalytics = "📊" ) const ( SeverityMinor = "minor" SeverityMajor = "major" ) const ( ServiceAPIGateway = "api" ServiceWeb = "web" ServiceAuth = "auth" ServiceDB = "database" ServiceStorage = "storage" ServiceNotifications = "notifications" ServiceSearch = "search" ServiceAnalytics = "analytics" ) func StatusHandler(w http.ResponseWriter, r *http.Request) { type response struct { Status string `json:"status"` Description string `json:"description"` Uptime float64 `json:"uptime"` ResponseTime int `json:"responseTime"` ActiveIncidents int `json:"activeIncidents"` ScheduledMaintenance int `json:"scheduledMaintenance"` } // res := response{ // Status: StatusDown, // Description: "Everything is on fire", // Uptime: 0.0, // ResponseTime: 0.0, // ActiveIncidents: 9001, // ScheduledMaintenance: 0, // } res := response{ Status: StatusDegraded, Description: "Everything is not great", Uptime: 50.0, ResponseTime: 20000, ActiveIncidents: 9001, ScheduledMaintenance: 1, } jsonData, _ := json.Marshal(res) fmt.Fprintf(w, "%s", string(jsonData)) } func StatusServicesHandler(w http.ResponseWriter, r *http.Request) { type service struct { Id string `json:"id"` Name string `json:"name"` Description string `json:"description"` Icon string `json:"icon"` Status string `json:"status"` ResponseTime int `json:"responseTime"` Uptime float64 `json:"uptime"` } var response []service _ = response } func StatusMetricsHandler(w http.ResponseWriter, r *http.Request) { type response struct { Uptime float64 `json:"uptime"` ResponseTime int `json:"responseTime"` RequestVolume int `json:"requestVolume"` ErrorRate float64 `json:"errorRate"` } } func StatusIncidentsHandler(w http.ResponseWriter, r *http.Request) { type incident struct { Id string `json:"id"` Title string `json:"title"` Description string `json:"description"` Status string `json:"status"` Severity string `json:"severity"` StartTime time.Time `json:"startTime"` AffectedServices []string `json:"affectedServices"` } var response []incident _ = response } func StatusMaintenanceHandler(w http.ResponseWriter, r *http.Request) { type event struct { Id string `json:"id"` Title string `json:"title"` Description string `json:"description"` StartTime time.Time `json:"startTime"` EndTime time.Time `json:"endTime"` AffectedServices []string `json:"affectedServices"` } var response []event _ = response } func StatusUptimeHandler(w http.ResponseWriter, r *http.Request) { type event struct { Date time.Time `json:"date"` Uptime float64 `json:"uptime"` } var response []event _ = response } // TODO: SUBSCRIBE TO EMAILS func StatusSubscribeHandler(w http.ResponseWriter, r *http.Request) { } // TODO: CONTACT HANDLER func ContactHandler(w http.ResponseWriter, r *http.Request) { } func redactIP(input string) string { ipRegex := `\b(?:\d{1,3}\.){3}\d{1,3}\b` re := regexp.MustCompile(ipRegex) return re.ReplaceAllStringFunc(input, func(match string) string { if ip := net.ParseIP(match); ip != nil { parts := strings.Split(match, ".") if len(parts) == 4 { parts[3] = "XXX" return strings.Join(parts, ".") } } return match }) } func addRotLog(logs *[LogLength]string, last *int, parser chan string, value string) { if strings.Contains(value, "\n") { for _, v := range strings.Split(value, "\n") { addRotLog(logs, last, parser, v) } } else { if *last == LogLength { for i := 0; i < LogLength-1; i++ { logs[i] = logs[i+1] } logs[LogLength-1] = value parser <- value } else { logs[*last] = value *last++ parser <- value } } }