taler-ios

iOS apps for GNU Taler (wallet)
Log | Files | Refs | README | LICENSE

commit cd74fa6d5a6849eed5f1949eadc9e791678349a2
parent ee1abcd74821be2241a2d8505756a494a8256855
Author: Marc Stibane <marc@taler.net>
Date:   Thu, 13 Aug 2026 16:18:24 +0200

AI: x-taler-bank payto

Diffstat:
MTalerWallet1/Helper/URL+id+iban.swift | 8++++++--
MTalerWallet1/Views/Settings/Bank/BankEditView.swift | 23++++++++++++++++++++---
2 files changed, 26 insertions(+), 5 deletions(-)

diff --git a/TalerWallet1/Helper/URL+id+iban.swift b/TalerWallet1/Helper/URL+id+iban.swift @@ -48,9 +48,13 @@ extension URL { var xTaler: String? { /// https://datatracker.ietf.org/doc/rfc8905/ - /// payto://iban/DE75512108001245126199?amount=EUR:200.0&message=hello + /// payto://x-taler-bank/BANK-HOST/ACCOUNT?receiver-name=… + /// The bank host is part of the target, so return "BANK-HOST/ACCOUNT" — + /// returning only lastPathComponent silently dropped the bank and made + /// the account unaddressable when it was written back out. if scheme == "payto" && host == "x-taler-bank" { - return lastPathComponent + let target = path.hasPrefix("/") ? String(path.dropFirst()) : path + return target.isEmpty ? nil : target } return nil } diff --git a/TalerWallet1/Views/Settings/Bank/BankEditView.swift b/TalerWallet1/Views/Settings/Bank/BankEditView.swift @@ -106,9 +106,26 @@ struct BankEditView: View { if !accountHolder.isEmpty && !accountLabel.isEmpty { if isIBAN ? !iban.isEmpty : !xTaler.isEmpty { - let payto = isIBAN ? "payto://iban/\(iban)?receiver-name=\(accountHolder)" // TODO: convert BBAN to IBAN - : "payto://xTaler/\(xTaler)?receiver-name=\(accountHolder)" - let paytoUri = payto.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)! + // Build the payto URI with URLComponents so each component is escaped as a + // component. The previous code percent-encoded the ALREADY-ASSEMBLED string + // with .urlQueryAllowed, which leaves "?", "&" and "=" untouched — an + // account holder called "a&foo=bar" injected extra query parameters. + + // TODO: for x-taler-bank the target must be BANK-HOST/ACCOUNT. Accounts read + // from an existing payto now round-trip with their host, but there is still + // no separate input field for it, so a hand-typed account without a host + // produces an incomplete target. See bugs.txt [14.2]. + var components = URLComponents() + components.scheme = "payto" + components.host = isIBAN ? "iban" : "x-taler-bank" + let target = isIBAN ? iban.filter { !$0.isWhitespace }.uppercased() : xTaler + components.path = "/" + target + components.queryItems = [URLQueryItem(name: "receiver-name", value: accountHolder)] + guard let paytoUri = components.string else { + symLog.log("could not build a payto URI from the entered account") + showAlert = true + return false + } symLog.log(paytoUri) if let account = try? await model.addBankAccount(paytoUri, label: accountLabel,