View Issue Details
| ID | Project | Category | View Status | Date Submitted | Last Update |
|---|---|---|---|---|---|
| 0012099 | Taler | wallet (WebExtension) | public | 2026-11-11 01:58 | 2026-11-11 01:58 |
| Reporter | bot-cg [agent] | Assigned To | Resolution deadline | ||
| Implementer | Reviewer | ||||
| Release signed by | Deployed by | ||||
| Verifier | Communicator | CM_7 | |||
| Data protection authority notification required | No | ||||
| CSIRT notification required | No | ||||
| Estimated effort (hours) | Actual effort (hours) | 0 | |||
| Fast-track | No | ||||
| Work package | none | ||||
| Priority | normal | Severity | minor | Reproducibility | have not tried |
| Status | new | Resolution | open | ||
| Summary | 0012099: WebExtension: an expired or already used peer link says only "This peer payment is no longer available." -- wallet-core's purseExpired is ignored (patch attached) | ||||
| Description | Opening a peer payment link that can no longer be used -- a taler://pay-push whose money expired or was taken back, or a taler://pay-pull request that expired or was already paid -- the web wallet says only "This peer payment is no longer available." for every case. wallet-core tells the UI which case it is: both purse-gone errors (WALLET_PEER_PUSH_CREDIT_PURSE_GONE, WALLET_PEER_PULL_DEBIT_PURSE_GONE) carry purseExpired: true/false (see 0011654). For an expired request the screen additionally offers "Withdraw funds", which cannot help. Android shows wallet-core's reason ("this payment expired", "this invoice expired"; untranslated); iOS shows the same text under "Internal core error" (0011934). Screenshots (demo backend, links created with a 2-minute expiry and opened afterwards): - before-web-1-push-expired.png, before-web-2-pull-expired.png: web, "This peer payment is no longer available." (+ "Withdraw funds" for the request) - before-android-1-push-expired.png, before-android-3-pull-expired.png (and -2 behind the sheet): Android "this payment expired" / "this invoice expired" - before-ios-1-push-expired.png: iOS "Internal core error" / "this payment expired" - after-web-1-push-expired.png, after-web-2-pull-expired.png: with the patch, "This payment link has expired." / "This payment request has expired.", no "Withdraw funds" Code (taler-typescript-core origin/master bf2e571a2, packages/wallet-webui/src/): - ui/error.ts:73-75: both PURSE_GONE codes -> one sentence, purseExpired unused - screens/PeerReceiveScreen.tsx:67-74: "Withdraw funds" for every error of a pay request wallet-core: pay-peer-push-credit.ts:759-782 and 1541-1548 ({ purseExpired }, "this payment expired" / "the sender aborted this payment"), pay-peer-pull-debit.ts:2010-2040 ({ purseExpired }, "this invoice expired" / "this invoice was already paid or withdrawn by the payee"). Patch (attached, web-peer-link-gone-reason.patch): errorMessage() uses purseExpired to say "This payment link has expired." / "This payment request has expired." or, when not expired, "This payment was cancelled by the sender or has already been received." / "This payment request was already paid or withdrawn."; without the flag the old sentence stays. PeerReceiveScreen hides "Withdraw funds" for a request that is gone. Four new source strings. Verification: Chrome extension build; after-web-1/2 for the expired cases (the not-expired variants could not be produced with the test backend). pnpm typecheck: no errors in the touched files (29 pre-existing elsewhere). Assisted by LLM | ||||
| Steps To Reproduce | 1. Let another wallet create a pay-push and a pay-pull link with a short expiry (e.g. 2 minutes) and wait until they expire. 2. Open them in the web wallet: both say only "This peer payment is no longer available."; the request also offers "Withdraw funds". | ||||
| Tags | No tags attached. | ||||
| Attached Files | web-peer-link-gone-reason.patch (3,064 bytes)
diff --git a/packages/wallet-webui/src/screens/PeerReceiveScreen.tsx b/packages/wallet-webui/src/screens/PeerReceiveScreen.tsx
index bb4cde691..d1638ea82 100644
--- a/packages/wallet-webui/src/screens/PeerReceiveScreen.tsx
+++ b/packages/wallet-webui/src/screens/PeerReceiveScreen.tsx
@@ -1,3 +1,4 @@
+import { TalerErrorCode } from "@gnu-taler/taler-util";
import { Button } from "../ui/Button.js";
import { Card } from "../ui/Card.js";
import { ErrorCard } from "../ui/ErrorCard.js";
@@ -25,6 +26,10 @@ export function PeerReceiveScreen(props: {
onWithdraw: () => void;
}) {
const receive = props.kind === "receive";
+ // more money does not help with a request that expired or was paid
+ const requestGone =
+ props.error?.detail?.code ===
+ TalerErrorCode.WALLET_PEER_PULL_DEBIT_PURSE_GONE;
return (
<div class="mx-auto w-full max-w-2xl space-y-6">
<div class="flex items-center gap-4">
@@ -64,7 +69,7 @@ export function PeerReceiveScreen(props: {
onClick={props.onRetryObservation}
>{i18n.str`Retry updates`}</Button>
)}
- {!receive && (
+ {!receive && !requestGone && (
<div class="mt-4">
<Button
tone="secondary"
diff --git a/packages/wallet-webui/src/ui/error.ts b/packages/wallet-webui/src/ui/error.ts
index 1450c2531..90cc8edab 100644
--- a/packages/wallet-webui/src/ui/error.ts
+++ b/packages/wallet-webui/src/ui/error.ts
@@ -71,8 +71,21 @@ function errorMessage(detail: TalerErrorDetail, fallback: string): string {
case TalerErrorCode.WALLET_NO_SUITABLE_EXCHANGE:
return /* Translators: An exchange is a GNU Taler service issuing and redeeming digital cash, not an action that converts one currency into another. */ i18n.str`No compatible exchange is available for this operation.`;
case TalerErrorCode.WALLET_PEER_PULL_DEBIT_PURSE_GONE:
- case TalerErrorCode.WALLET_PEER_PUSH_CREDIT_PURSE_GONE:
+ case TalerErrorCode.WALLET_PEER_PUSH_CREDIT_PURSE_GONE: {
+ // wallet-core says whether the link expired or was used/withdrawn
+ const purseExpired = (detail as { purseExpired?: boolean }).purseExpired;
+ const push =
+ detail.code === TalerErrorCode.WALLET_PEER_PUSH_CREDIT_PURSE_GONE;
+ if (purseExpired === true)
+ return push
+ ? i18n.str`This payment link has expired.`
+ : i18n.str`This payment request has expired.`;
+ if (purseExpired === false)
+ return push
+ ? /* Translators: The money of a peer payment link is gone because the sender took it back or another wallet received it. */ i18n.str`This payment was cancelled by the sender or has already been received.`
+ : i18n.str`This payment request was already paid or withdrawn.`;
return /* Translators: Peer payments transfer digital cash between people using links. A shared link can offer money to receive or request money to be paid. */ i18n.str`This peer payment is no longer available.`;
+ }
default:
return fallback;
}
| ||||
| related to | 0011654 | closed | Florian Dold | wallet-core should use local time to distinguish purse gone reasons |
| Date Modified | Username | Field | Change |
|---|---|---|---|
| 2026-11-11 01:58 | bot-cg | New Issue | |
| 2026-11-11 01:58 | bot-cg | Relationship added | related to 0011654 |
| 2026-11-11 01:58 | bot-cg | File Added: before-web-1-push-expired.png | |
| 2026-11-11 01:58 | bot-cg | File Added: before-web-2-pull-expired.png | |
| 2026-11-11 01:58 | bot-cg | File Added: before-android-1-push-expired.png | |
| 2026-11-11 01:58 | bot-cg | File Added: before-android-2-push-expired-behind.png | |
| 2026-11-11 01:58 | bot-cg | File Added: before-android-3-pull-expired.png | |
| 2026-11-11 01:58 | bot-cg | File Added: before-ios-1-push-expired.png | |
| 2026-11-11 01:58 | bot-cg | File Added: after-web-1-push-expired.png | |
| 2026-11-11 01:58 | bot-cg | File Added: after-web-2-pull-expired.png | |
| 2026-11-11 01:58 | bot-cg | File Added: web-peer-link-gone-reason.patch |