From a1df5a1060687109c9585c960d28ef3a51ec0947 Mon Sep 17 00:00:00 2001 From: Toby Chui Date: Fri, 30 May 2025 17:28:14 +0800 Subject: [PATCH] Added static capture example - Added static capture example - Added instruction on how to view plugin info --- .../1. Introduction/5. Viewing Plugin Info.md | 13 ++ .../image-20250530171724441.png | Bin 0 -> 47861 bytes .../image-20250530171732607.png | Bin 0 -> 7039 bytes .../1. What is Zoraxy Plugin.html | 3 + .../1. Introduction/2. Getting Started.html | 3 + .../1. Introduction/3. Installing Plugin.html | 3 + .../1. Introduction/4. Enable Plugins.html | 3 + .../5. Viewing Plugin Info.html | 203 ++++++++++++++++++ .../image-20250530171724441.png | Bin 0 -> 47861 bytes .../image-20250530171732607.png | Bin 0 -> 7039 bytes .../1. Plugin Architecture.html | 3 + .../html/2. Architecture/2. Introspect.html | 3 + .../html/2. Architecture/3. Configure.html | 3 + .../2. Architecture/4. Capture Modes.html | 3 + .../html/2. Architecture/5. Plugin UI.html | 3 + .../3. Basic Examples/1. Hello World.html | 3 + .../3. Basic Examples/2. RESTful Example.html | 3 + .../3. Static Capture Example.html | 3 + docs/plugins/html/index.html | 3 + docs/plugins/index.json | 5 + example/plugins/static-capture-example/go.mod | 3 + .../plugins/static-capture-example/main.go | 107 +++++++++ .../mod/zoraxy_plugin/README.txt | 19 ++ .../mod/zoraxy_plugin/dev_webserver.go | 145 +++++++++++++ .../mod/zoraxy_plugin/dynamic_router.go | 162 ++++++++++++++ .../mod/zoraxy_plugin/embed_webserver.go | 174 +++++++++++++++ .../mod/zoraxy_plugin/static_router.go | 105 +++++++++ .../mod/zoraxy_plugin/zoraxy_plugin.go | 176 +++++++++++++++ .../plugins/static-capture-example/ui_info.go | 5 + 29 files changed, 1156 insertions(+) create mode 100644 docs/plugins/docs/1. Introduction/5. Viewing Plugin Info.md create mode 100644 docs/plugins/docs/1. Introduction/img/5. Viewing Plugin Info/image-20250530171724441.png create mode 100644 docs/plugins/docs/1. Introduction/img/5. Viewing Plugin Info/image-20250530171732607.png create mode 100644 docs/plugins/html/1. Introduction/5. Viewing Plugin Info.html create mode 100644 docs/plugins/html/1. Introduction/img/5. Viewing Plugin Info/image-20250530171724441.png create mode 100644 docs/plugins/html/1. Introduction/img/5. Viewing Plugin Info/image-20250530171732607.png create mode 100644 example/plugins/static-capture-example/go.mod create mode 100644 example/plugins/static-capture-example/main.go create mode 100644 example/plugins/static-capture-example/mod/zoraxy_plugin/README.txt create mode 100644 example/plugins/static-capture-example/mod/zoraxy_plugin/dev_webserver.go create mode 100644 example/plugins/static-capture-example/mod/zoraxy_plugin/dynamic_router.go create mode 100644 example/plugins/static-capture-example/mod/zoraxy_plugin/embed_webserver.go create mode 100644 example/plugins/static-capture-example/mod/zoraxy_plugin/static_router.go create mode 100644 example/plugins/static-capture-example/mod/zoraxy_plugin/zoraxy_plugin.go create mode 100644 example/plugins/static-capture-example/ui_info.go diff --git a/docs/plugins/docs/1. Introduction/5. Viewing Plugin Info.md b/docs/plugins/docs/1. Introduction/5. Viewing Plugin Info.md new file mode 100644 index 0000000..12647db --- /dev/null +++ b/docs/plugins/docs/1. Introduction/5. Viewing Plugin Info.md @@ -0,0 +1,13 @@ +# Viewing Plugin Info + +To view plugin information, you can click on the (i) icon in the plugin list. + +![image-20250530171732607](img/5. Viewing Plugin Info/image-20250530171732607.png) + +Next, a side menu will pop up from the side. Here ,you can see the current Plugin information and runtime values including Working directories and runtime assigned port. + +If you are a developer (which you probably is considering you are reading this doc), you can click on the "developer insight" dropdown to show the capture paths registered by this plugin for debug purposes. + + + +![image-20250530171724441](img/5. Viewing Plugin Info/image-20250530171724441.png) \ No newline at end of file diff --git a/docs/plugins/docs/1. Introduction/img/5. Viewing Plugin Info/image-20250530171724441.png b/docs/plugins/docs/1. Introduction/img/5. Viewing Plugin Info/image-20250530171724441.png new file mode 100644 index 0000000000000000000000000000000000000000..cac42bb4ef86ad2a1a6ee8f4166a8f484933ebed GIT binary patch literal 47861 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 literal 0 HcmV?d00001 diff --git a/docs/plugins/docs/1. Introduction/img/5. Viewing Plugin Info/image-20250530171732607.png b/docs/plugins/docs/1. Introduction/img/5. Viewing Plugin Info/image-20250530171732607.png new file mode 100644 index 0000000000000000000000000000000000000000..c63c5e4aab2499c74513c11e16862ff9947a8429 GIT binary patch literal 7039 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 Enable Plugins + + Viewing Plugin Info + Architecture diff --git a/docs/plugins/html/1. Introduction/2. Getting Started.html b/docs/plugins/html/1. Introduction/2. Getting Started.html index 9aea2dd..c15e0be 100644 --- a/docs/plugins/html/1. Introduction/2. Getting Started.html +++ b/docs/plugins/html/1. Introduction/2. Getting Started.html @@ -99,6 +99,9 @@ Enable Plugins + + Viewing Plugin Info + Architecture diff --git a/docs/plugins/html/1. Introduction/3. Installing Plugin.html b/docs/plugins/html/1. Introduction/3. Installing Plugin.html index 0a9c72b..3636ba4 100644 --- a/docs/plugins/html/1. Introduction/3. Installing Plugin.html +++ b/docs/plugins/html/1. Introduction/3. Installing Plugin.html @@ -99,6 +99,9 @@ Enable Plugins + + Viewing Plugin Info + Architecture diff --git a/docs/plugins/html/1. Introduction/4. Enable Plugins.html b/docs/plugins/html/1. Introduction/4. Enable Plugins.html index d1dc7ad..fa637f4 100644 --- a/docs/plugins/html/1. Introduction/4. Enable Plugins.html +++ b/docs/plugins/html/1. Introduction/4. Enable Plugins.html @@ -99,6 +99,9 @@ Enable Plugins + + Viewing Plugin Info + Architecture diff --git a/docs/plugins/html/1. Introduction/5. Viewing Plugin Info.html b/docs/plugins/html/1. Introduction/5. Viewing Plugin Info.html new file mode 100644 index 0000000..d354dda --- /dev/null +++ b/docs/plugins/html/1. Introduction/5. Viewing Plugin Info.html @@ -0,0 +1,203 @@ + + + + + + + + Viewing Plugin Info | Zoraxy Documentation + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ +
+
+
+

+ Viewing Plugin Info +

+

+

+ To view plugin information, you can click on the (i) icon in the plugin list. +

+

+

+

+ image-20250530171732607 +
+

+

+

+ Next, a side menu will pop up from the side. Here ,you can see the current Plugin information and runtime values including Working directories and runtime assigned port. +

+

+

+ If you are a developer (which you probably is considering you are reading this doc), you can click on the “developer insight” dropdown to show the capture paths registered by this plugin for debug purposes. +

+

+

+ image-20250530171724441 +
+

+
+
+
+
+
+
+
+
+
+
+
+
+ Zoraxy © tobychui + + 2025 + +
+
+
+ + + + \ No newline at end of file diff --git a/docs/plugins/html/1. Introduction/img/5. Viewing Plugin Info/image-20250530171724441.png b/docs/plugins/html/1. Introduction/img/5. Viewing Plugin Info/image-20250530171724441.png new file mode 100644 index 0000000000000000000000000000000000000000..cac42bb4ef86ad2a1a6ee8f4166a8f484933ebed GIT binary patch literal 47861 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 literal 0 HcmV?d00001 diff --git a/docs/plugins/html/1. Introduction/img/5. Viewing Plugin Info/image-20250530171732607.png b/docs/plugins/html/1. Introduction/img/5. Viewing Plugin Info/image-20250530171732607.png new file mode 100644 index 0000000000000000000000000000000000000000..c63c5e4aab2499c74513c11e16862ff9947a8429 GIT binary patch literal 7039 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 Enable Plugins + + Viewing Plugin Info + Architecture diff --git a/docs/plugins/html/2. Architecture/2. Introspect.html b/docs/plugins/html/2. Architecture/2. Introspect.html index 00c85b9..5b6904d 100644 --- a/docs/plugins/html/2. Architecture/2. Introspect.html +++ b/docs/plugins/html/2. Architecture/2. Introspect.html @@ -99,6 +99,9 @@ Enable Plugins + + Viewing Plugin Info + Architecture diff --git a/docs/plugins/html/2. Architecture/3. Configure.html b/docs/plugins/html/2. Architecture/3. Configure.html index d32694c..12b26c9 100644 --- a/docs/plugins/html/2. Architecture/3. Configure.html +++ b/docs/plugins/html/2. Architecture/3. Configure.html @@ -99,6 +99,9 @@ Enable Plugins + + Viewing Plugin Info + Architecture diff --git a/docs/plugins/html/2. Architecture/4. Capture Modes.html b/docs/plugins/html/2. Architecture/4. Capture Modes.html index 104ecf2..9420a3c 100644 --- a/docs/plugins/html/2. Architecture/4. Capture Modes.html +++ b/docs/plugins/html/2. Architecture/4. Capture Modes.html @@ -99,6 +99,9 @@ Enable Plugins + + Viewing Plugin Info + Architecture diff --git a/docs/plugins/html/2. Architecture/5. Plugin UI.html b/docs/plugins/html/2. Architecture/5. Plugin UI.html index 61debdb..6b81c60 100644 --- a/docs/plugins/html/2. Architecture/5. Plugin UI.html +++ b/docs/plugins/html/2. Architecture/5. Plugin UI.html @@ -99,6 +99,9 @@ Enable Plugins + + Viewing Plugin Info + Architecture diff --git a/docs/plugins/html/3. Basic Examples/1. Hello World.html b/docs/plugins/html/3. Basic Examples/1. Hello World.html index d1da632..7d58ba0 100644 --- a/docs/plugins/html/3. Basic Examples/1. Hello World.html +++ b/docs/plugins/html/3. Basic Examples/1. Hello World.html @@ -99,6 +99,9 @@ Enable Plugins + + Viewing Plugin Info + Architecture diff --git a/docs/plugins/html/3. Basic Examples/2. RESTful Example.html b/docs/plugins/html/3. Basic Examples/2. RESTful Example.html index e27a037..094994a 100644 --- a/docs/plugins/html/3. Basic Examples/2. RESTful Example.html +++ b/docs/plugins/html/3. Basic Examples/2. RESTful Example.html @@ -99,6 +99,9 @@ Enable Plugins + + Viewing Plugin Info + Architecture diff --git a/docs/plugins/html/3. Basic Examples/3. Static Capture Example.html b/docs/plugins/html/3. Basic Examples/3. Static Capture Example.html index c9897f6..eddfbf1 100644 --- a/docs/plugins/html/3. Basic Examples/3. Static Capture Example.html +++ b/docs/plugins/html/3. Basic Examples/3. Static Capture Example.html @@ -99,6 +99,9 @@ Enable Plugins + + Viewing Plugin Info + Architecture diff --git a/docs/plugins/html/index.html b/docs/plugins/html/index.html index 91d2215..8dc7832 100644 --- a/docs/plugins/html/index.html +++ b/docs/plugins/html/index.html @@ -99,6 +99,9 @@ Enable Plugins + + Viewing Plugin Info + Architecture diff --git a/docs/plugins/index.json b/docs/plugins/index.json index 6392c2f..ea09214 100644 --- a/docs/plugins/index.json +++ b/docs/plugins/index.json @@ -27,6 +27,11 @@ "filename": "1. Introduction/4. Enable Plugins.md", "title": "Enable Plugins", "type": "file" + }, + { + "filename": "1. Introduction/5. Viewing Plugin Info.md", + "title": "Viewing Plugin Info", + "type": "file" } ] }, diff --git a/example/plugins/static-capture-example/go.mod b/example/plugins/static-capture-example/go.mod new file mode 100644 index 0000000..5323b38 --- /dev/null +++ b/example/plugins/static-capture-example/go.mod @@ -0,0 +1,3 @@ +module example.com/zoraxy/static-capture-example + +go 1.23.6 diff --git a/example/plugins/static-capture-example/main.go b/example/plugins/static-capture-example/main.go new file mode 100644 index 0000000..f0f42d4 --- /dev/null +++ b/example/plugins/static-capture-example/main.go @@ -0,0 +1,107 @@ +package main + +import ( + "fmt" + "net/http" + "sort" + "strconv" + + plugin "example.com/zoraxy/static-capture-example/mod/zoraxy_plugin" +) + +const ( + PLUGIN_ID = "org.aroz.zoraxy.static-capture-example" + UI_PATH = "/ui" + STATIC_CAPTURE_INGRESS = "/s_capture" +) + +func main() { + // Serve the plugin intro spect + // This will print the plugin intro spect and exit if the -introspect flag is provided + runtimeCfg, err := plugin.ServeAndRecvSpec(&plugin.IntroSpect{ + ID: "org.aroz.zoraxy.static-capture-example", + Name: "Static Capture Example", + Author: "aroz.org", + AuthorContact: "https://aroz.org", + Description: "An example for showing how static capture works in Zoraxy.", + URL: "https://zoraxy.aroz.org", + Type: plugin.PluginType_Router, + VersionMajor: 1, + VersionMinor: 0, + VersionPatch: 0, + + StaticCapturePaths: []plugin.StaticCaptureRule{ + { + CapturePath: "/test_a", // This is the path that will be captured by the static capture handler + }, + { + CapturePath: "/test_b", // This is another path that will be captured by the static capture handler + }, + }, + StaticCaptureIngress: "/s_capture", // This is the ingress path for static capture requests + + UIPath: UI_PATH, + + /* + SubscriptionPath: "/subept", + SubscriptionsEvents: []plugin.SubscriptionEvent{ + */ + }) + if err != nil { + //Terminate or enter standalone mode here + panic(err) + } + + // Setup the path router + pathRouter := plugin.NewPathRouter() + //pathRouter.SetDebugPrintMode(true) + + /* + Static Routers + */ + pathRouter.RegisterPathHandler("/test_a", http.HandlerFunc(HandleCaptureA)) + pathRouter.RegisterPathHandler("/test_b", http.HandlerFunc(HandleCaptureB)) + pathRouter.SetDefaultHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // In theory this should never be called + // except when there is registered static path in Introspect but you don't create a handler for it (usually a mistake) + // but just in case the request is not captured by the path handlers + // this will be the fallback handler + w.Header().Set("Content-Type", "text/html") + w.Write([]byte("This request is captured by the default handler!
Request URI: " + r.URL.String())) + })) + pathRouter.RegisterStaticCaptureHandle(STATIC_CAPTURE_INGRESS, http.DefaultServeMux) + + // To simplify the example, we will use the default HTTP ServeMux + http.HandleFunc(UI_PATH+"/", RenderDebugUI) + fmt.Println("Static path capture example started at http://127.0.0.1:" + strconv.Itoa(runtimeCfg.Port)) + http.ListenAndServe("127.0.0.1:"+strconv.Itoa(runtimeCfg.Port), nil) +} + +// Handle the captured request +func HandleCaptureA(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "text/html") + w.Write([]byte("This request is captured by A handler!
Request URI: " + r.URL.String())) +} + +func HandleCaptureB(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "text/html") + w.Write([]byte("This request is captured by the B handler!
Request URI: " + r.URL.String())) +} + +// Render the debug UI +func RenderDebugUI(w http.ResponseWriter, r *http.Request) { + fmt.Fprint(w, "**Plugin UI Debug Interface**\n\n[Recv Headers] \n") + + headerKeys := make([]string, 0, len(r.Header)) + for name := range r.Header { + headerKeys = append(headerKeys, name) + } + sort.Strings(headerKeys) + for _, name := range headerKeys { + values := r.Header[name] + for _, value := range values { + fmt.Fprintf(w, "%s: %s\n", name, value) + } + } + w.Header().Set("Content-Type", "text/html") +} diff --git a/example/plugins/static-capture-example/mod/zoraxy_plugin/README.txt b/example/plugins/static-capture-example/mod/zoraxy_plugin/README.txt new file mode 100644 index 0000000..ed8a405 --- /dev/null +++ b/example/plugins/static-capture-example/mod/zoraxy_plugin/README.txt @@ -0,0 +1,19 @@ +# Zoraxy Plugin + +## Overview +This module serves as a template for building your own plugins for the Zoraxy Reverse Proxy. By copying this module to your plugin mod folder, you can create a new plugin with the necessary structure and components. + +## Instructions + +1. **Copy the Module:** + - Copy the entire `zoraxy_plugin` module to your plugin mod folder. + +2. **Include the Structure:** + - Ensure that you maintain the directory structure and file organization as provided in this module. + +3. **Modify as Needed:** + - Customize the copied module to implement the desired functionality for your plugin. + +## Directory Structure + zoraxy_plugin: Handle -introspect and -configuration process required for plugin loading and startup + embed_webserver: Handle embeded web server routing and injecting csrf token to your plugin served UI pages \ No newline at end of file diff --git a/example/plugins/static-capture-example/mod/zoraxy_plugin/dev_webserver.go b/example/plugins/static-capture-example/mod/zoraxy_plugin/dev_webserver.go new file mode 100644 index 0000000..9bed106 --- /dev/null +++ b/example/plugins/static-capture-example/mod/zoraxy_plugin/dev_webserver.go @@ -0,0 +1,145 @@ +package zoraxy_plugin + +import ( + "fmt" + "net/http" + "os" + "strings" + "time" +) + +type PluginUiDebugRouter struct { + PluginID string //The ID of the plugin + TargetDir string //The directory where the UI files are stored + HandlerPrefix string //The prefix of the handler used to route this router, e.g. /ui + EnableDebug bool //Enable debug mode + terminateHandler func() //The handler to be called when the plugin is terminated +} + +// NewPluginFileSystemUIRouter creates a new PluginUiRouter with file system +// The targetDir is the directory where the UI files are stored (e.g. ./www) +// The handlerPrefix is the prefix of the handler used to route this router +// The handlerPrefix should start with a slash (e.g. /ui) that matches the http.Handle path +// All prefix should not end with a slash +func NewPluginFileSystemUIRouter(pluginID string, targetDir string, handlerPrefix string) *PluginUiDebugRouter { + //Make sure all prefix are in /prefix format + if !strings.HasPrefix(handlerPrefix, "/") { + handlerPrefix = "/" + handlerPrefix + } + handlerPrefix = strings.TrimSuffix(handlerPrefix, "/") + + //Return the PluginUiRouter + return &PluginUiDebugRouter{ + PluginID: pluginID, + TargetDir: targetDir, + HandlerPrefix: handlerPrefix, + } +} + +func (p *PluginUiDebugRouter) populateCSRFToken(r *http.Request, fsHandler http.Handler) http.Handler { + //Get the CSRF token from header + csrfToken := r.Header.Get("X-Zoraxy-Csrf") + if csrfToken == "" { + csrfToken = "missing-csrf-token" + } + + //Return the middleware + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // Check if the request is for an HTML file + if strings.HasSuffix(r.URL.Path, ".html") { + //Read the target file from file system + targetFilePath := strings.TrimPrefix(r.URL.Path, "/") + targetFilePath = p.TargetDir + "/" + targetFilePath + targetFilePath = strings.TrimPrefix(targetFilePath, "/") + targetFileContent, err := os.ReadFile(targetFilePath) + if err != nil { + http.Error(w, "File not found", http.StatusNotFound) + return + } + body := string(targetFileContent) + body = strings.ReplaceAll(body, "{{.csrfToken}}", csrfToken) + w.Header().Set("Content-Type", "text/html") + w.WriteHeader(http.StatusOK) + w.Write([]byte(body)) + return + } else if strings.HasSuffix(r.URL.Path, "/") { + //Check if the request is for a directory + //Check if the directory has an index.html file + targetFilePath := strings.TrimPrefix(r.URL.Path, "/") + targetFilePath = p.TargetDir + "/" + targetFilePath + "index.html" + targetFilePath = strings.TrimPrefix(targetFilePath, "/") + if _, err := os.Stat(targetFilePath); err == nil { + //Serve the index.html file + targetFileContent, err := os.ReadFile(targetFilePath) + if err != nil { + http.Error(w, "File not found", http.StatusNotFound) + return + } + body := string(targetFileContent) + body = strings.ReplaceAll(body, "{{.csrfToken}}", csrfToken) + w.Header().Set("Content-Type", "text/html") + w.WriteHeader(http.StatusOK) + w.Write([]byte(body)) + return + } + } + + //Call the next handler + fsHandler.ServeHTTP(w, r) + }) + +} + +// GetHttpHandler returns the http.Handler for the PluginUiRouter +func (p *PluginUiDebugRouter) Handler() http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + //Remove the plugin UI handler path prefix + if p.EnableDebug { + fmt.Print("Request URL:", r.URL.Path, " rewriting to ") + } + + rewrittenURL := r.RequestURI + rewrittenURL = strings.TrimPrefix(rewrittenURL, p.HandlerPrefix) + rewrittenURL = strings.ReplaceAll(rewrittenURL, "//", "/") + r.URL.Path = rewrittenURL + r.RequestURI = rewrittenURL + if p.EnableDebug { + fmt.Println(r.URL.Path) + } + + //Serve the file from the file system + fsHandler := http.FileServer(http.Dir(p.TargetDir)) + + // Replace {{csrf_token}} with the actual CSRF token and serve the file + p.populateCSRFToken(r, fsHandler).ServeHTTP(w, r) + }) +} + +// RegisterTerminateHandler registers the terminate handler for the PluginUiRouter +// The terminate handler will be called when the plugin is terminated from Zoraxy plugin manager +// if mux is nil, the handler will be registered to http.DefaultServeMux +func (p *PluginUiDebugRouter) RegisterTerminateHandler(termFunc func(), mux *http.ServeMux) { + p.terminateHandler = termFunc + if mux == nil { + mux = http.DefaultServeMux + } + mux.HandleFunc(p.HandlerPrefix+"/term", func(w http.ResponseWriter, r *http.Request) { + p.terminateHandler() + w.WriteHeader(http.StatusOK) + go func() { + //Make sure the response is sent before the plugin is terminated + time.Sleep(100 * time.Millisecond) + os.Exit(0) + }() + }) +} + +// Attach the file system UI handler to the target http.ServeMux +func (p *PluginUiDebugRouter) AttachHandlerToMux(mux *http.ServeMux) { + if mux == nil { + mux = http.DefaultServeMux + } + + p.HandlerPrefix = strings.TrimSuffix(p.HandlerPrefix, "/") + mux.Handle(p.HandlerPrefix+"/", p.Handler()) +} diff --git a/example/plugins/static-capture-example/mod/zoraxy_plugin/dynamic_router.go b/example/plugins/static-capture-example/mod/zoraxy_plugin/dynamic_router.go new file mode 100644 index 0000000..1dc53ce --- /dev/null +++ b/example/plugins/static-capture-example/mod/zoraxy_plugin/dynamic_router.go @@ -0,0 +1,162 @@ +package zoraxy_plugin + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + "strings" +) + +/* + + Dynamic Path Handler + +*/ + +type SniffResult int + +const ( + SniffResultAccpet SniffResult = iota // Forward the request to this plugin dynamic capture ingress + SniffResultSkip // Skip this plugin and let the next plugin handle the request +) + +type SniffHandler func(*DynamicSniffForwardRequest) SniffResult + +/* +RegisterDynamicSniffHandler registers a dynamic sniff handler for a path +You can decide to accept or skip the request based on the request header and paths +*/ +func (p *PathRouter) RegisterDynamicSniffHandler(sniff_ingress string, mux *http.ServeMux, handler SniffHandler) { + if !strings.HasSuffix(sniff_ingress, "/") { + sniff_ingress = sniff_ingress + "/" + } + mux.Handle(sniff_ingress, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if p.enableDebugPrint { + fmt.Println("Request captured by dynamic sniff path: " + r.RequestURI) + } + + // Decode the request payload + jsonBytes, err := io.ReadAll(r.Body) + if err != nil { + if p.enableDebugPrint { + fmt.Println("Error reading request body:", err) + } + http.Error(w, "Internal Server Error", http.StatusInternalServerError) + return + } + payload, err := DecodeForwardRequestPayload(jsonBytes) + if err != nil { + if p.enableDebugPrint { + fmt.Println("Error decoding request payload:", err) + fmt.Print("Payload: ") + fmt.Println(string(jsonBytes)) + } + http.Error(w, "Internal Server Error", http.StatusInternalServerError) + return + } + + // Get the forwarded request UUID + forwardUUID := r.Header.Get("X-Zoraxy-RequestID") + payload.requestUUID = forwardUUID + payload.rawRequest = r + + sniffResult := handler(&payload) + if sniffResult == SniffResultAccpet { + w.WriteHeader(http.StatusOK) + w.Write([]byte("OK")) + } else { + w.WriteHeader(http.StatusNotImplemented) + w.Write([]byte("SKIP")) + } + })) +} + +// RegisterDynamicCaptureHandle register the dynamic capture ingress path with a handler +func (p *PathRouter) RegisterDynamicCaptureHandle(capture_ingress string, mux *http.ServeMux, handlefunc func(http.ResponseWriter, *http.Request)) { + if !strings.HasSuffix(capture_ingress, "/") { + capture_ingress = capture_ingress + "/" + } + mux.Handle(capture_ingress, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if p.enableDebugPrint { + fmt.Println("Request captured by dynamic capture path: " + r.RequestURI) + } + + rewrittenURL := r.RequestURI + rewrittenURL = strings.TrimPrefix(rewrittenURL, capture_ingress) + rewrittenURL = strings.ReplaceAll(rewrittenURL, "//", "/") + if rewrittenURL == "" { + rewrittenURL = "/" + } + if !strings.HasPrefix(rewrittenURL, "/") { + rewrittenURL = "/" + rewrittenURL + } + r.RequestURI = rewrittenURL + + handlefunc(w, r) + })) +} + +/* + Sniffing and forwarding + + The following functions are here to help with + sniffing and forwarding requests to the dynamic + router. +*/ +// A custom request object to be used in the dynamic sniffing +type DynamicSniffForwardRequest struct { + Method string `json:"method"` + Hostname string `json:"hostname"` + URL string `json:"url"` + Header map[string][]string `json:"header"` + RemoteAddr string `json:"remote_addr"` + Host string `json:"host"` + RequestURI string `json:"request_uri"` + Proto string `json:"proto"` + ProtoMajor int `json:"proto_major"` + ProtoMinor int `json:"proto_minor"` + + /* Internal use */ + rawRequest *http.Request `json:"-"` + requestUUID string `json:"-"` +} + +// GetForwardRequestPayload returns a DynamicSniffForwardRequest object from an http.Request object +func EncodeForwardRequestPayload(r *http.Request) DynamicSniffForwardRequest { + return DynamicSniffForwardRequest{ + Method: r.Method, + Hostname: r.Host, + URL: r.URL.String(), + Header: r.Header, + RemoteAddr: r.RemoteAddr, + Host: r.Host, + RequestURI: r.RequestURI, + Proto: r.Proto, + ProtoMajor: r.ProtoMajor, + ProtoMinor: r.ProtoMinor, + rawRequest: r, + } +} + +// DecodeForwardRequestPayload decodes JSON bytes into a DynamicSniffForwardRequest object +func DecodeForwardRequestPayload(jsonBytes []byte) (DynamicSniffForwardRequest, error) { + var payload DynamicSniffForwardRequest + err := json.Unmarshal(jsonBytes, &payload) + if err != nil { + return DynamicSniffForwardRequest{}, err + } + return payload, nil +} + +// GetRequest returns the original http.Request object, for debugging purposes +func (dsfr *DynamicSniffForwardRequest) GetRequest() *http.Request { + return dsfr.rawRequest +} + +// GetRequestUUID returns the request UUID +// if this UUID is empty string, that might indicate the request +// is not coming from the dynamic router +func (dsfr *DynamicSniffForwardRequest) GetRequestUUID() string { + return dsfr.requestUUID +} diff --git a/example/plugins/static-capture-example/mod/zoraxy_plugin/embed_webserver.go b/example/plugins/static-capture-example/mod/zoraxy_plugin/embed_webserver.go new file mode 100644 index 0000000..b68b417 --- /dev/null +++ b/example/plugins/static-capture-example/mod/zoraxy_plugin/embed_webserver.go @@ -0,0 +1,174 @@ +package zoraxy_plugin + +import ( + "embed" + "fmt" + "io/fs" + "net/http" + "net/url" + "os" + "strings" + "time" +) + +type PluginUiRouter struct { + PluginID string //The ID of the plugin + TargetFs *embed.FS //The embed.FS where the UI files are stored + TargetFsPrefix string //The prefix of the embed.FS where the UI files are stored, e.g. /web + HandlerPrefix string //The prefix of the handler used to route this router, e.g. /ui + EnableDebug bool //Enable debug mode + terminateHandler func() //The handler to be called when the plugin is terminated +} + +// NewPluginEmbedUIRouter creates a new PluginUiRouter with embed.FS +// The targetFsPrefix is the prefix of the embed.FS where the UI files are stored +// The targetFsPrefix should be relative to the root of the embed.FS +// The targetFsPrefix should start with a slash (e.g. /web) that corresponds to the root folder of the embed.FS +// The handlerPrefix is the prefix of the handler used to route this router +// The handlerPrefix should start with a slash (e.g. /ui) that matches the http.Handle path +// All prefix should not end with a slash +func NewPluginEmbedUIRouter(pluginID string, targetFs *embed.FS, targetFsPrefix string, handlerPrefix string) *PluginUiRouter { + //Make sure all prefix are in /prefix format + if !strings.HasPrefix(targetFsPrefix, "/") { + targetFsPrefix = "/" + targetFsPrefix + } + targetFsPrefix = strings.TrimSuffix(targetFsPrefix, "/") + + if !strings.HasPrefix(handlerPrefix, "/") { + handlerPrefix = "/" + handlerPrefix + } + handlerPrefix = strings.TrimSuffix(handlerPrefix, "/") + + //Return the PluginUiRouter + return &PluginUiRouter{ + PluginID: pluginID, + TargetFs: targetFs, + TargetFsPrefix: targetFsPrefix, + HandlerPrefix: handlerPrefix, + } +} + +func (p *PluginUiRouter) populateCSRFToken(r *http.Request, fsHandler http.Handler) http.Handler { + //Get the CSRF token from header + csrfToken := r.Header.Get("X-Zoraxy-Csrf") + if csrfToken == "" { + csrfToken = "missing-csrf-token" + } + + //Return the middleware + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // Check if the request is for an HTML file + if strings.HasSuffix(r.URL.Path, ".html") { + //Read the target file from embed.FS + targetFilePath := strings.TrimPrefix(r.URL.Path, "/") + targetFilePath = p.TargetFsPrefix + "/" + targetFilePath + targetFilePath = strings.TrimPrefix(targetFilePath, "/") + targetFileContent, err := fs.ReadFile(*p.TargetFs, targetFilePath) + if err != nil { + http.Error(w, "File not found", http.StatusNotFound) + return + } + body := string(targetFileContent) + body = strings.ReplaceAll(body, "{{.csrfToken}}", csrfToken) + w.Header().Set("Content-Type", "text/html") + w.WriteHeader(http.StatusOK) + w.Write([]byte(body)) + return + } else if strings.HasSuffix(r.URL.Path, "/") { + // Check if the directory has an index.html file + indexFilePath := strings.TrimPrefix(r.URL.Path, "/") + "index.html" + indexFilePath = p.TargetFsPrefix + "/" + indexFilePath + indexFilePath = strings.TrimPrefix(indexFilePath, "/") + indexFileContent, err := fs.ReadFile(*p.TargetFs, indexFilePath) + if err == nil { + body := string(indexFileContent) + body = strings.ReplaceAll(body, "{{.csrfToken}}", csrfToken) + w.Header().Set("Content-Type", "text/html") + w.WriteHeader(http.StatusOK) + w.Write([]byte(body)) + return + } + } + + //Call the next handler + fsHandler.ServeHTTP(w, r) + }) + +} + +// GetHttpHandler returns the http.Handler for the PluginUiRouter +func (p *PluginUiRouter) Handler() http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + //Remove the plugin UI handler path prefix + if p.EnableDebug { + fmt.Print("Request URL:", r.URL.Path, " rewriting to ") + } + + rewrittenURL := r.RequestURI + rewrittenURL = strings.TrimPrefix(rewrittenURL, p.HandlerPrefix) + rewrittenURL = strings.ReplaceAll(rewrittenURL, "//", "/") + r.URL, _ = url.Parse(rewrittenURL) + r.RequestURI = rewrittenURL + if p.EnableDebug { + fmt.Println(r.URL.Path) + } + + //Serve the file from the embed.FS + subFS, err := fs.Sub(*p.TargetFs, strings.TrimPrefix(p.TargetFsPrefix, "/")) + if err != nil { + fmt.Println(err.Error()) + http.Error(w, "Internal Server Error", http.StatusInternalServerError) + return + } + + // Replace {{csrf_token}} with the actual CSRF token and serve the file + p.populateCSRFToken(r, http.FileServer(http.FS(subFS))).ServeHTTP(w, r) + }) +} + +// RegisterTerminateHandler registers the terminate handler for the PluginUiRouter +// The terminate handler will be called when the plugin is terminated from Zoraxy plugin manager +// if mux is nil, the handler will be registered to http.DefaultServeMux +func (p *PluginUiRouter) RegisterTerminateHandler(termFunc func(), mux *http.ServeMux) { + p.terminateHandler = termFunc + if mux == nil { + mux = http.DefaultServeMux + } + mux.HandleFunc(p.HandlerPrefix+"/term", func(w http.ResponseWriter, r *http.Request) { + p.terminateHandler() + w.WriteHeader(http.StatusOK) + go func() { + //Make sure the response is sent before the plugin is terminated + time.Sleep(100 * time.Millisecond) + os.Exit(0) + }() + }) +} + +// HandleFunc registers a handler function for the given pattern +// The pattern should start with the handler prefix, e.g. /ui/hello +// If the pattern does not start with the handler prefix, it will be prepended with the handler prefix +func (p *PluginUiRouter) HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request), mux *http.ServeMux) { + // If mux is nil, use the default ServeMux + if mux == nil { + mux = http.DefaultServeMux + } + + // Make sure the pattern starts with the handler prefix + if !strings.HasPrefix(pattern, p.HandlerPrefix) { + pattern = p.HandlerPrefix + pattern + } + + // Register the handler with the http.ServeMux + mux.HandleFunc(pattern, handler) +} + +// Attach the embed UI handler to the target http.ServeMux +func (p *PluginUiRouter) AttachHandlerToMux(mux *http.ServeMux) { + if mux == nil { + mux = http.DefaultServeMux + } + + p.HandlerPrefix = strings.TrimSuffix(p.HandlerPrefix, "/") + mux.Handle(p.HandlerPrefix+"/", p.Handler()) +} diff --git a/example/plugins/static-capture-example/mod/zoraxy_plugin/static_router.go b/example/plugins/static-capture-example/mod/zoraxy_plugin/static_router.go new file mode 100644 index 0000000..f4abcb7 --- /dev/null +++ b/example/plugins/static-capture-example/mod/zoraxy_plugin/static_router.go @@ -0,0 +1,105 @@ +package zoraxy_plugin + +import ( + "fmt" + "net/http" + "sort" + "strings" +) + +type PathRouter struct { + enableDebugPrint bool + pathHandlers map[string]http.Handler + defaultHandler http.Handler +} + +// NewPathRouter creates a new PathRouter +func NewPathRouter() *PathRouter { + return &PathRouter{ + enableDebugPrint: false, + pathHandlers: make(map[string]http.Handler), + } +} + +// RegisterPathHandler registers a handler for a path +func (p *PathRouter) RegisterPathHandler(path string, handler http.Handler) { + path = strings.TrimSuffix(path, "/") + p.pathHandlers[path] = handler +} + +// RemovePathHandler removes a handler for a path +func (p *PathRouter) RemovePathHandler(path string) { + delete(p.pathHandlers, path) +} + +// SetDefaultHandler sets the default handler for the router +// This handler will be called if no path handler is found +func (p *PathRouter) SetDefaultHandler(handler http.Handler) { + p.defaultHandler = handler +} + +// SetDebugPrintMode sets the debug print mode +func (p *PathRouter) SetDebugPrintMode(enable bool) { + p.enableDebugPrint = enable +} + +// StartStaticCapture starts the static capture ingress +func (p *PathRouter) RegisterStaticCaptureHandle(capture_ingress string, mux *http.ServeMux) { + if !strings.HasSuffix(capture_ingress, "/") { + capture_ingress = capture_ingress + "/" + } + mux.Handle(capture_ingress, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + p.staticCaptureServeHTTP(w, r) + })) +} + +// staticCaptureServeHTTP serves the static capture path using user defined handler +func (p *PathRouter) staticCaptureServeHTTP(w http.ResponseWriter, r *http.Request) { + capturePath := r.Header.Get("X-Zoraxy-Capture") + if capturePath != "" { + if p.enableDebugPrint { + fmt.Printf("Using capture path: %s\n", capturePath) + } + originalURI := r.Header.Get("X-Zoraxy-Uri") + r.URL.Path = originalURI + if handler, ok := p.pathHandlers[capturePath]; ok { + handler.ServeHTTP(w, r) + return + } + } + p.defaultHandler.ServeHTTP(w, r) +} + +func (p *PathRouter) PrintRequestDebugMessage(r *http.Request) { + if p.enableDebugPrint { + fmt.Printf("Capture Request with path: %s \n\n**Request Headers** \n\n", r.URL.Path) + keys := make([]string, 0, len(r.Header)) + for key := range r.Header { + keys = append(keys, key) + } + sort.Strings(keys) + for _, key := range keys { + for _, value := range r.Header[key] { + fmt.Printf("%s: %s\n", key, value) + } + } + + fmt.Printf("\n\n**Request Details**\n\n") + fmt.Printf("Method: %s\n", r.Method) + fmt.Printf("URL: %s\n", r.URL.String()) + fmt.Printf("Proto: %s\n", r.Proto) + fmt.Printf("Host: %s\n", r.Host) + fmt.Printf("RemoteAddr: %s\n", r.RemoteAddr) + fmt.Printf("RequestURI: %s\n", r.RequestURI) + fmt.Printf("ContentLength: %d\n", r.ContentLength) + fmt.Printf("TransferEncoding: %v\n", r.TransferEncoding) + fmt.Printf("Close: %v\n", r.Close) + fmt.Printf("Form: %v\n", r.Form) + fmt.Printf("PostForm: %v\n", r.PostForm) + fmt.Printf("MultipartForm: %v\n", r.MultipartForm) + fmt.Printf("Trailer: %v\n", r.Trailer) + fmt.Printf("RemoteAddr: %s\n", r.RemoteAddr) + fmt.Printf("RequestURI: %s\n", r.RequestURI) + + } +} diff --git a/example/plugins/static-capture-example/mod/zoraxy_plugin/zoraxy_plugin.go b/example/plugins/static-capture-example/mod/zoraxy_plugin/zoraxy_plugin.go new file mode 100644 index 0000000..737e928 --- /dev/null +++ b/example/plugins/static-capture-example/mod/zoraxy_plugin/zoraxy_plugin.go @@ -0,0 +1,176 @@ +package zoraxy_plugin + +import ( + "encoding/json" + "fmt" + "os" + "strings" +) + +/* + Plugins Includes.go + + This file is copied from Zoraxy source code + You can always find the latest version under mod/plugins/includes.go + Usually this file are backward compatible +*/ + +type PluginType int + +const ( + PluginType_Router PluginType = 0 //Router Plugin, used for handling / routing / forwarding traffic + PluginType_Utilities PluginType = 1 //Utilities Plugin, used for utilities like Zerotier or Static Web Server that do not require interception with the dpcore +) + +type StaticCaptureRule struct { + CapturePath string `json:"capture_path"` + //To be expanded +} + +type ControlStatusCode int + +const ( + ControlStatusCode_CAPTURED ControlStatusCode = 280 //Traffic captured by plugin, ask Zoraxy not to process the traffic + ControlStatusCode_UNHANDLED ControlStatusCode = 284 //Traffic not handled by plugin, ask Zoraxy to process the traffic + ControlStatusCode_ERROR ControlStatusCode = 580 //Error occurred while processing the traffic, ask Zoraxy to process the traffic and log the error +) + +type SubscriptionEvent struct { + EventName string `json:"event_name"` + EventSource string `json:"event_source"` + Payload string `json:"payload"` //Payload of the event, can be empty +} + +type RuntimeConstantValue struct { + ZoraxyVersion string `json:"zoraxy_version"` + ZoraxyUUID string `json:"zoraxy_uuid"` + DevelopmentBuild bool `json:"development_build"` //Whether the Zoraxy is a development build or not +} + +/* +IntroSpect Payload + +When the plugin is initialized with -introspect flag, +the plugin shell return this payload as JSON and exit +*/ +type IntroSpect struct { + /* Plugin metadata */ + ID string `json:"id"` //Unique ID of your plugin, recommended using your own domain in reverse like com.yourdomain.pluginname + Name string `json:"name"` //Name of your plugin + Author string `json:"author"` //Author name of your plugin + AuthorContact string `json:"author_contact"` //Author contact of your plugin, like email + Description string `json:"description"` //Description of your plugin + URL string `json:"url"` //URL of your plugin + Type PluginType `json:"type"` //Type of your plugin, Router(0) or Utilities(1) + VersionMajor int `json:"version_major"` //Major version of your plugin + VersionMinor int `json:"version_minor"` //Minor version of your plugin + VersionPatch int `json:"version_patch"` //Patch version of your plugin + + /* + + Endpoint Settings + + */ + + /* + Static Capture Settings + + Once plugin is enabled these rules always applies to the enabled HTTP Proxy rule + This is faster than dynamic capture, but less flexible + */ + StaticCapturePaths []StaticCaptureRule `json:"static_capture_paths"` //Static capture paths of your plugin, see Zoraxy documentation for more details + StaticCaptureIngress string `json:"static_capture_ingress"` //Static capture ingress path of your plugin (e.g. /s_handler) + + /* + Dynamic Capture Settings + + Once plugin is enabled, these rules will be captured and forward to plugin sniff + if the plugin sniff returns 280, the traffic will be captured + otherwise, the traffic will be forwarded to the next plugin + This is slower than static capture, but more flexible + */ + DynamicCaptureSniff string `json:"dynamic_capture_sniff"` //Dynamic capture sniff path of your plugin (e.g. /d_sniff) + DynamicCaptureIngress string `json:"dynamic_capture_ingress"` //Dynamic capture ingress path of your plugin (e.g. /d_handler) + + /* UI Path for your plugin */ + UIPath string `json:"ui_path"` //UI path of your plugin (e.g. /ui), will proxy the whole subpath tree to Zoraxy Web UI as plugin UI + + /* Subscriptions Settings */ + SubscriptionPath string `json:"subscription_path"` //Subscription event path of your plugin (e.g. /notifyme), a POST request with SubscriptionEvent as body will be sent to this path when the event is triggered + SubscriptionsEvents map[string]string `json:"subscriptions_events"` //Subscriptions events of your plugin, see Zoraxy documentation for more details +} + +/* +ServeIntroSpect Function + +This function will check if the plugin is initialized with -introspect flag, +if so, it will print the intro spect and exit + +Place this function at the beginning of your plugin main function +*/ +func ServeIntroSpect(pluginSpect *IntroSpect) { + if len(os.Args) > 1 && os.Args[1] == "-introspect" { + //Print the intro spect and exit + jsonData, _ := json.MarshalIndent(pluginSpect, "", " ") + fmt.Println(string(jsonData)) + os.Exit(0) + } +} + +/* +ConfigureSpec Payload + +Zoraxy will start your plugin with -configure flag, +the plugin shell read this payload as JSON and configure itself +by the supplied values like starting a web server at given port +that listens to 127.0.0.1:port +*/ +type ConfigureSpec struct { + Port int `json:"port"` //Port to listen + RuntimeConst RuntimeConstantValue `json:"runtime_const"` //Runtime constant values + //To be expanded +} + +/* +RecvExecuteConfigureSpec Function + +This function will read the configure spec from Zoraxy +and return the ConfigureSpec object + +Place this function after ServeIntroSpect function in your plugin main function +*/ +func RecvConfigureSpec() (*ConfigureSpec, error) { + for i, arg := range os.Args { + if strings.HasPrefix(arg, "-configure=") { + var configSpec ConfigureSpec + if err := json.Unmarshal([]byte(arg[11:]), &configSpec); err != nil { + return nil, err + } + return &configSpec, nil + } else if arg == "-configure" { + var configSpec ConfigureSpec + var nextArg string + if len(os.Args) > i+1 { + nextArg = os.Args[i+1] + if err := json.Unmarshal([]byte(nextArg), &configSpec); err != nil { + return nil, err + } + } else { + return nil, fmt.Errorf("No port specified after -configure flag") + } + return &configSpec, nil + } + } + return nil, fmt.Errorf("No -configure flag found") +} + +/* +ServeAndRecvSpec Function + +This function will serve the intro spect and return the configure spec +See the ServeIntroSpect and RecvConfigureSpec for more details +*/ +func ServeAndRecvSpec(pluginSpect *IntroSpect) (*ConfigureSpec, error) { + ServeIntroSpect(pluginSpect) + return RecvConfigureSpec() +} diff --git a/example/plugins/static-capture-example/ui_info.go b/example/plugins/static-capture-example/ui_info.go new file mode 100644 index 0000000..6522496 --- /dev/null +++ b/example/plugins/static-capture-example/ui_info.go @@ -0,0 +1,5 @@ +package main + +import ( + _ "embed" +)