#!/usr/bin/env python3 """nc_compare.py — every file under Ödön's „Csalad" folder through Nextcloud's own WebDAV door (the box's LAN address with the Host header; TLS not verified, the rehearsal's tester4.test has no DNS), sha256 against the rehearsal's A5 manifest. Env: REHEARSAL_2026_10_20_ODON_PW (under `sec run`). Prints counts and up to 15 differing names; never a secret.""" import base64, hashlib, http.client, os, ssl, sys, unicodedata, urllib.parse, xml.etree.ElementTree as ET IP, HOST = "192.168.0.139", "cloud.tester4.test" MAN = "/mnt/5_hdd/felhom.eu/git/felhom.eu/documentation/audits/rehearsal-2026-10-20/A5-data/MANIFEST.tsv" auth = "Basic " + base64.b64encode(("odon:" + os.environ["REHEARSAL_2026_10_20_ODON_PW"]).encode()).decode() ctx = ssl._create_unverified_context() def req(method, path, body=None, extra=None): c = http.client.HTTPSConnection(IP, 443, context=ctx, timeout=300) h = {"Host": HOST, "Authorization": auth}; h.update(extra or {}) c.request(method, path, body=body, headers=h); r = c.getresponse(); data = r.read(); c.close() return r.status, data base = "/remote.php/dav/files/odon" files = {} def walk(path): st, data = req("PROPFIND", urllib.parse.quote(base + path), b'', {"Depth": "1"}) if st != 207: print("PROPFIND", path, st); return for resp in ET.fromstring(data).findall("{DAV:}response"): href = urllib.parse.unquote(resp.find("{DAV:}href").text) rel = href[len(base):] if rel.rstrip("/") == path.rstrip("/"): continue if resp.find(".//{DAV:}collection") is not None: walk(rel) else: files[rel] = href walk("/Csalad/") want = {} for line in open(MAN, encoding="utf-8"): p = line.rstrip("\n").split("\t") if p[0].startswith("nextcloud/Csalad/"): want[unicodedata.normalize("NFC", "/" + p[0][len("nextcloud/"):])] = p[2] same, differ, extra = 0, [], [] got = {} for rel, href in files.items(): st, data = req("GET", urllib.parse.quote(href)) got[unicodedata.normalize("NFC", rel)] = hashlib.sha256(data).hexdigest() if st == 200 else f"HTTP{st}" for k, h in want.items(): if got.get(k) == h: same += 1 else: differ.append(("MISSING" if k not in got else "DIFFERS") + " " + k) extra = [k for k in got if k not in want] print(f"nextcloud Csalad: manifest {len(want)} files; on the box {len(got)}; byte-identical {same}; missing/different {len(differ)}; extra {len(extra)}") for d in differ[:15]: print(" ", d) for e in extra[:8]: print(" EXTRA", e)