Files
felhom.eu/documentation/audits/lockouts-2026-10-01/tools/b_wger.py
T

68 lines
4.0 KiB
Python

#!/usr/bin/env python3
"""R-752 wger on 9202. argv[1] = control | fix.
control: the LIVE template (axes keyed on ip_address, 10 failures, 30 min). fix: the drill template
(AXES_LOCKOUT_PARAMETERS=username, AXES_COOLOFF_TIME=15).
Both: install, a SECOND household member made with wger's own Django (manage.py shell — seeding, not a login),
positive controls, 10 wrong REST logins for the public name `admin` as a stranger, then admin's and the second
member's RIGHT passwords. fix only: one right-password try at +8 min (a try DURING the lock — does it extend it?),
then single tries at +16, +24, +32 min until it works; a wrong one after."""
import sys, time
import walk as w
import lk
MODE = sys.argv[1]
SUB = "fitness"
w.login()
lk.p(f"##### wger {MODE} — controller {w.guest('docker inspect felhom-controller --format {{.Config.Image}}').strip()}")
if MODE == "fix":
for _ in range(12):
w.sync_rescan()
cat = w.guest("grep -rh AXES_LOCKOUT_PARAMETERS /var/lib/docker/volumes/felhom-controller-data/_data/ --include=docker-compose.yml 2>/dev/null | sort -u").strip()
if "COOLOFF_TIME=5" in w.guest("grep -rh AXES_COOLOFF_TIME /var/lib/docker/volumes/felhom-controller-data/_data/ --include=docker-compose.yml 2>/dev/null"):
break
time.sleep(15)
lk.p("the box's catalog copy:", cat)
lk.p("deploy:", w.deploy("wger", SUB))
for _ in range(120):
time.sleep(5)
if "hold OPENED" in w.guest("docker logs --since 20m felhom-controller 2>&1 | grep 'wger: install hold OPENED'"):
break
w.wait_app(SUB, "/en/user/login", want=("200",), tries=72)
lk.p("axes settings inside the app:", w.guest("""cat > /tmp/axs.py <<'PY'
import os, sys
sys.path.insert(0, '/home/wger/src'); os.chdir('/home/wger/src')
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'settings.main')
import django; django.setup()
from django.conf import settings as s
print(s.AXES_LOCKOUT_PARAMETERS, s.AXES_FAILURE_LIMIT, s.AXES_COOLOFF_TIME, s.AXES_RESET_COOL_OFF_ON_FAILURE_DURING_LOCKOUT, s.AXES_HANDLER, s.CACHES['default']['BACKEND'])
PY
docker cp /tmp/axs.py wger:/tmp/axs.py && docker exec wger python3 /tmp/axs.py 2>&1 | tail -1; docker exec wger sh -c 'ps -eo args' | grep -E '[g]unicorn|[r]unserver|[u]vicorn' | head -3""").strip())
pw = (w.GENERATED.get("wger") or {}).get("ADMIN_PASSWORD", "")
pw2 = "Second-" + str(int(time.time()))
lk.p("second member:", w.guest(
"docker exec wger python3 -c \"import os,sys; sys.path.insert(0,'/home/wger/src'); os.chdir('/home/wger/src'); "
"os.environ.setdefault('DJANGO_SETTINGS_MODULE','settings.main'); import django; django.setup(); "
"from django.contrib.auth.models import User; u=User.objects.create_user('second', 'second@gate.invalid', sys.argv[1]); print('made', u.username)\" " + pw2).strip())
lk.p("positive controls — admin:", lk.wger("admin", pw), "| second:", lk.wger("second", pw2))
for i in range(1, 12):
lk.p(f"stranger wrong try {i} (admin):", lk.wger("admin", f"wrong-{i}-{time.time()}"))
t0 = time.time()
lk.p("household — admin RIGHT password:", lk.wger("admin", pw), "| second member RIGHT password:", lk.wger("second", pw2))
if MODE == "fix":
def at(minutes, label, who="admin", p=None):
while time.time() - t0 < minutes * 60:
time.sleep(10)
r = lk.wger(who, p or pw)
lk.p(f"+{(time.time() - t0) / 60:.1f} min {label}:", r)
return r
sched = [float(x) for x in (sys.argv[2].split(",") if len(sys.argv) > 2 else ["8", "16", "24", "32", "40"])]
at(sched[0], "admin RIGHT password DURING the lock (does it restart the cool-off?)")
lk.p("second member, same moment:", lk.wger("second", pw2))
for m in sched[1:]:
if at(m, "admin RIGHT password") == "ok":
break
lk.p("a wrong one after:", lk.wger("admin", "wrong-after"), "| right again:", lk.wger("admin", pw))
lk.p(w.guest("docker logs --since 60m wger 2>&1 | grep -i -E 'axes|lock' | tail -6 | cut -c1-220").strip())
w.remove("wger")
lk.p("removed; deployed =", w.stack("wger").get("deployed"))