commit f31e901f43e61b16ac1ce31753917f3c42cbbed0
parent 139b03f9afb5bb8b511c9dd6d09680c467560ba2
Author: Florian Dold <florian@dold.me>
Date: Thu, 9 Jul 2026 19:34:34 +0200
fix subject/message confusion in payto URIs
Diffstat:
4 files changed, 29 insertions(+), 15 deletions(-)
diff --git a/packages/libeufin-bank-webui/src/pages/PaytoWireTransferForm.tsx b/packages/libeufin-bank-webui/src/pages/PaytoWireTransferForm.tsx
@@ -297,6 +297,7 @@ export function PaytoWireTransferForm({
setAmount(Amounts.stringifyValue(amount));
}
}
+ // FIXME: Why? Do we still need this fallback?
const subject = !parsed.value.params["message"]
? parsed.value.params["subject"]
: parsed.value.params["message"];
diff --git a/packages/taler-util/src/payto.ts b/packages/taler-util/src/payto.ts
@@ -19,6 +19,7 @@ import { generateFakeSegwitAddress } from "./bitcoin.js";
import { Codec, Context, DecodingError, renderContext } from "./codec.js";
import { assertUnreachable } from "./errors.js";
import { IbanString, parseIban, ParseIbanError } from "./iban.js";
+import { AmountString } from "./index.node.js";
import { Result, ResultError, ResultOk } from "./result.js";
import {
decodeCrock,
@@ -965,6 +966,12 @@ export interface PaytoUriCyclos extends PaytoUriGeneric {
account: string;
}
+export interface WellKnownPaytoParams {
+ amount?: AmountString;
+ message?: string;
+ ["ch-qrr"]?: string;
+}
+
/**
* Add query parameters to a payto URI.
*
@@ -972,7 +979,7 @@ export interface PaytoUriCyclos extends PaytoUriGeneric {
*/
export function addPaytoQueryParams(
s: string,
- params: { [name: string]: string },
+ params: WellKnownPaytoParams,
): string {
const [acct, search] = s.slice(PAYTO_PREFIX.length).split("?");
const searchParams = new URLSearchParams(search || "");
diff --git a/packages/taler-wallet-core/src/common.ts b/packages/taler-wallet-core/src/common.ts
@@ -1181,7 +1181,7 @@ export async function prepareTransferOptionsRaw(
});
if (reservePub != null) {
paytoUri = addPaytoQueryParams(paytoUri, {
- subject: `Taler ${reservePub}`,
+ message: `Taler ${reservePub}`,
});
}
return {
diff --git a/packages/taler-wallet-webextension/src/components/BankDetailsByPaytoType.tsx b/packages/taler-wallet-webextension/src/components/BankDetailsByPaytoType.tsx
@@ -96,7 +96,8 @@ export function BankDetailsForWithdrawal({
const accounts = unsortedAccounts.sort(accountOrder);
const options = accounts.flatMap((account) =>
- account.transferOptions.sort(optionOrder))
+ account.transferOptions.sort(optionOrder),
+ );
const selectedOption = options[index];
// const altCurrency = selectedOption.account.currencySpecification?.name;
@@ -105,8 +106,8 @@ export function BankDetailsForWithdrawal({
case "ch-qr-bill":
case "payto": {
const payto = Result.unpack(Paytos.fromString(selectedOption.paytoUri));
- const amount = Amounts.parseOrThrow(payto.params["amount"])
- const subject = payto.params["subject"]
+ const amount = Amounts.parseOrThrow(payto.params["amount"]);
+ const subject = payto.params["message"];
// make sure the payto has the right params
// payto.params["amount"] = altCurrency
// ? selectedOption.account.transferAmount!
@@ -250,18 +251,20 @@ export function BankDetailsForWithdrawal({
}
export function BankDetailsForKycAuth({
- info
-}: { info: KycAuthTransferInfo }): VNode {
+ info,
+}: {
+ info: KycAuthTransferInfo;
+}): VNode {
const { i18n } = useTranslationContext();
const [index, setIndex] = useState(0);
- const { transferOptions: unsortedOptions } = info
+ const { transferOptions: unsortedOptions } = info;
if (!unsortedOptions.length) {
return <div>the exchange account list is empty</div>;
}
- const options = unsortedOptions.sort(optionOrder)
+ const options = unsortedOptions.sort(optionOrder);
const selectedOption = options[index];
@@ -269,8 +272,8 @@ export function BankDetailsForKycAuth({
case "ch-qr-bill":
case "payto": {
const payto = Result.unpack(Paytos.fromString(selectedOption.paytoUri));
- const amount = Amounts.parseOrThrow(payto.params["amount"])
- const subject = payto.params["subject"]
+ const amount = Amounts.parseOrThrow(payto.params["amount"]);
+ const subject = payto.params["message"];
// make sure the payto has the right params
// payto.params["amount"] = altCurrency
// ? selectedOption.account.transferAmount!
@@ -422,7 +425,7 @@ export function IBANAccountInfoTable({
subject: string;
qrCodes: QrCodeSpec[];
refCode?: string;
- payto: Paytos.URI
+ payto: Paytos.URI;
}) {
const { i18n } = useTranslationContext();
const api = useBackendContext();
@@ -560,7 +563,7 @@ export function IBANAccountInfoTable({
);
case PaytoType.Bitcoin:
case PaytoType.Ethereum:
- return <Fragment />
+ return <Fragment />;
default:
assertUnreachable(payto);
@@ -809,7 +812,10 @@ function Frame({
{accounts.length > 1 ? (
<Fragment>
{accounts.map((ac, acIdx) => {
- const desc = ac.type === "ch-qr-bill" ? i18n.str`Swiss Bill` : i18n.str`Wire transfer`
+ const desc =
+ ac.type === "ch-qr-bill"
+ ? i18n.str`Swiss Bill`
+ : i18n.str`Wire transfer`;
return (
<Button
key={acIdx}
@@ -818,7 +824,7 @@ function Frame({
updateIndex(acIdx);
}}
>
- {acIdx+1}) {desc}
+ {acIdx + 1}) {desc}
</Button>
);
})}