package main import ( "net/http" "regexp" "sort" "strconv" "strings" ) func profileHandler(w http.ResponseWriter, r *http.Request) { configMu.RLock() mfaEnabled := config.MFASecret != "" configMu.RUnlock() data := struct { MFAEnabled bool }{ MFAEnabled: mfaEnabled, } renderTemplate(w, r, "profile.html", data) } func dashboardHandler(w http.ResponseWriter, r *http.Request) { renderTemplate(w, r, "dashboard.html", nil) } func urlListsHandler(w http.ResponseWriter, r *http.Request) { if r.Method == "POST" { action := r.FormValue("action") url := sanitizeInput(r.FormValue("url")) indexStr := r.FormValue("index") configMu.RLock() urlFileList := config.URLFileList configMu.RUnlock() urls, err := readLines(urlFileList) if err != nil { http.Error(w, "Error reading URL list", http.StatusInternalServerError) return } switch action { case "add": if isValidURL(url) { urls = append(urls, url) } case "remove": index, _ := strconv.Atoi(indexStr) if index >= 0 && index < len(urls) { urls = append(urls[:index], urls[index+1:]...) } case "toggle": // Assume enabled/disabled by commenting out with # index, _ := strconv.Atoi(indexStr) if index >= 0 && index < len(urls) { if strings.HasPrefix(urls[index], "#") { urls[index] = strings.TrimPrefix(urls[index], "#") } else { urls[index] = "#" + urls[index] } } } writeLines(urlFileList, urls) http.Redirect(w, r, "/urllists", http.StatusSeeOther) return } configMu.RLock() urlFileList := config.URLFileList defaultURLs := config.DefaultURLs configMu.RUnlock() urls, _ := readLines(urlFileList) if len(urls) == 0 { writeLines(urlFileList, defaultURLs) urls = defaultURLs } data := struct { URLs []string }{ URLs: urls, } renderTemplate(w, r, "urllists.html", data) } func domainsHandler(w http.ResponseWriter, r *http.Request) { if r.Method == "POST" { action := r.FormValue("action") domain := sanitizeInput(r.FormValue("domain")) configMu.RLock() blocklistFile := config.BlocklistFile configMu.RUnlock() domains, err := readLines(blocklistFile) if err != nil { http.Error(w, "Error reading domains", http.StatusInternalServerError) return } switch action { case "add": if isValidDomain(domain) { domains = append(domains, domain) sort.Strings(domains) } case "remove": for i, d := range domains { if d == domain { domains = append(domains[:i], domains[i+1:]...) break } } } writeLines(blocklistFile, domains) http.Redirect(w, r, "/domains", http.StatusSeeOther) return } configMu.RLock() blocklistFile := config.BlocklistFile configMu.RUnlock() query := r.URL.Query().Get("query") domains, _ := readLines(blocklistFile) var filtered []string if query != "" { query = strings.ReplaceAll(query, "*", ".*") re, err := regexp.Compile("(?i)" + query) if err == nil { for _, d := range domains { if re.MatchString(d) { filtered = append(filtered, d) } } } } else { filtered = domains } data := struct { Domains []string Query string }{ Domains: filtered, Query: query, } renderTemplate(w, r, "domains.html", data) } func applyHandler(w http.ResponseWriter, r *http.Request) { userInitiatedMu.Lock() userInitiated = true userInitiatedMu.Unlock() updateBlocklist(1) // Force userInitiatedMu.Lock() userInitiated = false userInitiatedMu.Unlock() http.Redirect(w, r, "/", http.StatusSeeOther) } func logsHandler(w http.ResponseWriter, r *http.Request) { // For simplicity, assume logs are in stdout, or implement file logging w.Header().Set("Content-Type", "text/plain") w.WriteHeader(http.StatusOK) w.Write([]byte("Logs placeholder")) }