klyrek-tech
Status: live on PyPI — pip install klyrek-tech
Signature-based technology fingerprinting: web servers, frameworks, CMSes, JS libraries, hosting/CDN providers, all matched against response headers, cookies, and body content.
from klyrek_tech.fingerprint import fingerprint
for tech in fingerprint(response):
print(tech.name, tech.category, tech.version)
Real output against admin.sandbox.klyrek.com: Express framework None, Vercel hosting None — Vercel's edge adds its own headers regardless of the app behind it, so hosting and framework both show up independently.
Signatures are declarative (klyrek_tech.signatures.SIGNATURES), matched by header regex, cookie-name regex, or body substring — adding a new technology is a new list entry, not new matching code.
API reference
klyrek_tech.fingerprint
Match an HTTP response against known technology signatures.
fingerprint
fingerprint(response: Response) -> list[Technology]
Match a response against every known signature and return the technologies found.
Source code in klyrek_tech\fingerprint.py
| def fingerprint(response: httpx.Response) -> list[Technology]:
"""Match a response against every known signature and return the technologies found."""
body = response.text if _looks_like_text(response) and response.content else ""
meta_generator_match = _META_GENERATOR_RE.search(body) if body else None
cookie_names = _cookie_names(response)
technologies: list[Technology] = []
for sig in SIGNATURES:
evidence: list[str] = []
version: str | None = None
for header_name, pattern in sig.headers.items():
value = response.headers.get(header_name)
if value is None:
continue
match = pattern.search(value)
if match:
evidence.append(f"{header_name}: {value}")
version = version or _extract_version(match)
for cookie_pattern in sig.cookies:
for name in cookie_names:
if cookie_pattern.search(name):
evidence.append(f"cookie: {name}")
if sig.meta_generator and meta_generator_match:
content = meta_generator_match.group(1)
match = sig.meta_generator.search(content)
if match:
evidence.append(f"meta generator: {content}")
version = version or _extract_version(match)
for body_pattern in sig.body:
if not body:
continue
match = body_pattern.search(body)
if match:
evidence.append(f"body pattern: {body_pattern.pattern}")
version = version or _extract_version(match)
if evidence:
technologies.append(
Technology(
name=sig.name,
category=sig.category,
version=version,
evidence=evidence,
discovered_by="klyrek-tech",
)
)
return technologies
|
klyrek_tech.signatures
Declarative technology signatures.
Kept data-driven (a list of Signature records) rather than one class per
technology, since the matching logic (header/cookie/body regex) is identical
across every signature — only the patterns differ. Adding a new technology is a
new list entry, not new code.