View Issue Details
| ID | Project | Category | View Status | Date Submitted | Last Update |
|---|---|---|---|---|---|
| 0012091 | Taler | wallet (WebExtension) | public | 2026-11-11 01:46 | 2026-11-11 01:46 |
| 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 | 0012091: Web wallet: the QR scanner silently ignores a QR code that is not a valid Taler link -- nothing tells the user what was scanned (Android/iOS do) (patch attached) | ||||
| Description | The QR scanner of the web wallet decodes a QR code that is not a valid GNU Taler (or payto) link and then silently ignores it: the camera keeps running, nothing is shown, and there is no hint to use "Enter link manually". To the user the scanner looks broken. The Android and iOS wallets tell the user what they scanned. What the user sees: - WebExtension, camera pointed at a QR code containing taler://frobnicate/x (an unknown action): "Scan a GNU Taler QR code / Keep the code inside the camera frame." with the code in view, indefinitely (before-web-1.png). Same for a QR code with plain text "hello" (before-web-2.png). Control: a QR code with taler://withdraw-exchange/exchange.demo.taler.net/ in the same setup opens the action at once (before-web-control-valid.png), so the codes are decoded and then dropped. - Android: an error sheet with the scanned content ("Unsupported URI: taler://frobnicate/x", before-android-1.png; the English literal is reported in 0012069). - iOS: "Unknown command: taler://frobnicate/x" (before-ios-1.png); for non-URL content "Scanned QR is no URL", for other URLs "Scanned QR is no talerURI" (QRSheet.swift:32-58). Code (taler-typescript-core bf2e571a2): - packages/wallet-webui/src/routes/App.tsx:3115-3124 (QrScanRoute): platform.actionInbox.put(code.data, "qr") inside try { ... } catch { // Ignore non-Taler QR payloads and keep scanning. } - packages/wallet-webui/src/platform/action-inbox.ts:46-53: validateActionUri throws for anything TalerUris.parse and Paytos.fromString reject. The patch (web-F410-scanner-reports-invalid-codes.patch): QrScanRoute remembers the last rejected payload (no flicker, re-set only when a different code is seen) and keeps scanning; QrScannerScreen shows it under the viewfinder in a role="status" box with the existing translated string "This wallet action is invalid or unsupported." and the (truncated) content. No new strings. after-web-1.png and after-web-2.png show the two cases with the patch; the valid-QR control still navigates immediately. Related observation (not changed by this patch): the same unknown action handed over as wallet.html?talerUri=taler://frobnicate/x (what the window.taler API produces) shows "Action could not be captured / The wallet could not save the requested action." with a "Retry capture" button, which misdescribes an unsupported link as a storage problem (before-web-param-unknown-action.png); via a page link the content script does not intercept it at all. Verified: wc-web build of the patched tree; QR shots with Chromium's fake camera (--use-file-for-fake-video-capture) before and after. Assisted by LLM | ||||
| Steps To Reproduce | 1. Open Scan QR code. 2. Show the camera a QR code containing taler://frobnicate/x or plain text. 3. Nothing happens; the scanner keeps running without any message. | ||||
| Tags | No tags attached. | ||||
| Attached Files | web-F410-scanner-reports-invalid-codes.patch (2,696 bytes)
diff --git a/packages/wallet-webui/src/routes/App.tsx b/packages/wallet-webui/src/routes/App.tsx
index e649abaf4..399057537 100644
--- a/packages/wallet-webui/src/routes/App.tsx
+++ b/packages/wallet-webui/src/routes/App.tsx
@@ -3096,10 +3096,12 @@ function QrScanRoute() {
const [, navigate] = useLocation();
const videoRef = useRef<HTMLVideoElement>(null);
const [error, setError] = useState<string>();
+ const [rejected, setRejected] = useState<string>();
useEffect(() => {
let stream: MediaStream | undefined;
let frame = 0;
let finished = false;
+ let lastRejected: string | undefined;
const canvas = document.createElement("canvas");
const scan = async () => {
const video = videoRef.current;
@@ -3120,7 +3122,11 @@ function QrScanRoute() {
navigate(`/action/${entry.id}`, { replace: true });
return;
} catch {
- // Ignore non-Taler QR payloads and keep scanning.
+ // Not a Taler link: say so, and keep scanning.
+ if (code.data !== lastRejected) {
+ lastRejected = code.data;
+ setRejected(code.data);
+ }
}
}
}
@@ -3164,6 +3170,7 @@ function QrScanRoute() {
<QrScannerScreen
videoRef={videoRef}
error={error}
+ rejected={rejected}
onEnterLink={() => navigate("/enter")}
onCancel={() => navigate("/")}
/>
diff --git a/packages/wallet-webui/src/screens/QrScannerScreen.tsx b/packages/wallet-webui/src/screens/QrScannerScreen.tsx
index 51f47e14f..5638fe6fc 100644
--- a/packages/wallet-webui/src/screens/QrScannerScreen.tsx
+++ b/packages/wallet-webui/src/screens/QrScannerScreen.tsx
@@ -6,6 +6,8 @@ import { i18n } from "../i18n/runtime.js";
export function QrScannerScreen(props: {
videoRef: Ref<HTMLVideoElement>;
error?: string;
+ /** Content of the last scanned QR code that is not a usable Taler link. */
+ rejected?: string;
onEnterLink: () => void;
onCancel: () => void;
}) {
@@ -31,6 +33,16 @@ export function QrScannerScreen(props: {
muted
/>
)}
+ {props.rejected !== undefined && (
+ <div role="status" class="mt-4 rounded-xl bg-errorContainer p-3 text-onErrorContainer">
+ <p>{i18n.str`This wallet action is invalid or unsupported.`}</p>
+ <p class="mt-1 break-all font-mono text-xs">
+ {props.rejected.length > 120
+ ? `${props.rejected.slice(0, 120)}…`
+ : props.rejected}
+ </p>
+ </div>
+ )}
<div class="mt-4 flex flex-wrap gap-3">
<Button
tone="secondary"
| ||||
| related to | 0012069 | new | Android: errors are shown as "Error" + wallet-core's English hint -- no translated message even for "could not reach the service"; "Unsupported URI" is a hard-coded English literal (patch attached) |
| Date Modified | Username | Field | Change |
|---|---|---|---|
| 2026-11-11 01:46 | bot-cg | New Issue | |
| 2026-11-11 01:46 | bot-cg | Relationship added | related to 0012069 |
| 2026-11-11 01:46 | bot-cg | File Added: before-web-1.png | |
| 2026-11-11 01:46 | bot-cg | File Added: before-web-2.png | |
| 2026-11-11 01:46 | bot-cg | File Added: before-web-control-valid.png | |
| 2026-11-11 01:46 | bot-cg | File Added: before-android-1.png | |
| 2026-11-11 01:46 | bot-cg | File Added: before-ios-1.png | |
| 2026-11-11 01:46 | bot-cg | File Added: before-web-param-unknown-action.png | |
| 2026-11-11 01:46 | bot-cg | File Added: after-web-1.png | |
| 2026-11-11 01:46 | bot-cg | File Added: after-web-2.png | |
| 2026-11-11 01:46 | bot-cg | File Added: web-F410-scanner-reports-invalid-codes.patch |