Fix DDNS registration and wizard pre-fill after installer run
Unit Tests / test (push) Successful in 15m29s
Unit Tests / test (push) Successful in 15m29s
DDNS registration (setup_cell.py): - Replace pyotp dependency with stdlib TOTP (HMAC-SHA1, RFC 6238) pyotp is only available inside the Docker container, not on the host where setup_cell.py runs — registration was silently skipped every time - OTP header still sent if generation succeeds; omitted gracefully if not Wizard pre-fill (setup_manager + Setup.jsx): - GET /api/setup/status now returns 'preconfigured' dict with cell_name, domain_mode, domain_name, and provider tokens from installer-written config - Setup.jsx fetches status on mount and pre-fills all form state so the user only needs to set password, services, and timezone — not re-enter the identity they already configured in the bash installer - Fails silently so wizard still works on fresh installs with no config Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+16
-13
@@ -304,25 +304,28 @@ def register_with_ddns(cell_name: str) -> None:
|
||||
print(f'[WARN] Could not detect public IP: {e} — skipping DDNS registration')
|
||||
return
|
||||
|
||||
# Generate TOTP code (requires pyotp; if not available fall back gracefully)
|
||||
# Generate TOTP using stdlib only — no third-party package needed
|
||||
otp = ''
|
||||
try:
|
||||
import pyotp
|
||||
otp = pyotp.TOTP(DDNS_TOTP_SECRET).now()
|
||||
except ImportError:
|
||||
# Try python3 -c as a subprocess fallback
|
||||
try:
|
||||
otp = subprocess.check_output(
|
||||
['python3', '-c', f"import pyotp; print(pyotp.TOTP('{DDNS_TOTP_SECRET}').now())"]
|
||||
).decode().strip()
|
||||
except Exception as e:
|
||||
print(f'[WARN] pyotp not available and fallback failed: {e} — skipping DDNS')
|
||||
return
|
||||
import base64 as _b64, hashlib as _hl, hmac as _hmac, struct as _struct
|
||||
import time as _time
|
||||
_key = _b64.b32decode(DDNS_TOTP_SECRET.upper())
|
||||
_t = int(_time.time()) // 30
|
||||
_h = _hmac.new(_key, _struct.pack('>Q', _t), _hl.sha1).digest()
|
||||
_offset = _h[-1] & 0xF
|
||||
_code = _struct.unpack('>I', _h[_offset:_offset + 4])[0] & 0x7FFFFFFF
|
||||
otp = f'{_code % 1_000_000:06d}'
|
||||
except Exception as e:
|
||||
print(f'[WARN] Could not generate OTP: {e} — registering without OTP header')
|
||||
|
||||
data = json.dumps({'name': cell_name, 'ip': public_ip}).encode()
|
||||
headers = {'Content-Type': 'application/json'}
|
||||
if otp:
|
||||
headers['X-Register-OTP'] = otp
|
||||
req = urllib.request.Request(
|
||||
f'{DDNS_URL}/register',
|
||||
data=data,
|
||||
headers={'Content-Type': 'application/json', 'X-Register-OTP': otp},
|
||||
headers=headers,
|
||||
method='POST',
|
||||
)
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user