{"id":30694574,"url":"https://github.com/4nkitd/gatekeeper","last_synced_at":"2025-09-02T06:42:28.830Z","repository":{"id":296443064,"uuid":"993387825","full_name":"4nkitd/gatekeeper","owner":"4nkitd","description":"Enhance the security and control of your web applications","archived":false,"fork":false,"pushed_at":"2025-05-30T18:46:16.000Z","size":70,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-08-29T22:48:21.879Z","etag":null,"topics":["blacklist","firewall","golang","ip","profanity","referer","whitelist"],"latest_commit_sha":null,"homepage":"https://4nkitd.github.io/gatekeeper/","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/4nkitd.png","metadata":{"files":{"readme":"Readme.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-05-30T17:48:14.000Z","updated_at":"2025-07-24T20:49:08.000Z","dependencies_parsed_at":"2025-05-31T03:15:24.172Z","dependency_job_id":"2e58b6af-3958-4cac-8b37-e9409bbc2e69","html_url":"https://github.com/4nkitd/gatekeeper","commit_stats":null,"previous_names":["4nkitd/gatekeeper"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/4nkitd/gatekeeper","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/4nkitd%2Fgatekeeper","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/4nkitd%2Fgatekeeper/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/4nkitd%2Fgatekeeper/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/4nkitd%2Fgatekeeper/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/4nkitd","download_url":"https://codeload.github.com/4nkitd/gatekeeper/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/4nkitd%2Fgatekeeper/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273244304,"owners_count":25070958,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-02T02:00:09.530Z","response_time":77,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["blacklist","firewall","golang","ip","profanity","referer","whitelist"],"created_at":"2025-09-02T06:42:26.509Z","updated_at":"2025-09-02T06:42:28.811Z","avatar_url":"https://github.com/4nkitd.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Gatekeeper: HTTP Middleware for Go Security and Control\n\nGatekeeper is a flexible and performant Go middleware library designed to enhance the security and control of your web applications. It offers seamless integration with the standard `net/http` library and popular Go web frameworks, providing essential security features out-of-the-box.\n\n## Features\n\nGatekeeper provides five key security and control features:\n\n1.  **User-Agent Blacklisting/Whitelisting:**\n    *   **Purpose:** Block or allow requests based on the `User-Agent` header.\n    *   **Configuration:** Define lists of exact User-Agent strings or regular expression patterns. Operates in `BLACKLIST` (block if matched) or `WHITELIST` (allow only if matched) mode.\n\n2.  **IP Address Blacklisting/Whitelisting:**\n    *   **Purpose:** Control access based on client IP address.\n    *   **Configuration:** Define lists of individual IP addresses or CIDR ranges. Operates in `BLACKLIST` or `WHITELIST` mode. Supports trusting `X-Forwarded-For` / `X-Real-IP` headers from configured trusted proxies.\n\n3.  **Referer Blacklisting/Whitelisting:**\n    *   **Purpose:** Control access based on the HTTP `Referer` header to prevent hotlinking, block malicious referrers, or enforce HTTPS.\n    *   **Configuration:** Define lists of exact Referer URLs or regular expression patterns. Operates in `BLACKLIST` (block if matched) or `WHITELIST` (allow only if matched) mode.\n    *   **Use Cases:** Block spam domains, enforce HTTPS-only referers, prevent hotlinking, block known phishing sites.\n\n4.  **IP Address Rate Limiting (with Exceptions):**\n    *   **Purpose:** Prevent abuse and brute-force attacks by limiting request rates per IP.\n    *   **Configuration:** Define requests per period (e.g., 100 requests/minute).\n    *   **Storage:** Defaults to an in-memory store (suitable for single instances). Pluggable `RateLimiterStore` interface allows for custom backends (e.g., Redis, Memcached) for distributed environments.\n    *   **Exceptions:** Whitelist specific IPs/CIDRs or URL route patterns to bypass or have different rate limits.\n\n5.  **Profanity Firewall (with Whitelisting):**\n    *   **Purpose:** Filter requests containing undesirable language.\n    *   **Configuration:** Define lists of profane words/phrases and a whitelist of words to ignore (e.g., \"Scunthorpe\").\n    *   **Scope:** Can check query parameters, form data (urlencoded/multipart), and JSON request bodies.\n\n## Installation\n\n```bash\ngo get github.com/4nkitd/gatekeeper\n```\n\n## Quick Start Examples\n\n### Standard Library (`net/http`)\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n\t\"time\"\n\n\t\"github.com/4nkitd/gatekeeper\"\n\t\"github.com/4nkitd/gatekeeper/store\"\n)\n\nfunc main() {\n\t// Configure Gatekeeper\n\tgk, err := gatekeeper.New(gatekeeper.Config{\n\t\tIPPolicy: \u0026gatekeeper.IPPolicyConfig{\n\t\t\tMode:  gatekeeper.ModeBlacklist,\n\t\t\tIPs:   []string{\"1.2.3.4\"},         // Block this specific IP\n\t\t\tCIDRs: []string{\"192.168.100.0/24\"}, // Block this CIDR range\n\t\t},\n\t\tUserAgentPolicy: \u0026gatekeeper.UserAgentPolicyConfig{\n\t\t\tMode:     gatekeeper.ModeBlacklist,\n\t\t\tPatterns: []string{`^curl/.*`, `(?i)^.*bot.*$`}, // Block curl and bots\n\t\t},\n\t\tRefererPolicy: \u0026gatekeeper.RefererPolicyConfig{\n\t\t\tMode: gatekeeper.ModeBlacklist,\n\t\t\tExact: []string{\"http://malicious-site.com\"},\n\t\t\tPatterns: []string{`(?i).*evil\\.com.*`, `^http://.*`}, // Block evil.com and non-HTTPS\n\t\t},\n\t\tRateLimiter: \u0026gatekeeper.RateLimiterConfig{\n\t\t\tRequests: 60,\n\t\t\tPeriod:   1 * time.Minute, // 60 requests per minute per IP\n\t\t\tStore:    store.NewMemoryStore(5 * time.Minute),\n\t\t\tExceptions: \u0026gatekeeper.RateLimiterExceptions{\n\t\t\t\tIPWhitelist:            []string{\"127.0.0.1\", \"::1\"}, // Localhost bypasses rate limiting\n\t\t\t\tRouteWhitelistPatterns: []string{`^/health$`},         // Health endpoint exempt\n\t\t\t},\n\t\t},\n\t\tProfanityFilter: \u0026gatekeeper.ProfanityFilterConfig{\n\t\t\tBlockWords:       []string{\"badword\", \"spam\", \"offensive\"},\n\t\t\tAllowWords:       []string{\"scunthorpe\"}, // Avoid false positives\n\t\t\tCheckQueryParams: true,\n\t\t\tCheckFormFields:  true,\n\t\t\tCheckJSONBody:    true,\n\t\t},\n\t\tDefaultBlockStatusCode: http.StatusForbidden,\n\t\tDefaultBlockMessage:    \"Access denied by security policy\",\n\t})\n\tif err != nil {\n\t\tlog.Fatalf(\"Failed to initialize Gatekeeper: %v\", err)\n\t}\n\n\t// Your main handler\n\tmyHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\t\tfmt.Fprintln(w, \"Hello, you've passed Gatekeeper!\")\n\t})\n\n\t// Apply all configured Gatekeeper protections\n\tprotectedHandler := gk.Protect(myHandler)\n\n\thttp.Handle(\"/\", protectedHandler)\n\n\tlog.Println(\"Server starting on :8080...\")\n\tif err := http.ListenAndServe(\":8080\", nil); err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n\n### Echo Framework\n\n```go\npackage main\n\nimport (\n\t\"net/http\"\n\t\"time\"\n\n\t\"github.com/4nkitd/gatekeeper\"\n\t\"github.com/4nkitd/gatekeeper/store\"\n\t\"github.com/labstack/echo/v4\"\n\t\"github.com/labstack/echo/v4/middleware\"\n)\n\nfunc main() {\n\te := echo.New()\n\n\t// Configure Gatekeeper with comprehensive security\n\tconfig := gatekeeper.Config{\n\t\tIPPolicy: \u0026gatekeeper.IPPolicyConfig{\n\t\t\tMode:  gatekeeper.ModeBlacklist,\n\t\t\tIPs:   []string{\"1.2.3.4\", \"5.6.7.8\"},\n\t\t\tCIDRs: []string{\"192.168.100.0/24\"},\n\t\t},\n\t\tUserAgentPolicy: \u0026gatekeeper.UserAgentPolicyConfig{\n\t\t\tMode: gatekeeper.ModeBlacklist,\n\t\t\tExact: []string{\"BadBot/1.0\", \"EvilScraper/2.0\"},\n\t\t\tPatterns: []string{\n\t\t\t\t`^curl/.*`,               // Block curl\n\t\t\t\t`(?i)^.*bot.*scanner.*$`, // Block bot scanners\n\t\t\t\t`(?i)^.*scraper.*$`,      // Block scrapers\n\t\t\t},\n\t\t},\n\t\tRateLimiter: \u0026gatekeeper.RateLimiterConfig{\n\t\t\tRequests: 60,\n\t\t\tPeriod:   1 * time.Minute,\n\t\t\tStore:    store.NewMemoryStore(5 * time.Minute),\n\t\t\tExceptions: \u0026gatekeeper.RateLimiterExceptions{\n\t\t\t\tIPWhitelist: []string{\"127.0.0.1\", \"::1\"},\n\t\t\t\tRouteWhitelistPatterns: []string{\n\t\t\t\t\t`^/health$`,   // Health checks\n\t\t\t\t\t`^/metrics$`,  // Monitoring\n\t\t\t\t\t`^/static/.*`, // Static assets\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tProfanityFilter: \u0026gatekeeper.ProfanityFilterConfig{\n\t\t\tBlockWords:       []string{\"badword\", \"spam\", \"offensive\"},\n\t\t\tCheckQueryParams: true,\n\t\t\tCheckFormFields:  true,\n\t\t\tCheckJSONBody:    true,\n\t\t},\n\t\tDefaultBlockStatusCode: http.StatusForbidden,\n\t\tDefaultBlockMessage:    \"Access denied by security policy\",\n\t}\n\n\t// Apply Gatekeeper middleware\n\tgk, err := gatekeeper.New(config)\n\tif err != nil {\n\t\te.Logger.Fatal(\"Failed to initialize Gatekeeper: \", err)\n\t}\n\te.Use(gk.EchoMiddleware())\n\n\t// Add other Echo middleware\n\te.Use(middleware.Logger())\n\te.Use(middleware.Recover())\n\n\t// Define routes\n\te.GET(\"/\", func(c echo.Context) error {\n\t\treturn c.JSON(http.StatusOK, map[string]string{\n\t\t\t\"message\": \"Welcome! You passed all security checks.\",\n\t\t})\n\t})\n\n\te.GET(\"/health\", func(c echo.Context) error {\n\t\treturn c.JSON(http.StatusOK, map[string]string{\n\t\t\t\"status\": \"healthy\",\n\t\t})\n\t})\n\n\te.Logger.Fatal(e.Start(\":8080\"))\n}\n```\n\n## Supported Frameworks\n\nGatekeeper provides built-in middleware support for popular Go web frameworks:\n\n### Echo Framework (Built-in Support)\n\nGatekeeper provides native Echo middleware support with two convenient methods:\n\n**Method 1: Create instance then use middleware**\n```go\nimport (\n    \"github.com/4nkitd/gatekeeper\"\n    \"github.com/labstack/echo/v4\"\n)\n\nfunc main() {\n    e := echo.New()\n    \n    // Create Gatekeeper instance\n    gk, err := gatekeeper.New(config)\n    if err != nil {\n        log.Fatal(err)\n    }\n    \n    // Apply middleware\n    e.Use(gk.EchoMiddleware())\n    \n    // Your routes...\n}\n```\n\n**Method 2: One-step creation**\n```go\nfunc main() {\n    e := echo.New()\n    \n    // Create and apply middleware in one step\n    middleware, err := gatekeeper.EchoMiddlewareFromConfig(config)\n    if err != nil {\n        log.Fatal(err)\n    }\n    e.Use(middleware)\n    \n    // Your routes...\n}\n```\n\n### Other Frameworks\n\n*   **`net/http`** (Standard Library): Use `gk.Protect(handler)` or individual policies\n*   **Gin**: Use `gk.Protect()` with Gin's `WrapH()` function\n*   **Fiber**: Use `gk.Protect()` with Fiber's `adaptor.HTTPHandler()`\n*   **Chi**: Compatible with standard `net/http` middleware using `gk.Protect()`\n\nFor complete Echo example, see `example/echo.go` in the repository.\n\n## Configuration Options\n\nGatekeeper is configured using the `gatekeeper.Config` struct passed to `gatekeeper.New()`.\n\n```go\ntype Config struct {\n    UserAgentPolicy *UserAgentPolicyConfig\n    IPPolicy        *IPPolicyConfig\n    RateLimiter     *RateLimiterConfig\n    ProfanityFilter *ProfanityFilterConfig\n\n    Logger                 *log.Logger // Optional: Custom logger\n    DefaultBlockStatusCode int         // Optional: Defaults to 403 Forbidden\n    DefaultBlockMessage    string      // Optional: Defaults to \"Forbidden\"\n}\n```\n\n### User-Agent Policy (`UserAgentPolicyConfig`)\n\n*   `Mode`: `gatekeeper.ModeBlacklist` or `gatekeeper.ModeWhitelist`.\n*   `Exact`: `[]string` of exact User-Agent strings (case-insensitive match).\n*   `Patterns`: `[]string` of regular expressions to match User-Agents (case-sensitive by default, use `(?i)` in regex for insensitivity).\n\n### IP Policy (`IPPolicyConfig`)\n\n*   `Mode`: `gatekeeper.ModeBlacklist` or `gatekeeper.ModeWhitelist`.\n*   `IPs`: `[]string` of individual IP addresses (e.g., \"1.2.3.4\").\n*   `CIDRs`: `[]string` of IP ranges in CIDR notation (e.g., \"10.0.0.0/8\").\n*   `TrustProxyHeaders`: `bool` (default `false`). If `true`, attempts to get client IP from `X-Forwarded-For` or `X-Real-IP`.\n*   `TrustedProxies`: `[]string` of trusted proxy IPs/CIDRs. If `TrustProxyHeaders` is true, headers are only trusted if the direct connection is from one of these proxies. If empty and `TrustProxyHeaders` is true, headers from private IPs are typically trusted.\n\n### Rate Limiter (`RateLimiterConfig`)\n\n*   `Requests`: `int64` - Maximum number of requests allowed.\n*   `Period`: `time.Duration` - The time window for the request limit (e.g., `1 * time.Minute`).\n*   `Store`: `store.RateLimiterStore` - Storage backend. Defaults to `store.NewMemoryStore()` if not provided.\n*   `LimitExceededMessage`: `string` (defaults to \"Rate limit exceeded. Please slow down!\").\n*   `LimitExceededStatusCode`: `int` (defaults to `http.StatusTooManyRequests`).\n*   `Exceptions`: `*RateLimiterExceptions`\n    *   `IPWhitelist`: `[]string` of IPs/CIDRs exempt from rate limiting.\n    *   `RouteWhitelistPatterns`: `[]string` of regex patterns for URL paths exempt from rate limiting (e.g., `^/health$`, `^/static/.*`).\n\n### Profanity Filter (`ProfanityFilterConfig`)\n\n*   `BlockWords`: `[]string` of words/phrases to block (case-insensitive).\n*   `AllowWords`: `[]string` of words/phrases to explicitly allow, helping avoid false positives (e.g., \"scunthorpe\" problem).\n*   `CheckQueryParams`: `bool` - Scan URL query parameters for profanity.\n*   `CheckFormFields`: `bool` - Scan `application/x-www-form-urlencoded` and `multipart/form-data` fields.\n*   `CheckJSONBody`: `bool` - Scan JSON request bodies for profanity.\n*   `BlockedMessage`: `string` (defaults to \"Content contains inappropriate language\").\n*   `BlockedStatusCode`: `int` (defaults to `http.StatusBadRequest`).\n\n## Rate Limiter Store\n\nThe rate limiter uses an in-memory store by default (`store.NewMemoryStore()`). For distributed systems, you can implement the `store.RateLimiterStore` interface using a shared backend like Redis or Memcached.\n\n```go\npackage store\n\ntype RateLimiterStore interface {\n    Allow(key string, limit int64, window time.Duration) (allowed bool, retryAfter time.Duration, err error)\n    Cleanup() // Optional, for stores that need explicit cleanup\n}\n```\n\nExample custom store implementation:\n```go\n// RedisStore implements RateLimiterStore using Redis\ntype RedisStore struct {\n    client *redis.Client\n}\n\nfunc (r *RedisStore) Allow(key string, limit int64, window time.Duration) (bool, time.Duration, error) {\n    // Implement sliding window rate limiting using Redis\n    // Return whether request is allowed and retry-after duration\n}\n```\n\n## Advanced Usage\n\n### Individual Policy Application\n\nYou can apply policies individually instead of using `gk.Protect()`:\n\n```go\nhandler := myHandler\nif gk.ConfiguredIPPolicy() {\n    handler = gk.IPPolicy(handler)\n}\nif gk.ConfiguredUserAgentPolicy() {\n    handler = gk.UserAgentPolicy(handler)\n}\nif gk.ConfiguredRateLimiter() {\n    handler = gk.RateLimit(handler)\n}\nif gk.ConfiguredProfanityFilter() {\n    handler = gk.ProfanityPolicy(handler)\n}\n```\n\n### Framework Integration Examples\n\n**Gin Framework:**\n```go\nimport \"github.com/gin-gonic/gin\"\n\nr := gin.Default()\ngk, _ := gatekeeper.New(config)\nr.Use(gin.WrapH(gk.Protect(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n    // This will be called for each request that passes Gatekeeper\n}))))\n```\n\n**Fiber Framework:**\n```go\nimport \"github.com/gofiber/fiber/v2/middleware/adaptor\"\n\napp := fiber.New()\ngk, _ := gatekeeper.New(config)\napp.Use(adaptor.HTTPMiddleware(gk.Protect))\n```\n\n### Testing Gatekeeper Policies\n\n```bash\n# Test User-Agent blocking\ncurl -H \"User-Agent: curl/7.68.0\" http://localhost:8080/\n# Expected: Access denied by security policy\n\n# Test with allowed User-Agent\ncurl -H \"User-Agent: Chrome/91.0\" http://localhost:8080/\n# Expected: Normal response\n\n# Test rate limiting (run multiple times quickly)\nfor i in {1..70}; do curl -s http://localhost:8080/ \u003e/dev/null; done\ncurl http://localhost:8080/\n# Expected: Rate limit exceeded after 60 requests\n\n# Test profanity filter\ncurl -X POST -d \"message=badword\" http://localhost:8080/api/submit\n# Expected: Content contains inappropriate language\n```\n\n## Order of Middleware Execution\n\nWhen using `gk.Protect(handler)`, the middleware is applied in the following default order (from outermost to innermost):\n\n1.  IP Policy - First line of defense, blocks malicious IPs\n2.  User-Agent Policy - Blocks bots and scrapers  \n3.  Rate Limiter - Prevents abuse and DDoS attacks\n4.  Profanity Filter - Content moderation (innermost, closest to your handler)\n\nThis order ensures maximum security efficiency - cheaper checks (IP, User-Agent) happen before more expensive ones (rate limiting, content scanning).\n\n## Logging\n\nGatekeeper uses the standard `log` package by default, prefixed with `[Gatekeeper]`. You can provide your own `*log.Logger` instance in `gatekeeper.Config.Logger`.\n\nExample logs:\n```\n[Gatekeeper] Request blocked: GET /api/data from 1.2.3.4. Reason: IP address in blacklist\n[Gatekeeper] Request blocked: POST /submit from 10.0.0.1. Reason: User-Agent 'curl/7.68.0' matches blocked pattern\n[Gatekeeper] Request blocked: GET /api/data from 127.0.0.1. Reason: Rate limit exceeded (60 requests/minute)\n[Gatekeeper] Request blocked: POST /comment from 192.168.1.100. Reason: Profanity detected in request body\n```\n\n## Contributing\n\nContributions are welcome! Please feel free to submit issues, fork the repository, and send pull requests.\n\n1.  Fork the repository.\n2.  Create your feature branch (`git checkout -b feature/my-new-feature`).\n3.  Commit your changes (`git commit -am 'Add some feature'`).\n4.  Push to the branch (`git push origin feature/my-new-feature`).\n5.  Create a new Pull Request.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F4nkitd%2Fgatekeeper","html_url":"https://awesome.ecosyste.ms/projects/github.com%2F4nkitd%2Fgatekeeper","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F4nkitd%2Fgatekeeper/lists"}