#!/usr/bin/env python3
import json
import os
import re
import shutil
import subprocess
import sys
from datetime import datetime
from pathlib import Path
BEGIN = "# BEGIN wp-MM-System request protection"
END = "# END wp-MM-System request protection"
BLOCK = """# BEGIN wp-MM-System request protection
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_URI} ^/+xmlrpc\\.php(?:/)?$ [NC,OR]
RewriteCond %{HTTP_USER_AGENT} (SERankingBacklinksBot|SemrushBot|MJ12bot|AhrefsBot|DotBot|DataForSeoBot) [NC]
RewriteRule ^ - [F,L]
</IfModule>
# END wp-MM-System request protection
"""
def sites():
found = {}
source = Path("/etc/userdatadomains")
for raw in source.read_text(errors="replace").splitlines() if source.exists() else []:
parts = raw.split("==")
if len(parts) < 5 or ":" not in parts[0]:
continue
domain = parts[0].split(":", 1)[0].strip().lower().rstrip(".")
root = Path(parts[4].strip())
if not domain or not root.is_dir():
continue
if not ((root / "wp-config.php").is_file() or ((root / "wp-admin").is_dir() and (root / "wp-includes").is_dir())):
continue
found.setdefault(str(root), domain)
return sorted((Path(root), domain) for root, domain in found.items())
def main():
stamp = datetime.now().astimezone().strftime("%Y%m%d_%H%M%S")
backup = Path("/root/wpmm-backups") / ("request-protection-" + stamp)
originals = backup / "originals"
originals.mkdir(parents=True, exist_ok=True)
changed = []
skipped = []
entries = sites()
for index, (root, domain) in enumerate(entries, 1):
target = root / ".htaccess"
if target.is_symlink():
skipped.append({"domain": domain, "path": str(target), "reason": "symlink"})
continue
old = target.read_text(errors="replace") if target.exists() else ""
cleaned = re.sub(r"(?ms)^# BEGIN wp-MM-System request protection\n.*?^# END wp-MM-System request protection\n?", "", old).lstrip("\n")
new = BLOCK + ("\n" + cleaned if cleaned else "")
if old == new:
continue
if target.exists():
shutil.copy2(str(target), str(originals / ("%04d.htaccess" % index)))
stat = target.stat()
else:
stat = root.stat()
temporary = target.with_name(".htaccess.wpmm.tmp")
temporary.write_text(new, encoding="utf-8")
os.chmod(str(temporary), stat.st_mode & 0o777 if target.exists() else 0o644)
os.chown(str(temporary), stat.st_uid, stat.st_gid)
os.replace(str(temporary), str(target))
changed.append({"domain": domain, "documentroot": str(root), "had_htaccess": bool(old)})
manifest = {"created_at": datetime.now().astimezone().isoformat(timespec="seconds"), "backup": str(backup), "sites_found": len(entries), "changed": changed, "skipped": skipped}
(backup / "manifest.json").write_text(json.dumps(manifest, ensure_ascii=False, indent=2), encoding="utf-8")
os.chmod(str(backup / "manifest.json"), 0o600)
print(json.dumps({"sites_found": len(entries), "changed": len(changed), "skipped": skipped, "backup": str(backup), "test_domain": entries[0][1] if entries else ""}, ensure_ascii=False))
if __name__ == "__main__":
main()