Documentation
¶
Overview ¶
Package botdetect provides bot, crawler, and malicious-traffic detection for HTTP requests, plus an optional blocking middleware.
Detection is split into pure, request-agnostic functions (Detect, DetectRequest, IsBot, IsBotPath, IsMaliciousPath, IsReferrerSpam, IsDataCenterIP) so the verdicts can be reused from middleware, ingestion pipelines, or batch jobs.
Index ¶
- Constants
- func BotPathPatterns() []string
- func IsBot(userAgent string) bool
- func IsBotPath(path string) bool
- func IsDataCenterIP(ip string) bool
- func IsMaliciousPath(path string) bool
- func IsReferrerSpam(referrer string) bool
- func MaliciousPathPatterns() []string
- type BotClass
- type Detection
- type UserAgentInfo
Constants ¶
const ( OsMacOS = "macos" OsIOS = "ios" )
OS names returned by ParseUserAgent.
const ( DeviceIPhone = "iphone" DeviceIPad = "ipad" DeviceIPod = "ipod" )
Device names returned by ParseUserAgent.
const ( DeviceTypeDesktop = "desktop" DeviceTypeMobile = "mobile" DeviceTypeTablet = "tablet" DeviceTypeTV = "tv" )
Device types returned by ParseUserAgent in UserAgentInfo.DeviceType.
const Bot = "bot"
Bot is the value uasurfer-derived fields (DeviceType, Browser, Device) take when the user-agent is classified as a bot.
const (
BrowserEdge = "edge"
)
Browser names returned by ParseUserAgent. All values are lowercase — display formatting (e.g. "macos" → "macOS") is left to consumers.
Variables ¶
This section is empty.
Functions ¶
func BotPathPatterns ¶
func BotPathPatterns() []string
BotPathPatterns returns the list of path substrings for bot-only files (robots.txt, ads.txt, sitemap.xml, etc.) that legitimate crawlers request but no human browser does. Consumers can use this list to drive SQL LIKE scans or similar bulk queries.
func IsBot ¶
IsBot checks whether a user-agent string belongs to a bot, crawler, or automated tool. The primary verdict comes from uasurfer's IsBot() (conventional bot tokens, contact-URL convention, headless browsers, named crawler fleets). Our own pattern lists then act as a supplementary pass for scanners and crawlers uasurfer deliberately skips. An empty user-agent returns false — a missing UA is not, by itself, evidence of a bot.
func IsBotPath ¶
IsBotPath reports whether a request path targets a bot-only file (robots.txt, ads.txt, sitemap.xml, etc.) that no human browser requests. Matching is case-insensitive. The pattern is matched as a suffix of the last path segment (filename), so "/app-ads.txt" matches "ads.txt" but "/ads.txt.backup" does not.
func IsDataCenterIP ¶
IsDataCenterIP checks whether an IP address falls within known data center CIDR ranges (AWS, GCP, Azure, DigitalOcean, Oracle Cloud, Hetzner, OVH, Linode/Akamai, Vultr, Alibaba, Tencent, Contabo, Scaleway/Online.net, IBM Cloud, UpCloud).
func IsMaliciousPath ¶
IsMaliciousPath reports whether a request path targets a universally malicious endpoint (.env, .git/, .svn/, .htpasswd, shell.php) that is never legitimate on any properly-configured site. A single hit is strong evidence of a vulnerability scanner. Stack-dependent patterns are not included — consumers should add their own.
File patterns (e.g. shell.php) are matched as a suffix of the last path segment. Dotfile patterns starting with '.' (e.g. .env, .htpasswd) match the segment exactly, as a suffix (e.g. "backup.env"), or as a prefix followed by a separator — capturing variants like .env.bak, .env_old, and .env.local while avoiding false positives on .envrc or .envelope.yml. Directory patterns (e.g. .git/, .svn/) are matched against individual path segments, so "/.git/config" matches but "/.github/workflows" does not.
func IsReferrerSpam ¶
IsReferrerSpam checks whether a referrer URL host matches a known spam domain. The referrer can be a full URL or just a domain. Matching is case-insensitive.
func MaliciousPathPatterns ¶
func MaliciousPathPatterns() []string
MaliciousPathPatterns returns the list of path substrings for endpoints that are never legitimate on any properly-configured website (e.g. .env, .git/, shell.php). Stack-dependent patterns like .php or wp-admin are excluded — consumers should add their own based on their tech stack.
Types ¶
type BotClass ¶
type BotClass string
BotClass categorizes a detected bot so consumers can apply purpose-aware policy (allow search engines, block scanners, observe AI crawlers) instead of a flat allow/block.
const ( ClassSearch BotClass = "search" // Googlebot, Bingbot, DuckDuckBot, ... ClassSocial BotClass = "social" // Twitterbot, FacebookExternalHit, LinkedInBot, ... ClassAI BotClass = "ai" // GPTBot, ClaudeBot, Google-Extended, Bytespider, ... ClassAIUser BotClass = "ai-user" // ChatGPT-User, Perplexity-User, Claude-Web (human-initiated fetch) ClassSEOTool BotClass = "seo-tool" // AhrefsBot, SemrushBot, PetalBot, ... ClassMonitor BotClass = "monitor" // Pingdom, Datadog, Site24x7, UptimeRobot, ... ClassScraper BotClass = "scraper" // curl, python-requests, scrapy, headless, ... ClassScanner BotClass = "scanner" // sqlmap, nikto, nmap, masscan, zgrab, cve-, ... ClassOther BotClass = "other" // generic/unclassified bots )
type Detection ¶
type Detection struct {
Bot bool // true if identified as a bot
Name string // normalized bot identifier (e.g. "googlebot", "gptbot", "sqlmap")
Class BotClass // empty when Bot is false
}
Detection is the result of analyzing a user-agent or request: whether it is a bot, its normalized identity, and its class.
func Detect ¶
Detect analyzes a user-agent string and returns a Detection with the bot's identity and class. An empty user-agent returns a zero Detection.
Order of evaluation: the specific-name classification table runs first (preserving per-agent identity that uasurfer collapses into fleet constants — e.g. "chatgpt-user" vs "gptbot" both parse as BrowserOpenAIBot), then uasurfer's IsBot() for named fleets and generic heuristics, then our broad word-boundary pattern list for anything unclassified.
func DetectRequest ¶
DetectRequest analyzes an *http.Request — currently its User-Agent — and returns a Detection. Returns a zero Detection if r is nil. Alternate UA-carrier headers (From, X-Scanner, ...) are added in a follow-up once the vendored headers list lands.
type UserAgentInfo ¶
type UserAgentInfo struct {
Browser string
BrowserVersion string
Os string
OsVersion string
Device string
DeviceType string
}
UserAgentInfo holds parsed user-agent data.
func ParseUserAgent ¶
func ParseUserAgent(ua string) UserAgentInfo
ParseUserAgent extracts browser, OS, device, and device-type from a user-agent string using the uasurfer library. Unknown values are left as empty strings. All name fields are normalized to lowercase so consumers can compare them without case-folding.