package app import ( "encoding/json" "io" "io/fs" "net/http" "os" "path/filepath" "strings" ) // --------------------------------------------------------------------- // domains file // --------------------------------------------------------------------- // GET /api/v1/domains/file?name=bases|meta|subs|static|smartdns|last-ips-map|last-ips-map-direct|last-ips-map-wildcard|wildcard-observed-hosts // POST /api/v1/domains/file { "name": "...", "content": "..." } func handleDomainsFile(w http.ResponseWriter, r *http.Request) { switch r.Method { case http.MethodGet: name := strings.TrimSpace(r.URL.Query().Get("name")) if name == "smartdns" { domains, source := loadSmartDNSWildcardDomainsState(nil) writeJSON(w, http.StatusOK, map[string]string{ "content": renderSmartDNSDomainsContent(domains), "source": source, }) return } if name == "wildcard-observed-hosts" { writeJSON(w, http.StatusOK, map[string]string{ "content": readWildcardObservedHostsContent(), "source": "derived", }) return } path, ok := domainFiles[name] if !ok { http.Error(w, "unknown file name", http.StatusBadRequest) return } source := "file" if strings.HasPrefix(name, "last-ips-map") { source = "artifact" } data, err := os.ReadFile(path) if err != nil { if !os.IsNotExist(err) { http.Error(w, "read error", http.StatusInternalServerError) return } switch name { case "bases", "meta", "subs": // fallback to embedded seed embedName := name + ".txt" if name == "meta" { embedName = "meta-special.txt" } data, _ = fs.ReadFile(embeddedDomains, "assets/domains/"+embedName) source = "embedded" default: data = []byte{} } } writeJSON(w, http.StatusOK, map[string]string{ "content": string(data), "source": source, }) case http.MethodPost: var body struct { Name string `json:"name"` Content string `json:"content"` } if r.Body != nil { defer r.Body.Close() if err := json.NewDecoder(io.LimitReader(r.Body, 1<<20)).Decode(&body); err != nil { http.Error(w, "bad json", http.StatusBadRequest) return } } if strings.TrimSpace(body.Name) == "smartdns" { domains := parseSmartDNSDomainsContent(body.Content) if err := saveSmartDNSWildcardDomainsState(domains); err != nil { http.Error(w, "write error", http.StatusInternalServerError) return } writeJSON(w, http.StatusOK, map[string]string{"status": "ok"}) return } if body.Name == "last-ips-map-direct" || body.Name == "last-ips-map-wildcard" || body.Name == "wildcard-observed-hosts" { http.Error(w, "read-only file name", http.StatusBadRequest) return } path, ok := domainFiles[strings.TrimSpace(body.Name)] if !ok { http.Error(w, "unknown file name", http.StatusBadRequest) return } _ = os.MkdirAll(filepath.Dir(path), 0o755) if err := os.WriteFile(path, []byte(body.Content), 0o644); err != nil { http.Error(w, "write error", http.StatusInternalServerError) return } writeJSON(w, http.StatusOK, map[string]string{"status": "ok"}) default: http.Error(w, "method not allowed", http.StatusMethodNotAllowed) } }