From aeb3b62b6451a3f075ba954919f5de19ead83872 Mon Sep 17 00:00:00 2001 From: jbergner Date: Mon, 16 Jun 2025 22:26:33 +0200 Subject: [PATCH] RC1 --- .gitea/workflows/register.yml | 51 +++++++++++++++++++++++++++++++++++ Dockerfile | 26 ++++++++++++++++++ main.go | 49 ++++++++++++++++++++++++++++++--- 3 files changed, 122 insertions(+), 4 deletions(-) create mode 100644 .gitea/workflows/register.yml create mode 100644 Dockerfile diff --git a/.gitea/workflows/register.yml b/.gitea/workflows/register.yml new file mode 100644 index 0000000..20912ac --- /dev/null +++ b/.gitea/workflows/register.yml @@ -0,0 +1,51 @@ +name: release-tag +on: + push: + branches: + - 'main' +jobs: + release-image: + runs-on: ubuntu-fast + env: + DOCKER_ORG: ${{ vars.DOCKER_ORG }} + DOCKER_LATEST: latest + RUNNER_TOOL_CACHE: /toolcache + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + + - name: Set up Docker BuildX + uses: docker/setup-buildx-action@v2 + with: # replace it with your local IP + config-inline: | + [registry."${{ vars.DOCKER_REGISTRY }}"] + http = true + insecure = true + + - name: Login to DockerHub + uses: docker/login-action@v2 + with: + registry: ${{ vars.DOCKER_REGISTRY }} # replace it with your local IP + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Get Meta + id: meta + run: | + echo REPO_NAME=$(echo ${GITHUB_REPOSITORY} | awk -F"/" '{print $2}') >> $GITHUB_OUTPUT + echo REPO_VERSION=$(git describe --tags --always | sed 's/^v//') >> $GITHUB_OUTPUT + + - name: Build and push + uses: docker/build-push-action@v4 + with: + context: . + file: ./Dockerfile + platforms: | + linux/amd64 + push: true + tags: | # replace it with your local IP and tags + ${{ vars.DOCKER_REGISTRY }}/${{ env.DOCKER_ORG }}/${{ steps.meta.outputs.REPO_NAME }}:${{ steps.meta.outputs.REPO_VERSION }} + ${{ vars.DOCKER_REGISTRY }}/${{ env.DOCKER_ORG }}/${{ steps.meta.outputs.REPO_NAME }}:${{ env.DOCKER_LATEST }} \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..d314191 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,26 @@ +# -------- Dockerfile (Multi-Stage Build) -------- +# 1. Builder-Stage +FROM golang:1.24-alpine AS builder + +WORKDIR /app +COPY go.* ./ +RUN go mod download +COPY . . +RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o /bin/ipblock-api + +# 2. Runtime-Stage +FROM alpine:3.20 + +# HTTPS-Callouts in Alpine brauchen ca-certificates +RUN apk add --no-cache ca-certificates + +COPY --from=builder /bin/ipblock-api /bin/ipblock-api + +# Default listens on :8080 – siehe main.go +EXPOSE 8080 + +# Environment defaults; können per compose überschrieben werden +ENV REDIS_ADDR=redis:6379 \ + TTL_HOURS=720 + +ENTRYPOINT ["/bin/ipblock-api"] diff --git a/main.go b/main.go index e1f0e0d..89244fa 100644 --- a/main.go +++ b/main.go @@ -24,6 +24,7 @@ package main import ( "bufio" + "encoding/json" "flag" "fmt" "io" @@ -577,17 +578,18 @@ type target struct { const ( indexTemplateHTML = ` -IPv64 Blocklists +IP Blocklists -

IPv64 Blocklists

-

Es sind {{len .Files}} Dateien verfügbar (letztes Update: {{.Updated}}).

+

IP Blocklists

+

There are {{len .Files}} files available (last Update: {{.Updated}}).

- + {{range .Files}} {{end}}
DateiGrößeZuletzt geändert
FileRow CountLast Changed
{{.Name}}{{.Size}}{{.ModTime}}
+

/lists.json - Full list as JSON

` ) @@ -647,6 +649,16 @@ func main() { tmpl.Execute(w, data) }) + // JSON API – /lists.json + http.HandleFunc("/lists.json", func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json; charset=utf-8") + enc := json.NewEncoder(w) + enc.SetIndent("", " ") + if err := enc.Encode(defaultLists); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + } + }) + log.Printf("HTTP server listening on %s, serving %s", *listenAddr, *outDir) log.Fatal(http.ListenAndServe(*listenAddr, nil)) } @@ -722,6 +734,35 @@ func fetchAndSave(client *http.Client, t target, outDir string) error { return os.Rename(tmp, dst) } +// ────────────────────────────────────────────────────────────────────────────── +// Helpers +// ────────────────────────────────────────────────────────────────────────────── +// ExportListJSON schreibt die Map als prettified JSON‑Datei. +func ExportListJSON(path string, m map[string]string) error { + f, err := os.Create(path) + if err != nil { + return err + } + defer f.Close() + enc := json.NewEncoder(f) + enc.SetIndent("", " ") + return enc.Encode(m) +} + +// ImportListJSON liest eine JSON‑Datei und gibt map[string]string zurück. +func ImportListJSON(path string) (map[string]string, error) { + f, err := os.Open(path) + if err != nil { + return nil, err + } + defer f.Close() + var m map[string]string + if err := json.NewDecoder(f).Decode(&m); err != nil { + return nil, err + } + return m, nil +} + // buildIndexData assembles a directory listing for the /index route. func buildIndexData(dir string) (struct { Files []fileInfo