taler-typescript-core

Wallet core logic and WebUIs for various components
Log | Files | Refs | Submodules | README | LICENSE

commit 8a81f4aa08d607caffcd8b3c2fca21fe9605cb64
parent ec9ede6a90cb49f0d628c14bd60cb4795c78b7d1
Author: Sebastian <sebasjm@taler-systems.com>
Date:   Thu,  9 Apr 2026 11:11:09 -0300

better way to handle differant up/low case on taler:// parsing

Diffstat:
Mpackages/taler-util/src/taleruri.ts | 16+++++++++++++---
Mpackages/taler-wallet-webextension/src/wallet/QrReader.tsx | 20+++++++-------------
2 files changed, 20 insertions(+), 16 deletions(-)

diff --git a/packages/taler-util/src/taleruri.ts b/packages/taler-util/src/taleruri.ts @@ -390,6 +390,12 @@ export namespace TalerUris { * do not check path component format */ ignoreComponentError?: boolean; + /** + * tolerate upper-case on taler:// and + * target action. + * Userful for user input + */ + ignoreUppercase?: boolean; } export type InvalidTargetPathDetail = @@ -458,9 +464,10 @@ export namespace TalerUris { > { // check prefix let isHttp = false; + const prefixCheck = opts.ignoreUppercase ? s.toLowerCase() : s if ( - !s.startsWith(TALER_PREFIX) && - !(isHttp = s.startsWith(TALER_HTTP_PREFIX)) + !prefixCheck.startsWith(TALER_PREFIX) && + !(isHttp = prefixCheck.startsWith(TALER_HTTP_PREFIX)) ) { return Result.error(TalerUriParseError.WRONG_PREFIX); } @@ -473,9 +480,12 @@ export namespace TalerUris { // check if supported const firstSlashPos = path.indexOf("/"); - const uriType = ( + const uriTypeUncased = ( firstSlashPos === -1 ? path : path.slice(0, firstSlashPos) ) as TalerUriAction; + + const uriType = opts.ignoreUppercase ? uriTypeUncased.toLowerCase() as TalerUriAction : uriTypeUncased; + if (!supported_targets[uriType]) { return Result.errorWithDetail(TalerUriParseError.UNSUPPORTED, { uriType, diff --git a/packages/taler-wallet-webextension/src/wallet/QrReader.tsx b/packages/taler-wallet-webextension/src/wallet/QrReader.tsx @@ -353,18 +353,18 @@ export function QrReaderPage({ onDetected }: Props): VNode { const canvasRef = useRef<HTMLCanvasElement>(null); const [error, setError] = useState<TranslatedString | undefined>(); const [value, setValue] = useState(""); + const [uri, setUri] = useState<TalerUris.URI>(); const [show, setShow] = useState<"canvas" | "video" | "nothing">("nothing"); const { i18n } = useTranslationContext(); async function onChangeDetect(str: string) { + setValue(str); if (str) { - const lstr = str.toLowerCase(); - const uriResp = TalerUris.fromString(lstr); + const uriResp = TalerUris.fromString(str, { ignoreUppercase: true }); if (uriResp.tag === "error") { setError(translateTalerUriError(uriResp, i18n)); - setValue(str); return; } const { value: uri } = uriResp; @@ -372,32 +372,28 @@ export function QrReaderPage({ onDetected }: Props): VNode { const errorMsg = await testValidUriDebounced(uri, i18n); if (errorMsg) { setError(errorMsg); - setValue(str); return; } onDetected(uri); setError(undefined); - setValue(str); + setUri(uri); } else { setError(undefined); - setValue(str); } } function onChange(str: string) { + setValue(str); if (str) { - const lstr = str.toLowerCase(); - const uriResp = TalerUris.fromString(lstr); - + const uriResp = TalerUris.fromString(str, { ignoreUppercase: true }); if (uriResp.tag === "error") { setError(translateTalerUriError(uriResp, i18n)); - setValue(str); return; } const { value: uri } = uriResp; setError(i18n.str`checking...`); - setValue(str); + setUri(uri); testValidUriDebounced(uri, i18n).then((errorMsg) => { if (errorMsg) { setError(errorMsg); @@ -407,7 +403,6 @@ export function QrReaderPage({ onDetected }: Props): VNode { }); } else { setError(undefined); - setValue(str); } } @@ -458,7 +453,6 @@ export function QrReaderPage({ onDetected }: Props): VNode { setError(i18n.str`Unexpected error happen reading the file: ${error}`); } } - const uri = Result.orElse(TalerUris.fromString(value), undefined); return ( <Container>