From 7221feb6d4ee6817a5a788664b68ca0a59e1633c Mon Sep 17 00:00:00 2001 From: db123-test Date: Mon, 4 May 2026 11:29:01 +0330 Subject: [PATCH] feat: add permanent whitelist list endpoint and rename DB table - Add GET /api/whitelist/perm/list to list permanent whitelisted entries - Implement permWhitelistListHandler with API key verification - Rename permanent_whitelist table to perm_whitelist for consistency - Update default DB path from ./data to /data - Comment out build job in CI/CD workflow --- .github/workflows/ci-cd.yml | 30 +++++++++++++++--------------- README.md | 1 + auth.go | 16 ++++++++++++++++ config.go | 2 +- db.go | 30 +++++++++++++++++++++++++----- docker-compose.yml | 4 +--- docs/api.md | 17 +++++++++++++++++ main.go | 1 + openapi.yaml | 28 +++++++++++++++++++++++++++- 9 files changed, 104 insertions(+), 25 deletions(-) diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index bae471f..87b9063 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -28,24 +28,24 @@ jobs: exit 1 fi - build: - name: Build binaries - runs-on: shell-ubuntu - needs: lint-and-format - steps: - - name: Checkout repo - run: git clone "${{ secrets.G_CLONE_URL }}" . + # build: + # name: Build binaries + # runs-on: shell-ubuntu + # needs: lint-and-format + # steps: + # - name: Checkout repo + # run: git clone "${{ secrets.G_CLONE_URL }}" . - - name: Build for Linux amd64 - run: CGO_ENABLED=0 GOOS=linux GOARCH=amd64 /usr/local/go/bin/go build -o auth-proxy-linux-amd64 . + # - name: Build for Linux amd64 + # run: CGO_ENABLED=0 GOOS=linux GOARCH=amd64 /usr/local/go/bin/go build -o auth-proxy-linux-amd64 . - - name: Build for Windows amd64 - run: CGO_ENABLED=0 GOOS=windows GOARCH=amd64 /usr/local/go/bin/go build -o auth-proxy-windows-amd64.exe + # - name: Build for Windows amd64 + # run: CGO_ENABLED=0 GOOS=windows GOARCH=amd64 /usr/local/go/bin/go build -o auth-proxy-windows-amd64.exe - - name: Package binaries - run: | - tar czf auth-proxy-linux-amd64.tar.gz auth-proxy-linux-amd64 - tar czf auth-proxy-windows-amd64.tar.gz auth-proxy-windows-amd64.exe + # - name: Package binaries + # run: | + # tar czf auth-proxy-linux-amd64.tar.gz auth-proxy-linux-amd64 + # tar czf auth-proxy-windows-amd64.tar.gz auth-proxy-windows-amd64.exe docker: name: Build & push Docker image diff --git a/README.md b/README.md index b3692bc..74add28 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,7 @@ The API requires a bearer token set via `AUTH_PROXY_API_TOKEN`. All endpoints re | GET | `/api/whitelist/temp/list` | List active temporary entries | | DELETE | `/api/whitelist/temp/{ip}` | Remove a temporary entry | | POST | `/api/whitelist/perm` | Add a permanent whitelisted IP/CIDR | +| GET | `/api/whitelist/perm/list` | List active permanent entries | | DELETE | `/api/whitelist/perm/{entry}` | Remove a permanent entry | | GET | `/api/logs` | Retrieve audit log entries | | GET | `/status` | Health check | diff --git a/auth.go b/auth.go index 0632655..b50670d 100644 --- a/auth.go +++ b/auth.go @@ -86,6 +86,22 @@ func whitelistListHandler(cfg Config, db *sql.DB) http.HandlerFunc { } } +func permWhitelistListHandler(cfg Config, db *sql.DB) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + if !verifyAPIKey(r, cfg.APIToken) { + http.Error(w, "unauthorized", http.StatusUnauthorized) + return + } + entries, err := ListPermEntries(db) + if err != nil { + http.Error(w, "database error", http.StatusInternalServerError) + return + } + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(entries) + } +} + func whitelistDeleteHandler(cfg Config, db *sql.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if !verifyAPIKey(r, cfg.APIToken) { diff --git a/config.go b/config.go index 3c9d60f..a1fa025 100644 --- a/config.go +++ b/config.go @@ -19,7 +19,7 @@ func loadConfig() Config { APIToken: getEnv("AUTH_PROXY_API_TOKEN", ""), DataDir: getEnv("DATA_DIR", "/data"), CleanupInterval: parseDuration("CLEANUP_INTERVAL", 60*time.Second), - DBPath: getEnv("AUTH_PROXY_DB_PATH", "./data/auth-proxy.db"), + DBPath: getEnv("AUTH_PROXY_DB_PATH", "/data/auth-proxy.db"), } } diff --git a/db.go b/db.go index 2faa013..280baf8 100644 --- a/db.go +++ b/db.go @@ -21,7 +21,7 @@ func InitDB(dbPath string) (*sql.DB, error) { } schema := ` - CREATE TABLE IF NOT EXISTS permanent_whitelist ( + CREATE TABLE IF NOT EXISTS perm_whitelist ( id INTEGER PRIMARY KEY AUTOINCREMENT, entry TEXT NOT NULL UNIQUE, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP @@ -56,7 +56,7 @@ func InitDB(dbPath string) (*sql.DB, error) { } func AddPermanentEntry(db *sql.DB, entry, apiClientIP string) (bool, error) { - _, err := db.Exec(`INSERT INTO permanent_whitelist(entry) VALUES(?)`, entry) + _, err := db.Exec(`INSERT INTO perm_whitelist(entry) VALUES(?)`, entry) if err != nil { if isUniqueConstraintError(err) { return false, nil @@ -68,7 +68,7 @@ func AddPermanentEntry(db *sql.DB, entry, apiClientIP string) (bool, error) { } func DeletePermanentEntry(db *sql.DB, entry, apiClientIP string) error { - res, err := db.Exec(`DELETE FROM permanent_whitelist WHERE entry = ?`, entry) + res, err := db.Exec(`DELETE FROM perm_whitelist WHERE entry = ?`, entry) if err != nil { return err } @@ -80,7 +80,7 @@ func DeletePermanentEntry(db *sql.DB, entry, apiClientIP string) error { } func IsPermanentWhitelisted(db *sql.DB, ip string) (bool, error) { - rows, err := db.Query(`SELECT entry FROM permanent_whitelist`) + rows, err := db.Query(`SELECT entry FROM perm_whitelist`) if err != nil { return false, err } @@ -189,6 +189,26 @@ func ListTempEntries(db *sql.DB) ([]map[string]interface{}, error) { return list, nil } +func ListPermEntries(db *sql.DB) ([]map[string]interface{}, error) { + rows, err := db.Query(`SELECT ip FROM perm_whitelist ORDER BY ip`) + if err != nil { + return nil, err + } + defer rows.Close() + var list []map[string]interface{} + for rows.Next() { + var ip, reason string + var expiresAt time.Time + if err := rows.Scan(&ip, &expiresAt, &reason); err != nil { + continue + } + list = append(list, map[string]interface{}{ + "ip": ip, + }) + } + return list, nil +} + func ipMatchesEntry(ip, entry string) (bool, error) { if entry == ip { return true, nil @@ -221,5 +241,5 @@ func isUniqueConstraintError(err error) bool { if err == nil { return false } - return err.Error() == "UNIQUE constraint failed: permanent_whitelist.entry" + return err.Error() == "UNIQUE constraint failed: perm_whitelist.entry" } diff --git a/docker-compose.yml b/docker-compose.yml index cb87214..e8cb265 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -14,10 +14,8 @@ services: environment: AUTH_PROXY_PORT: "8080" AUTH_PROXY_API_TOKEN: "${AUTH_PROXY_API_TOKEN:-CHANGE_ME}" - AUTH_PROXY_BASIC_USER: "${AUTH_PROXY_BASIC_USER:-admin}" - AUTH_PROXY_BASIC_PASSWORD: "${AUTH_PROXY_BASIC_PASSWORD:-CHANGE_ME}" - PERMANENT_WHITELIST_FILE: "/config/permanent_whitelist.txt" DATA_DIR: "/data" + AUTH_PROXY_DB_PATH: "/data/auth-proxy.db" volumes: - ./config/permanent_whitelist.txt:/config/permanent_whitelist.txt:ro - auth-data:/data diff --git a/docs/api.md b/docs/api.md index 6604ab8..eeaa6e4 100644 --- a/docs/api.md +++ b/docs/api.md @@ -80,6 +80,23 @@ curl -X POST http://127.0.0.1:8080/api/whitelist/perm \ -d '{"entry":"203.0.113.10"}' ``` +### GET /api/whitelist/perm/list + +List all currently active permanent whitelisted IPs. + +**Authorization:** Bearer `{API_TOKEN}` + +**Response body:** + +```json +[ + { + "ip": "1.2.3.4", + "reason": "my laptop", + } +] +``` + ### DELETE /api/whitelist/perm/{entry} Remove a permanent whitelisted IP or CIDR range. diff --git a/main.go b/main.go index b1ad51a..a8dae62 100644 --- a/main.go +++ b/main.go @@ -30,6 +30,7 @@ func main() { mux.HandleFunc("/api/whitelist/temp/list", whitelistListHandler(cfg, db)) mux.HandleFunc("/api/whitelist/temp/{ip}", whitelistDeleteHandler(cfg, db)) mux.HandleFunc("/api/whitelist/perm", permWhitelistAddHandler(cfg, db)) + mux.HandleFunc("/api/whitelist/perm/list", permWhitelistListHandler(cfg, db)) mux.HandleFunc("/api/whitelist/perm/{entry}", permWhitelistDeleteHandler(cfg, db)) mux.HandleFunc("/api/logs", logsHandler(cfg, db)) mux.HandleFunc("/status", statusHandler) diff --git a/openapi.yaml b/openapi.yaml index 4b0f5f2..7b8a2bb 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -74,7 +74,7 @@ paths: ip: type: string description: The IP address to whitelist - example: "203.0.113.10" + example: "1.2.3.4" ttl_seconds: type: integer description: Time-to-live in seconds @@ -185,6 +185,32 @@ paths: example: "entry already exists" '500': description: Internal error + + /api/whitelist/perm/list: + get: + summary: List permanent whitelisted IPs + description: List all currently active permanent whitelisted IPs. + operationId: listTempWhitelist + responses: + '200': + description: List of permanent whitelisted IPs + content: + application/json: + schema: + type: array + items: + type: object + properties: + ip: + type: string + example: "1.2.3.4" + reason: + type: string + example: "my laptop" + '401': + description: Unauthorized — invalid API token + '500': + description: Internal error — database failure /api/whitelist/perm/{entry}: delete: