diff --git a/configs/bank-landing/index.html b/configs/bank-landing/index.html index 2e4cefc..1897f42 100644 --- a/configs/bank-landing/index.html +++ b/configs/bank-landing/index.html @@ -1348,8 +1348,8 @@ tw balance
-
Your account · bank UI login
- https://bank.hacktivism.ch/webui/ +
Your account · payto
+ @@ -1776,8 +1776,8 @@ tw balance webuiA.setAttribute("target", "_blank"); webuiA.setAttribute("rel", "noopener noreferrer"); } - /* payto must include host:port (e.g. bank.hacktivism.ch:443) */ - var payto = d.payto_uri || ""; + /* Account payto (libeufin style) — this is what the account QR encodes */ + var payto = d.payto_uri || d.qr_payload || ""; if (payA) { if (payto && payto.indexOf("payto://") === 0) { payA.href = payto; @@ -1793,26 +1793,31 @@ tw balance st.textContent = "Account created for you · " + (d.username || d.name || "") + - " · save username & password"; + " · save username & password · QR = payto account"; } - /* Fancy QR_Taler: encode bank UI URL (login with credentials above) */ + /* QR encodes payto:// of this account (not the generic webui homepage) */ var qrBlock = document.getElementById("auto-account-qr-block"); var qrLabel = document.getElementById("qr-auto-acct-label"); + var qrPayload = payto || webui; if (qrBlock) qrBlock.hidden = false; if (qrLabel) { qrLabel.textContent = - "QR_Taler · open bank UI · login as " + (d.username || "you"); + "Account payto · " + (d.username || "you"); } var autoPayload = document.getElementById("qr-auto-acct-payload"); if (autoPayload) { - autoPayload.href = webui; - autoPayload.textContent = webui; - autoPayload.setAttribute("target", "_blank"); - autoPayload.setAttribute("rel", "noopener noreferrer"); + autoPayload.href = qrPayload; + autoPayload.textContent = qrPayload; + if (qrPayload.indexOf("http") === 0) { + autoPayload.setAttribute("target", "_blank"); + autoPayload.setAttribute("rel", "noopener noreferrer"); + } else { + autoPayload.removeAttribute("target"); + } } makeQr( document.getElementById("qr-auto-acct"), - webui, + qrPayload, document.getElementById("qr-auto-acct-logo") ); if (btn) { diff --git a/scripts/taler-bank/demo-withdraw-api.py b/scripts/taler-bank/demo-withdraw-api.py index e226518..12c0785 100755 --- a/scripts/taler-bank/demo-withdraw-api.py +++ b/scripts/taler-bank/demo-withdraw-api.py @@ -39,30 +39,38 @@ LANDING = Path(os.environ.get("LANDING_DIR", "/var/www/bank-landing")) LISTEN = ("127.0.0.1", int(os.environ.get("DEMO_WITHDRAW_PORT", "19096"))) -def bank_payto_authority() -> str: - """Host:port for payto://x-taler-bank/… (port required; public HTTPS → :443).""" +def bank_payto_host() -> str: + """Hostname for payto://x-taler-bank/HOST/account (libeufin style: no :443).""" override = os.environ.get("BANK_PAYTO_HOST", "").strip() if override: + # allow full host or host:port if operator sets it return override u = urllib.parse.urlparse( BANK_PUBLIC if "://" in BANK_PUBLIC else f"https://{BANK_PUBLIC}" ) - host = u.hostname or "bank.hacktivism.ch" - if u.port: - port = u.port - elif (u.scheme or "https") == "https": - port = 443 - else: - port = 80 - return f"{host}:{port}" + return u.hostname or "bank.hacktivism.ch" -def make_account_payto(username: str) -> str: - """Valid x-taler-bank payto with explicit port + encoded receiver-name.""" - auth = bank_payto_authority() +def make_account_payto(username: str, bank_payto: str = "") -> str: + """Account payto for QR/link. + + Prefer libeufin internal_payto_uri when present (authoritative). + Fallback matches bank registration: host without default HTTPS port. + """ rn = urllib.parse.quote(username, safe="") - # path account name is bank-safe [a-z0-9-]; keep unencoded - return f"payto://x-taler-bank/{auth}/{username}?receiver-name={rn}" + if isinstance(bank_payto, str) and bank_payto.startswith("payto://x-taler-bank/"): + # Keep bank-issued host/account; ensure receiver-name is encoded + try: + # payto://x-taler-bank/HOST/ACCOUNT?… + rest = bank_payto[len("payto://x-taler-bank/") :] + host_acct, _, _qs = rest.partition("?") + host, _, acct = host_acct.partition("/") + if host and acct: + return f"payto://x-taler-bank/{host}/{acct}?receiver-name={rn}" + except Exception: + pass + host = bank_payto_host() + return f"payto://x-taler-bank/{host}/{username}?receiver-name={rn}" def public_webui_url() -> str: @@ -240,8 +248,13 @@ def create_personal_account() -> dict: ) if code not in (200, 201, 204): raise RuntimeError(f"register failed HTTP {code}: {body}") - # Always emit a correct public payto (libeufin often omits :443 → invalid for HTTPS) - payto = make_account_payto(username) + bank_payto = "" + if isinstance(body, dict): + bank_payto = ( + body.get("internal_payto_uri") or body.get("payto_uri") or "" + ) + # Prefer bank-issued payto (no fake :443). QR encodes this account payto. + payto = make_account_payto(username, bank_payto) webui = public_webui_url() return { "ok": True, @@ -253,12 +266,14 @@ def create_personal_account() -> dict: "balance": "GOA:0", "balance_note": "Starts at zero — not the shared community pool.", "payto_uri": payto, + "qr_payload": payto, "webui": webui, "account_url": webui, "hint": ( "This bank account was created for you automatically " f"({username}). " - "Copy username and password now — we do not store them for later recovery." + "Copy username and password now — we do not store them for later recovery. " + "QR / blue link is the account payto:// (not the bank UI homepage)." ), "created": time.strftime("%Y-%m-%dT%H:%MZ", time.gmtime()), "created_human": time.strftime("%Y-%m-%d %H:%M %Z", time.localtime()), diff --git a/scripts/taler-monitoring/check_urls.sh b/scripts/taler-monitoring/check_urls.sh index 0feb5ce..d269e7c 100755 --- a/scripts/taler-monitoring/check_urls.sh +++ b/scripts/taler-monitoring/check_urls.sh @@ -189,29 +189,31 @@ except Exception as e: if not d.get("ok"): print("ok!=true") sys.exit(1) -payto = d.get("payto_uri") or "" +payto = d.get("payto_uri") or d.get("qr_payload") or "" webui = d.get("webui") or d.get("account_url") or "" -# payto://x-taler-bank/host:port/account?... +# payto://x-taler-bank/HOST[/port]/account?receiver-name=… +# Match libeufin: host without :443 is correct for x-taler-bank payto m = re.match(r"^payto://x-taler-bank/([^/?#]+)/([^/?#]+)(\?.*)?$", payto) if not m: print("payto shape invalid:", payto[:120]) sys.exit(1) auth, acct = m.group(1), m.group(2) -if ":" not in auth: - print("payto missing port (need host:port):", auth) +if not auth or not acct: + print("payto host/account empty") sys.exit(1) -host, port_s = auth.rsplit(":", 1) -if not host or not port_s.isdigit(): - print("payto host:port invalid:", auth) +if "receiver-name=" not in (m.group(3) or ""): + print("payto missing receiver-name") sys.exit(1) -if not acct: - print("payto account empty") +# QR must encode payto (not only webui homepage) +qr = d.get("qr_payload") or payto +if not qr.startswith("payto://"): + print("qr_payload must be payto:// account URI:", (qr or "")[:80]) sys.exit(1) u = urlparse(webui) if u.scheme not in ("http", "https") or not u.netloc or "webui" not in (u.path or ""): print("webui not absolute https …/webui/:", webui[:120]) sys.exit(1) -print(f"user={d.get('username','')} payto={auth}/{acct} webui={webui}") +print(f"user={d.get('username','')} payto={auth}/{acct} qr=payto webui={webui}") sys.exit(0) PY then