(self, headers: Dict[str, str], body: str, url: str)
| 942 | )) |
| 943 | |
| 944 | async def detect_tech(self, headers: Dict[str, str], body: str, url: str) -> None: |
| 945 | # Correct header matching: build "key: value" lines and search |
| 946 | header_lines = "\n".join([f"{k}: {v}" for k, v in headers.items()]).lower() |
| 947 | body_l = (body or "").lower() |
| 948 | |
| 949 | for name, pat, src in TECH_SIGS: |
| 950 | hay = header_lines if src == "header" else body_l |
| 951 | m = pat.search(hay) |
| 952 | if m: |
| 953 | ver = "" |
| 954 | if m.lastindex: |
| 955 | ver = first_nonempty_group(m) |
| 956 | self.add_tech(name=name, version=ver or "", confidence=80 if src == "header" else 70, source=src) |
| 957 | # Hint from headers |
| 958 | if "x-powered-by" in headers: |
| 959 | self.add_tech(headers["x-powered-by"].split()[0], source="header", confidence=60) |
| 960 | |
| 961 | # Store a finding for tech summary (Info) |
| 962 | if self.technologies: |
| 963 | tech_list = ", ".join( |
| 964 | sorted({f"{t.name}{('/' + t.version) if t.version else ''}" for t in self.technologies.values()}) |
| 965 | ) |
| 966 | self.add_finding(Finding( |
| 967 | category="Tech_Detected", |
| 968 | severity="Info", |
| 969 | url=url, |
| 970 | details=f"Detected: {tech_list}" |
| 971 | )) |
| 972 | |
| 973 | async def check_vuln_patterns(self, url: str, body: str) -> None: |
| 974 | if not body: |
no test coverage detected