pub struct Site {Show 14 fields
pub name: String,
pub url: UrlTemplate,
pub signals: Vec<Signal>,
pub known_present: Option<KnownPresent>,
pub known_absent: Option<String>,
pub extract: Vec<Extractor>,
pub tags: Vec<String>,
pub request_headers: BTreeMap<String, String>,
pub regex_check: Option<String>,
pub engine: Option<String>,
pub strip_bad_char: Option<String>,
pub request_method: HttpMethod,
pub request_body: Option<String>,
pub protection: Vec<ProtectionKind>,
}Expand description
One site we can probe for the existence of an account.
Fields§
§name: StringHuman-readable site name. Doubles as the stable filter key
(case-insensitive) used by CLI --only / --exclude.
url: UrlTemplateURL template containing a {username} placeholder.
signals: Vec<Signal>Ordered list of detection signals. Aggregated per the type-level docs.
Optional in source JSON when Site::engine is set — the engine’s
signals are inherited at load time. After
crate::Registry resolution this vec is always non-empty (or the
site fails validate).
known_present: Option<KnownPresent>One or more usernames known to exist on this site. Consumed by
adler doctor to verify the signal list still reports Found
for a real account. Accepts either a single string or an array
of strings in JSON; the doctor probes each in declaration order
and passes the present-check if any one of them resolves to
Found. Listing several is defensive — brand accounts or other
users that the site special-cases (e.g. Instagram’s own
instagram account) shouldn’t false-fail the whole site.
known_absent: Option<String>Username known to not exist on this site (optional). When omitted, the doctor generates a random nonsense username instead.
extract: Vec<Extractor>Optional CSS-selector rules for pulling profile fields (name, bio,
avatar, …) out of a Found page. Only applied under --enrich.
Free-form classification tags for scanning a subset of the registry,
e.g. "social", "dev", "region:ru". Matched by CLI --tag.
A site with no tags is universal (included unless a --tag filter
excludes it). Conventionally lowercase; axis:value is just a naming
convention, not enforced.
request_headers: BTreeMap<String, String>Extra HTTP headers to send with the probe (e.g.
{"X-IG-App-ID": "936619743392459"} to unlock Instagram’s
web_profile_info endpoint, or a custom User-Agent). Browser
backends apply them via Network.setExtraHTTPHeaders before
navigation; the raw-HTTP path doesn’t read this yet.
regex_check: Option<String>Optional regular expression describing usernames a site will
accept. When set and the scanned username doesn’t match, the
site is skipped (the outcome is reported as Uncertain with
reason UsernameNotAllowed, without issuing any HTTP request).
Saves work AND avoids the false-positive class where a site
404s on illegal usernames in ways our signal can’t tell apart
from a missing account.
Imported from Sherlock’s regexCheck field; 95+ sites
upstream carry one (length bounds, character classes, etc.).
Validation at load time compiles the regex with regex::Regex
— a malformed pattern rejects the site rather than silently
degrading at scan time.
engine: Option<String>Name of a shared Engine this site inherits from (e.g.
"Discourse", "vBulletin"). Forum-software platforms host
thousands of instances with identical detection signatures;
defining the signature once on an engine and inheriting it
keeps the registry small and the cost of a platform-wide
HTML change one fix instead of hundreds.
At crate::Registry::validate time, engine fields are
merged under the site’s own — anything the site declares
explicitly (signals, request_headers, regex_check) wins on
conflict; anything left empty / unset is filled from the
engine. An engine: "X" referring to a non-existent X is a
load-time error.
strip_bad_char: Option<String>Characters the site silently drops from the username server-side
before matching — john.doe and johndoe resolve to the same
account on a site that lists strip_bad_char: ".". We pre-strip
at probe time so the URL we issue matches the canonical form
the site uses, avoiding a false NotFound on a benign
punctuation variant. Mirrors WhatsMyName’s field of the same
name; carried verbatim through scripts/import_whatsmyname.py.
request_method: HttpMethodHTTP method used to probe this site. Defaults to GET — the vast majority of sites are GET-probed. A few (Anilist’s GraphQL API, some Discord/Holopin endpoints) only answer to POST.
request_body: Option<String>Request body to send when Site::request_method is POST. The
literal {username} placeholder is substituted with the probe
username (same as URL templates). For GraphQL endpoints this
is typically the JSON {"query":"...","variables":{"name":"{username}"}}.
protection: Vec<ProtectionKind>Specific anti-bot mechanisms the site is known to deploy. A
richer alternative to the flat bot-protected tag — knowing
which protection a site uses lets future routing pick the
right backend (Cloudflare → cloudscraper-style bypass,
CfFirewall → full browser, UserAuth → skip, …) instead
of the all-or-nothing bot-protected decision.
Independent of Site::tags: the existing bot-protected
tag stays as a back-compat shorthand and routes through the
browser backend exactly as before. When this vector is
non-empty Adler also treats the site as bot-protected
regardless of the tag.
Implementations§
Source§impl Site
impl Site
Sourcepub fn url_for(&self, username: &Username) -> String
pub fn url_for(&self, username: &Username) -> String
Render the site URL for a given username.
If the site declares strip_bad_char,
those characters are removed from username before
substitution — so a john.doe probe against a site that
lists strip_bad_char: "." actually hits the URL for
johndoe, matching the canonical form the site stores
internally.