From dc3cf78468f8ecbc9143a50dbab98941bbfb8b62 Mon Sep 17 00:00:00 2001 From: ReLoia Date: Fri, 26 Jun 2026 10:44:37 +0200 Subject: [PATCH] shit: slopped from bun into a (I hope) light go shit --- .gitea/workflows/docker.yml | 40 ++++++++++++ Dockerfile | 23 +++++++ go.mod | 3 + main.go | 126 ++++++++++++++++++++++++++++++++++++ 4 files changed, 192 insertions(+) create mode 100644 .gitea/workflows/docker.yml create mode 100644 Dockerfile create mode 100644 go.mod create mode 100644 main.go diff --git a/.gitea/workflows/docker.yml b/.gitea/workflows/docker.yml new file mode 100644 index 0000000..9b1e4cf --- /dev/null +++ b/.gitea/workflows/docker.yml @@ -0,0 +1,40 @@ +name: Build and Publish Docker Image + +on: + push: + branches: + - main + +env: + REGISTRY: git.reloia.uk + IMAGE_NAME: ${{ github.repository }} + +jobs: + build-and-push: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to Gitea Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + + password: ${{ secrets.LOGIN_TOKEN }} + + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: . + push: true + + platforms: linux/arm64 + tags: | + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..cd802f4 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,23 @@ +FROM --platform=$BUILDPLATFORM golang:1.22-alpine AS builder + +ARG TARGETOS +ARG TARGETARCH + +WORKDIR /app + +COPY go.mod ./ +COPY main.go ./ + +RUN CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -o debugghttpy . + +FROM scratch +LABEL authors="reloia" + +WORKDIR /app + +COPY --from=builder /app/debugghttpy . + +ENV PORT=3000 +ENV DOMAIN="*" + +CMD ["./debugghttpy"] \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..ff8b7a3 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module debugghttpy + +go 1.26 diff --git a/main.go b/main.go new file mode 100644 index 0000000..349ebf7 --- /dev/null +++ b/main.go @@ -0,0 +1,126 @@ +package debugghttpy + +import ( + "encoding/json" + "fmt" + "log" + "net" + "net/http" + "os" + "strings" +) + +func main() { + port := os.Getenv("PORT") + if port == "" { + port = "3000" + } + allowedOrigin := os.Getenv("DOMAIN") + if allowedOrigin == "" { + allowedOrigin = "*" + } + + http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Access-Control-Allow-Origin", allowedOrigin) + + // Handle CORS preflight (OPTIONS) requests + if r.Method == http.MethodOptions { + w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, PATCH, OPTIONS") + w.Header().Set("Access-Control-Allow-Headers", "*") + w.WriteHeader(http.StatusNoContent) + return + } + + w.Header().Set("Content-Type", "application/json") + + // Parse raw socket info + ip, portStr, err := net.SplitHostPort(r.RemoteAddr) + if err != nil { + ip = r.RemoteAddr + portStr = "unknown" + } + family := "IPv4" + if strings.Contains(ip, ":") { + family = "IPv6" + } + + // Flatten headers to a simple map and lowercase the keys + headers := make(map[string]string) + for k, v := range r.Header { + headers[strings.ToLower(k)] = strings.Join(v, ", ") + } + + // Flatten search params + searchParams := make(map[string]string) + for k, v := range r.URL.Query() { + searchParams[k] = v[0] + } + + // Handle Cookies logic + var cookiesData interface{} + if r.URL.Query().Has("cookies") { + cookiesMap := make(map[string]string) + for _, c := range r.Cookies() { + cookiesMap[c.Name] = c.Value + } + cookiesData = cookiesMap + } else { + cookiesData = "disabled, add ?cookies to query to see cookies" + // Explicitly remove the Cookie header from the headers map so it doesn't leak + delete(headers, "cookie") + } + + // Additional Statistics + tlsInfo := "none" + if r.TLS != nil { + tlsInfo = fmt.Sprintf("TLS (Version: %x)", r.TLS.Version) + } + + // Helper to return nil if string is empty + getValOrNil := func(val string) interface{} { + if val == "" { + return nil + } + return val + } + + // Build the JSON response + debugInfo := map[string]interface{}{ + "app": "debugghttpy", + "rawSocket": map[string]interface{}{ + "ip": ip, + "family": family, + "port": portStr, + }, + "request": map[string]interface{}{ + "method": r.Method, + "url": r.URL.RequestURI(), + "pathname": r.URL.Path, + "searchParams": searchParams, + "protocol": r.Proto, + "host": r.Host, + "contentLength": r.ContentLength, + "tls": tlsInfo, + }, + "quickIps": map[string]interface{}{ + "x-forwarded-for": getValOrNil(headers["x-forwarded-for"]), + "x-real-ip": getValOrNil(headers["x-real-ip"]), + "cf-connecting-ip": getValOrNil(headers["cf-connecting-ip"]), + "true-client-ip": getValOrNil(headers["true-client-ip"]), + }, + "headers": headers, + "cookies": cookiesData, + } + + // Encode and write JSON + enc := json.NewEncoder(w) + enc.SetIndent("", " ") + if err := enc.Encode(debugInfo); err != nil { + log.Printf("Error encoding JSON: %v", err) + } + }) + + log.Printf("🚀 debugghttpy listening on port %s\n", port) + log.Printf("🔒 CORS Allowed Origin: %s\n", allowedOrigin) + log.Fatal(http.ListenAndServe(":"+port, nil)) +}