diff --git a/README.md b/README.md index de488a3..e7a3fcc 100644 --- a/README.md +++ b/README.md @@ -90,7 +90,7 @@ services: --providers.docker=true --providers.docker.network=default --experimental.plugins.captcha-protect.modulename=github.com/libops/captcha-protect - --experimental.plugins.captcha-protect.version=v1.12.4 + --experimental.plugins.captcha-protect.version=v1.12.5 volumes: - /var/run/docker.sock:/var/run/docker.sock:z - /CHANGEME/TO/A/HOST/PATH/FOR/STATE/FILE:/tmp/state.json:rw @@ -130,7 +130,7 @@ services: | `protectFileExtensions` | `[]string` | `""` | Comma-separated file extensions to protect. By default, your protected routes only protect html files. This is to prevent files like CSS/JS/img from tripping the rate limit. | | `protectHttpMethods` | `[]string` | `"GET,HEAD"` | Comma-separated list of HTTP methods to protect against | | `exemptIps` | `[]string` | `privateIPs` | CIDR-formatted IPs that should never be challenged. Private IP ranges are always exempt. | -| `exemptUserAgents` | `[]string` | `""` | Comma-separated list of case-insensitive user agent **prefixes** to never challenge. e.g. `exemptUserAgents: edge` would never challenge useragents like "Edge/12.4 ..." | +| `exemptUserAgents` | `[]string` | `""` | Comma-separated list of case-insensitive user agent substrings to never challenge. For example, `exemptUserAgents: YandexBot` exempts user agents containing `YandexBot`. | | `challengeURL` | `string` | `"/challenge"` | URL where challenges are served. This will override existing routes if there is a conflict. Setting to blank will have the challenge presented on the same page that tripped the rate limit. | | `challengeTmpl` | `string` | `"./challenge.tmpl.html"`| Path to the Go HTML template for the captcha challenge page. | | `challengeStatusCode` | `int` | `200` | HTTP Response status code to return when serving a challenge | diff --git a/main.go b/main.go index ee98bb3..62129d4 100644 --- a/main.go +++ b/main.go @@ -858,8 +858,8 @@ protected: func (bc *CaptchaProtect) isGoodUserAgent(ua string) bool { ua = strings.ToLower(ua) - for _, agentPrefix := range bc.config.ExemptUserAgents { - if strings.HasPrefix(ua, agentPrefix) { + for _, agentSubstring := range bc.config.ExemptUserAgents { + if strings.Contains(ua, agentSubstring) { return true } } diff --git a/main_test.go b/main_test.go index 6fee6e6..3930b71 100644 --- a/main_test.go +++ b/main_test.go @@ -615,10 +615,11 @@ func TestIsGoodUserAgent(t *testing.T) { ua string expected bool }{ - {"Matching first prefix", []string{"Mozilla", "Google"}, "Mozilla/5.0 (Windows NT 10.0; Win64; x64)", true}, - {"Matching second prefix", []string{"Bing", "Edge"}, "Edge/12.0", true}, + {"Matching first substring", []string{"Mozilla", "Google"}, "Mozilla/5.0 (Windows NT 10.0; Win64; x64)", true}, + {"Matching second substring", []string{"Bing", "Edge"}, "Edge/12.0", true}, + {"Matching substring within user agent", []string{"YandexBot"}, "Mozilla/5.0 (compatible; YandexBot/3.0; +http://yandex.com/bots)", true}, {"Case insensitive", []string{"bing", "Edge"}, "BING/12.0", true}, - {"No matching prefix", []string{"Mozilla", "Google"}, "Safari/537.36", false}, + {"No matching substring", []string{"Mozilla", "Google"}, "Safari/537.36", false}, {"Empty user agent", []string{"Mozilla", "Google"}, "", false}, {"Empty exempt list", []string{}, "Mozilla/5.0", false}, }