Spaces:
Sleeping
Sleeping
| from __future__ import annotations | |
| import re | |
| from pathlib import Path | |
| EMAIL_RE = re.compile(r"\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b", re.IGNORECASE) | |
| TOKEN_PATTERNS = [ | |
| re.compile(r"\b(?:sk|hf|ghp|xox[baprs])_[A-Za-z0-9_-]{16,}\b"), | |
| re.compile(r"\bAKIA[0-9A-Z]{16}\b"), | |
| re.compile(r"(?i)\b(?:api[_ -]?key|access[_ -]?token|secret[_ -]?key)\s*[:=]\s*['\"]?[A-Za-z0-9_\-/.+=]{12,}"), | |
| ] | |
| PHONE_RE = re.compile(r"(?<!\d)(?:\+?1[-.\s]?)?(?:\(?\d{3}\)?[-.\s]?)\d{3}[-.\s]?\d{4}(?!\d)") | |
| TEXT_EXTENSIONS = {".txt", ".md", ".json", ".csv", ".yaml", ".yml", ".log"} | |
| MAX_SCAN_BYTES = 2 * 1024 * 1024 | |
| def scan_text(text: str) -> list[str]: | |
| findings: list[str] = [] | |
| if EMAIL_RE.search(text): | |
| findings.append("possible_email") | |
| if PHONE_RE.search(text): | |
| findings.append("possible_phone") | |
| if any(pattern.search(text) for pattern in TOKEN_PATTERNS): | |
| findings.append("possible_secret_or_token") | |
| return findings | |
| def scan_file(path: str | Path) -> list[str]: | |
| file_path = Path(path) | |
| findings = scan_text(file_path.name) | |
| if file_path.suffix.lower() in TEXT_EXTENSIONS and file_path.stat().st_size <= MAX_SCAN_BYTES: | |
| try: | |
| findings.extend(scan_text(file_path.read_text(encoding="utf-8", errors="ignore"))) | |
| except OSError: | |
| findings.append("scan_error") | |
| return sorted(set(findings)) | |