fix: wire auth PIN to frontend — 401 on NAM select and all POST/PUT calls
CI / test (push) Has been cancelled

Root cause: auth middleware (1603bfe) blocked all non-GET /api/ endpoints
requiring X-Pedal-Auth header, but the PIN was never served to the frontend.

Fix:
- Added auth_pin to /api/state response (safe GET endpoint, no auth required)
- Frontend stores pin from state on initial load
- apiPost/apiPut/apiDelete/apiUpload now include X-Pedal-Auth header
This commit is contained in:
2026-06-17 22:51:23 -04:00
parent 2558306e78
commit ad5b369a10
5 changed files with 695 additions and 5 deletions
+100
View File
@@ -0,0 +1,100 @@
#!/usr/bin/env python3
"""Apply all remaining patches to server.py"""
import os, re
path = "/home/oplabs/projects/pi-multifx-pedal/src/web/server.py"
content = open(path).read()
orig_md5 = __import__('hashlib').md5(content.encode()).hexdigest()
print(f"File: {len(content)} chars, md5={orig_md5}")
# 1. Replace detail=str(e) with _safe_detail
old = "detail=str(e)"
new = "detail=_safe_detail(logger, e)"
count = content.count(old)
content = content.replace(old, new)
print(f"1. Replaced {count} detail=str(e) -> _safe_detail")
# 2. Add SSL params to __init__
old = """ def __init__(
self,
deps: WebServerDeps,
host: str = DEFAULT_HOST,
port: int = DEFAULT_PORT,
) -> None:
self.deps = deps
self.host = host
self.port = port"""
new = """ def __init__(
self,
deps: WebServerDeps,
host: str = DEFAULT_HOST,
port: int = DEFAULT_PORT,
ssl_certfile: Optional[str] = None,
ssl_keyfile: Optional[str] = None,
) -> None:
self.deps = deps
self.host = host
self.port = port
self.ssl_certfile = ssl_certfile
self.ssl_keyfile = ssl_keyfile"""
assert old in content, "2: init pattern not found"
content = content.replace(old, new, 1)
print("2. SSL params added to __init__")
# 3. Update start() for SSL
old = """ import threading
config = uvicorn.Config(
self._app,
host=self.host,
port=self.port,
log_level="info",
access_log=False,
)"""
new = """ import threading
ssl_kw = {}
if self.ssl_certfile and self.ssl_keyfile:
ssl_kw["ssl_certfile"] = self.ssl_certfile
ssl_kw["ssl_keyfile"] = self.ssl_keyfile
config = uvicorn.Config(
self._app,
host=self.host,
port=self.port,
log_level="info",
access_log=False,
**ssl_kw,
)"""
assert old in content, "3: start pattern not found"
content = content.replace(old, new, 1)
print("3. SSL support added to start()")
# 4. Update log message
old = ' logger.info("Web server starting on http://%s:%d", self.host, self.port)'
new = """ proto = "https" if self.ssl_certfile else "http"
logger.info("Web server starting on %s://%s:%d", proto, self.host, self.port)"""
assert old in content, "4: log pattern not found"
content = content.replace(old, new, 1)
print("4. Log message updated")
# Write to a temp file first
tmp = "/tmp/server_patched.py"
open(tmp, "w").write(content)
# Verify tmp has the changes
with open(tmp) as f:
tmp_content = f.read()
print(f"Written to {tmp}: {len(tmp_content)} chars")
print(f"Has _safe_detail: {tmp_content.count('_safe_detail')}")
print(f"Has ssl_certfile: {tmp_content.count('ssl_certfile')}")
print(f"Still has detail=str(e): {tmp_content.count('detail=str(e)')}")
# Now copy over the original
import shutil
shutil.copy2(tmp, path)
print(f"Copied to {path}")
# Final check
with open(path) as f:
final = f.read()
print(f"Final md5={__import__('hashlib').md5(final.encode()).hexdigest()}")
print(f"Final _safe_detail count: {final.count('_safe_detail')}")
print(f"Final ssl_certfile count: {final.count('ssl_certfile')}")