package main import ( "embed" "fmt" "log" "net/http" "zoraxy-headers/zoraxy_plugin" ) //go:embed web/* var webFS embed.FS func main() { spec := &zoraxy_plugin.IntroSpect{ ID: "zoraxy-headers", Name: "Header Tagger", Author: "Zoraxy Community", AuthorContact: "", Description: "Copy custom headers from a source domain to all other domains sharing the same tag.", URL: "", Type: zoraxy_plugin.PluginType_Utilities, VersionMajor: 1, VersionMinor: 0, VersionPatch: 0, UIPath: "/ui", PermittedAPIEndpoints: []zoraxy_plugin.PermittedAPIEndpoint{ {Method: "GET", Endpoint: "/plugin/api/proxy/list", Reason: "List proxy rules and their tags"}, {Method: "GET", Endpoint: "/plugin/api/proxy/header/list", Reason: "Read existing custom headers on a domain"}, {Method: "POST", Endpoint: "/plugin/api/proxy/header/add", Reason: "Copy headers onto tagged domains"}, {Method: "POST", Endpoint: "/plugin/api/proxy/header/remove", Reason: "Remove copied headers from tagged domains"}, }, } config, err := zoraxy_plugin.ServeAndRecvSpec(spec) if err != nil { log.Fatalf("failed to receive config: %v", err) } // Build the Zoraxy API client using the scoped key and Zoraxy port. baseURL := "http://127.0.0.1:8000" if config.ZoraxyPort > 0 { baseURL = fmt.Sprintf("http://127.0.0.1:%d", config.ZoraxyPort) } client := NewZoraxyClient(baseURL, config.APIKey) handler := &Handler{client: client} mux := http.NewServeMux() uiRouter := zoraxy_plugin.NewPluginEmbedUIRouter(spec.ID, &webFS, "web", spec.UIPath) uiRouter.HandleFunc("/api/groups", handler.handleGroups, mux) uiRouter.HandleFunc("/api/apply", handler.handleApply, mux) uiRouter.HandleFunc("/api/remove", handler.handleRemove, mux) uiRouter.RegisterTerminateHandler(func() { log.Println("zoraxy-headers shutting down") }, mux) uiRouter.AttachHandlerToMux(mux) // Wrap with no-cache middleware so the browser always fetches fresh assets // (the plugin binary embeds the web files, so URLs never change and the // browser would otherwise cache stale JS/CSS indefinitely). wrappedMux := noCacheMiddleware(mux) addr := fmt.Sprintf("127.0.0.1:%d", config.Port) log.Printf("zoraxy-headers v%d.%d.%d listening on %s (zoraxy API %s)", spec.VersionMajor, spec.VersionMinor, spec.VersionPatch, addr, baseURL) if err := http.ListenAndServe(addr, wrappedMux); err != nil { log.Fatalf("server error: %v", err) } } // noCacheMiddleware disables caching for all plugin responses. func noCacheMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Cache-Control", "no-store, no-cache, must-revalidate") w.Header().Set("Pragma", "no-cache") next.ServeHTTP(w, r) }) }