commit 8885175ca4f7800cb448ec28cd1f0143389ac0b7 parent 57b439c7ca540c97a3dcac9a8f874fa17f46aa58 Author: Florian Dold <dold@taler.net> Date: Sun, 23 Aug 2026 12:56:11 +0200 web-util: remove unused helpers and assets Diffstat:
27 files changed, 30 insertions(+), 1412 deletions(-)
diff --git a/packages/web-util/build.mjs b/packages/web-util/build.mjs @@ -30,64 +30,20 @@ let GIT_ROOT = BASE_DIR; while (!fs.existsSync(path.join(GIT_ROOT, ".git")) && GIT_ROOT !== "/") { GIT_ROOT = path.join(GIT_ROOT, "../"); } -const GIT_HASH = GIT_ROOT === "/" ? 'not defined' : git_hash(); +const GIT_HASH = GIT_ROOT === "/" ? "not defined" : git_hash(); -let PACKAGE_VERSION = get_version() +let PACKAGE_VERSION = get_version(); function get_version() { try { - return JSON.parse(fs.readFileSync(path.join(BASE_DIR, "package.json"))).version; + return JSON.parse(fs.readFileSync(path.join(BASE_DIR, "package.json"))) + .version; } catch { - return 'not defined' + return "not defined"; } } function git_hash() { - return execSync(`git rev-parse HEAD`, { encoding: 'utf-8' }).trim(); -} - -/** - * Problem: - * No loader is configured for ".node" files: ../../node_modules/.pnpm/fsevents@2.3.3/node_modules/fsevents/fsevents.node - * - * Reference: - * https://github.com/evanw/esbuild/issues/1051#issuecomment-806325487 - * - * kept as reference, need to be tested on MacOs - */ -const nativeNodeModulesPlugin = { - name: 'native-node-modules', - setup(build) { - // If a ".node" file is imported within a module in the "file" namespace, resolve - // it to an absolute path and put it into the "node-file" virtual namespace. - build.onResolve({ filter: /\.node$/, namespace: 'file' }, args => ({ - path: require.resolve(args.path, { paths: [args.resolveDir] }), - namespace: 'node-file', - })) - - // Files in the "node-file" virtual namespace call "require()" on the - // path from esbuild of the ".node" file in the output directory. - build.onLoad({ filter: /.*/, namespace: 'node-file' }, args => ({ - contents: ` - import path from ${JSON.stringify(args.path)} - try { module.exports = require(path) } - catch {} - `, - })) - - // If a ".node" file is imported within a module in the "node-file" namespace, put - // it in the "file" namespace where esbuild's default loading behavior will handle - // it. It is already an absolute path since we resolved it to one above. - build.onResolve({ filter: /\.node$/, namespace: 'node-file' }, args => ({ - path: args.path, - namespace: 'file', - })) - - // Tell esbuild's default loading behavior to use the "file" loader for - // these ".node" files. - let opts = build.initialOptions - opts.loader = opts.loader || {} - opts.loader['.node'] = 'file' - }, + return execSync(`git rev-parse HEAD`, { encoding: "utf-8" }).trim(); } const buildConfigBase = { @@ -97,8 +53,6 @@ const buildConfigBase = { minify: false, target: ["es2023"], loader: { - ".key": "text", - ".crt": "text", ".node": "file", ".html": "text", ".svg": "dataurl", @@ -109,7 +63,6 @@ const buildConfigBase = { __VERSION__: `"${PACKAGE_VERSION}"`, __GIT_HASH__: `"${GIT_HASH}"`, }, - //plugins: [nativeNodeModulesPlugin], }; /** @@ -149,7 +102,14 @@ const buildConfigTesting = { }, format: "esm", platform: "browser", - external: ["preact", "@gnu-taler/taler-util", "jed", "swr", "axios", "node:child_process"], + external: [ + "preact", + "@gnu-taler/taler-util", + "jed", + "swr", + "axios", + "node:child_process", + ], jsxFactory: "h", jsxFragment: "Fragment", }; @@ -159,14 +119,13 @@ const buildConfigTesting = { */ const buildConfigNode = { ...buildConfigBase, - entryPoints: ["src/index.node.ts", "src/cli.ts"], + entryPoints: ["src/index.node.ts"], outExtension: { ".js": ".cjs", }, format: "cjs", platform: "node", external: ["preact"], - }; /** @@ -192,14 +151,11 @@ const buildConfigBrowser = { jsxFragment: "Fragment", }; -[ - buildConfigNode, - buildConfigBrowser, - buildConfigBuild, - buildConfigTesting, -].forEach((config) => { - esbuild.build(config).catch((e) => { - console.log(e); - process.exit(1); - }); -}); +await Promise.all( + [ + buildConfigNode, + buildConfigBrowser, + buildConfigBuild, + buildConfigTesting, + ].map((config) => esbuild.build(config)), +); diff --git a/packages/web-util/create_certificate.sh b/packages/web-util/create_certificate.sh @@ -1,48 +0,0 @@ -#!/usr/bin/env bash -set -eu -org=localhost-ca -domain=localhost - -rm -rf keys -mkdir keys -cd keys - -openssl genpkey -algorithm RSA -out ca.key -openssl req -x509 -key ca.key -out ca.crt \ - -subj "/CN=$org/O=$org" - -openssl genpkey -algorithm RSA -out "$domain".key -openssl req -new -key "$domain".key -out "$domain".csr \ - -subj "/CN=$domain/O=$org" - -openssl x509 -req -in "$domain".csr -days 365 -out "$domain".crt \ - -CA ca.crt -CAkey ca.key -CAcreateserial \ - -extfile <(cat <<END -basicConstraints = CA:FALSE -subjectKeyIdentifier = hash -authorityKeyIdentifier = keyid,issuer -subjectAltName = DNS:$domain -END - ) - -sudo cp ca.crt /usr/local/share/ca-certificates/testing.crt -sudo update-ca-certificates - - -echo ' -## Chrome -1. go to chrome://settings/certificates -2. tab "authorities" -3. button "import" -4. choose "ca.crt" -5. trust for identify websites - -## Firefox -1. go to about:preferences#privacy -2. button "view certificates" -3. button "import" -4. choose "ca.crt" -5. trust for identify websites -' - -echo done! diff --git a/packages/web-util/package.json b/packages/web-util/package.json @@ -3,8 +3,6 @@ "version": "1.6.32", "description": "Generic helper functionality for GNU Taler Web Apps", "type": "module", - "types": "./lib/index.node.d.ts", - "main": "./dist/taler-web-cli.cjs", "author": "Sebastian Marchano", "license": "AGPL-3.0-or-later", "private": false, @@ -27,7 +25,7 @@ } }, "scripts": { - "build": "tsc && ./build.mjs", + "build": "pnpm run clean && tsc && ./build.mjs", "build:with-deps": "pnpm --filter \"{.}...\" run build", "i18n:source2po": "pogen extract && pogen merge", "i18n:po2strings": "pogen emit", @@ -59,7 +57,6 @@ }, "dependencies": { "@types/chrome": "0.0.197", - "qrcode-generator": "1.4.4", "tailwindcss": "3.4.17" }, "pogen": { diff --git a/packages/web-util/src/assets/logo-2021.svg b/packages/web-util/src/assets/logo-2021.svg @@ -1,9 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 201 90"> - <g fill="#0042b3" fill-rule="evenodd" stroke-width=".3"> - <path d="M86.7 1.1c15.6 0 29 9.4 36 23.2h-5.9A35.1 35.1 0 0086.7 6.5C67 6.5 51 23.6 51 44.7c0 10.4 3.8 19.7 10 26.6a31.4 31.4 0 01-4.2 3A45.2 45.2 0 0146 44.7c0-24 18.2-43.6 40.7-43.6zm35.8 64.3a40.4 40.4 0 01-39 22.8c3-1.5 6-3.5 8.6-5.7a35.6 35.6 0 0024.6-17.1z" /> - <path d="M64.2 1.1l3.1.1c-3 1.6-5.9 3.5-8.5 5.8a37.5 37.5 0 00-30.2 37.7c0 14.3 7.3 26.7 18 33.3a29.6 29.6 0 01-8.5.2c-9-8-14.6-20-14.6-33.5 0-24 18.2-43.6 40.7-43.6zm5.4 81.4a35.6 35.6 0 0024.6-17.1h5.9a40.4 40.4 0 01-39 22.8c3-1.5 5.9-3.5 8.5-5.7zm24.8-58.2a37 37 0 00-12.6-12.8 29.6 29.6 0 018.5-.2c4 3.6 7.4 8 9.9 13z" /> - <path d="M41.8 1.1c1 0 2 0 3.1.2-3 1.5-5.9 3.4-8.5 5.6A37.5 37.5 0 006.1 44.7c0 21.1 16 38.3 35.7 38.3 12.6 0 23.6-7 30-17.6h5.8a40.4 40.4 0 01-35.8 23C19.3 88.4 1 68.8 1 44.7c0-24 18.2-43.6 40.7-43.6zm30.1 23.2a38.1 38.1 0 00-4.5-6.1c1.3-1.2 2.7-2.2 4.3-3 2.3 2.7 4.4 5.8 6 9.1z" /> - </g> - <path d="M76.1 34.4h9.2v-5H61.9v5H71v26h5.1zM92.6 52.9h13.7l3 7.4h5.3l-12.7-31.2h-4.7L84.5 60.3h5.2zm11.8-4.9h-9.9l5-12.4zM123.8 29.4h-4.6v31h20.6v-5h-16zM166.5 29.4H145v31h21.6v-5H150v-8.3h14.5v-4.9h-14.5v-8h16.4zM191.2 39.5c0 1.6-.5 2.8-1.6 3.8s-2.6 1.4-4.4 1.4h-7.4V34.3h7.4c1.9 0 3.4.4 4.4 1.3 1 .9 1.6 2.2 1.6 3.9zm6 20.8l-7.7-11.7c1-.3 1.9-.7 2.7-1.3a8.8 8.8 0 003.6-4.6c.4-1 .5-2.2.5-3.5 0-1.5-.2-2.9-.7-4.1a8.4 8.4 0 00-2.1-3.1c-1-.8-2-1.5-3.4-2-1.3-.4-2.8-.6-4.5-.6h-12.9v31h5V49.4h6.5l7 10.8z" /> -</svg> -\ No newline at end of file diff --git a/packages/web-util/src/assets/logo-white.svg b/packages/web-util/src/assets/logo-white.svg @@ -1,45 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - width="670" - height="300" - viewBox="0 0 201 90" - version="1.1" - id="svg8"> - <g - id="logo"> - <g - id="circles" - style="fill:#FFF;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.327943"> - <path - d="m 86.662153,1.1211936 c 15.589697,0 29.129227,9.4011664 35.961027,23.2018054 h -5.81736 C 110.4866,13.623304 99.349002,6.5180852 86.662153,6.5180852 c -19.690571,0 -35.652876,17.1120008 -35.652876,38.2205688 0,10.331797 3.825597,19.704678 10.03957,26.582945 -1.342357,1.120912 -2.771532,2.127905 -4.275488,3.006754 C 50.071485,66.553412 45.974857,56.15992 45.974857,44.738654 c 0,-24.089211 18.216325,-43.6174604 40.687296,-43.6174604 z M 122.51416,65.375898 c -6.86645,13.680134 -20.34561,22.980218 -35.852007,22.980218 -1.052702,0 -2.096093,-0.04291 -3.128683,-0.127026 3.052192,-1.561167 5.913582,-3.480387 8.538307,-5.707305 10.320963,-1.684389 19.185983,-8.113638 24.601813,-17.145887 z" - id="path2350" /> - <path - d="m 64.212372,1.1211936 c 1.052607,0 2.095998,0.042919 3.128684,0.1270583 C 64.288864,2.8094199 61.427378,4.728606 58.802653,6.9555572 41.679542,9.7498571 28.559494,25.601563 28.559494,44.738654 c 0,14.264563 7.29059,26.702023 18.093843,33.268925 -1.593656,0.26719 -3.226966,0.406948 -4.890748,0.406948 -1.239545,0 -2.46151,-0.07952 -3.663522,-0.229364 C 29.191129,70.184015 23.525076,58.171633 23.525076,44.738654 23.525076,20.649443 41.7414,1.1211936 64.212372,1.1211936 Z M 69.62209,82.521785 C 79.943207,80.837396 88.808164,74.407841 94.224059,65.375422 h 5.840511 c -6.866354,13.680305 -20.345548,22.980694 -35.852198,22.980694 -1.052703,0 -2.095999,-0.04291 -3.128684,-0.127026 3.052002,-1.561371 5.913836,-3.480218 8.538402,-5.707305 z M 94.355885,24.322999 c -3.13939,-5.314721 -7.467551,-9.74275 -12.584511,-12.853269 1.593656,-0.26719 3.226904,-0.406948 4.890779,-0.406948 1.239451,0 2.461512,0.07952 3.663524,0.229364 4.016018,3.607242 7.373195,8.030111 9.849053,13.030853 z" - id="path2352" /> - <path - d="m 41.762589,1.1211936 c 1.064296,0 2.118804,0.044379 3.162607,0.1302161 -3.046523,1.558961 -5.903162,3.4745139 -8.52358,5.6968133 C 19.254624,9.7205882 6.1097128,25.583465 6.1097128,44.738654 c 0,21.108568 15.9624012,38.22057 35.6528762,38.22057 12.599746,0 23.672446,-7.007056 30.013748,-17.583802 h 5.838515 C 70.748498,79.055727 57.26924,88.356116 41.762589,88.356116 c -22.470907,0 -40.6871998,-19.52825 -40.6871998,-43.617462 0,-24.089211 18.2162928,-43.6174604 40.6871998,-43.6174604 z M 71.905375,24.322999 c -1.31192,-2.220567 -2.830984,-4.287049 -4.528877,-6.166508 1.342452,-1.120945 2.771374,-2.128381 4.275139,-3.00723 2.372984,2.753011 4.418875,5.834636 6.072489,9.173738 z" - id="path2354" /> - </g> - <g - id="letters" - style="fill:#FFF"> - <path - d="m 76.135411,34.409066 h 9.161042 V 29.36588 H 61.857537 v 5.043186 h 9.161137 v 25.92317 h 5.116737 z" - id="path2346" /> - <path - d="m 92.647571,52.856334 h 13.659009 l 2.93009,7.476072 h 5.36461 L 101.89122,29.144903 H 97.187186 L 84.477089,60.332406 h 5.199533 z m 11.802109,-4.822276 h -9.944771 l 4.951718,-12.386462 z" - id="path2362" /> - <path - d="m 123.80641,29.366084 h -4.58038 v 30.966322 h 20.54728 v -4.910253 c -5.32227,0 -10.64463,0 -15.9669,0 z" - id="path2356" /> - <path - d="m 166.4722,29.366084 h -21.37564 v 30.966322 h 21.58203 v -4.910253 h -16.54771 v -8.27275 h 14.48439 V 42.23925 h -14.48439 v -7.962811 h 16.34132 z" - id="path2360" /> - <path - d="m 191.19035,39.474593 c 0,1.59947 -0.53646,2.87535 -1.61628,3.818883 -1.07281,0.95124 -2.52409,1.422837 -4.34678,1.422837 h -7.44851 V 34.276439 h 7.4073 c 1.9051,0 3.38376,0.435027 4.42939,1.312178 1.05226,0.870258 1.57488,2.167734 1.57488,3.885976 z m 6.06602,20.857813 -7.79911,-11.723191 c 1.01771,-0.294794 1.94631,-0.714813 2.78553,-1.260566 0.83885,-0.545619 1.56122,-1.209263 2.16629,-1.990627 0.60541,-0.781738 1.07981,-1.681096 1.42369,-2.698345 0.34378,-1.017553 0.51561,-2.175238 0.51561,-3.472883 0,-1.50409 -0.24743,-2.867948 -0.74267,-4.092048 -0.49515,-1.223794 -1.20344,-2.256186 -2.12499,-3.096734 -0.92173,-0.840446 -2.04957,-1.489252 -3.38375,-1.946452 -1.33447,-0.457267 -2.82692,-0.685476 -4.4774,-0.685476 h -12.87512 v 30.966322 h 5.03433 V 49.538522 h 6.37569 l 7.11829,10.793884 z" - id="path2358" /> - </g> - </g> -</svg> diff --git a/packages/web-util/src/assets/taler-logo-blue.png b/packages/web-util/src/assets/taler-logo-blue.png Binary files differ. diff --git a/packages/web-util/src/cli.ts b/packages/web-util/src/cli.ts @@ -1,50 +0,0 @@ -import { setGlobalLogLevelFromString } from "@gnu-taler/taler-util"; -import { clk } from "@gnu-taler/taler-util/clk"; -import { serve } from "./serve.js"; - -export const walletCli = clk - .program("wallet", { - help: "Command line interface for the GNU Taler wallet.", - }) - .maybeOption("log", ["-L", "--log"], clk.STRING, { - help: "configure log level (NONE, ..., TRACE)", - onPresentHandler: (x) => { - setGlobalLogLevelFromString(x); - }, - }) - .flag("version", ["-v", "--version"], { - onPresentHandler: printVersion, - }) - .flag("verbose", ["-V", "--verbose"], { - help: "Enable verbose output.", - }); - -walletCli - .subcommand("serve", "serve", { help: "Create a server." }) - .maybeOption("folder", ["-F", "--folder"], clk.STRING, { - help: "should complete", - // default: "./dist" - }) - .maybeOption("port", ["-P", "--port"], clk.INT, { - help: "should complete", - // default: 8000 - }) - .flag("development", ["-D", "--dev"], { - help: "should complete", - }) - .action(async (args) => { - return serve({ - folder: args.serve.folder || "./dist", - port: args.serve.port || 8000, - }); - }); - -declare const __VERSION__: string; -function printVersion(): void { - console.log(__VERSION__); - process.exit(0); -} - -export function main(): void { - walletCli.run(); -} diff --git a/packages/web-util/src/components/ErrorLoadingMerchant.tsx b/packages/web-util/src/components/ErrorLoadingMerchant.tsx @@ -1,51 +0,0 @@ -/* - This file is part of GNU Taler - (C) 2022 Taler Systems S.A. - - GNU Taler is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> - */ - -import { TalerError, TranslatedString } from "@gnu-taler/taler-util"; -import { Fragment, VNode, h } from "preact"; -import { useCommonPreferences } from "../context/common-preferences.js"; -import { useTranslationContext } from "../context/translation.js"; -import { translateTalerError } from "../hooks/useNotifications.js"; -import { Attention } from "./Attention.js"; - -function DebugInfo({ error }: { error: any }): VNode { - const [{ showDebugInfo }, update] = useCommonPreferences(); - if (!showDebugInfo) return <Fragment />; - return ( - <pre class="whitespace-break-spaces "> - {JSON.stringify(error, undefined, 2)} - </pre> - ); -} - -export function ErrorLoading({ - title, - error, -}: { - title: TranslatedString; - error: TalerError; -}): VNode { - const { i18n } = useTranslationContext(); - const description = translateTalerError(error, i18n); - return ( - <Attention type="danger" title={title}> - {(description ?? []).map((d, idx) => ( - <p key={idx}>{d}</p> - ))} - <DebugInfo error={error.errorDetail} /> - </Attention> - ); -} diff --git a/packages/web-util/src/components/NotificationCardBulma.tsx b/packages/web-util/src/components/NotificationCardBulma.tsx @@ -1,46 +0,0 @@ -import { h, VNode } from "preact"; - -export type MessageType = "INFO" | "WARN" | "ERROR" | "SUCCESS"; -export interface NotificationCard { - message: string; - description?: string | VNode; - details?: string | VNode | string; - type: MessageType; -} - -interface Props { - notification?: NotificationCard; -} - -export function NotificationCardBulma({ - notification: n, -}: Props): VNode | null { - if (!n) return null; - return ( - <div class="notification"> - <div class="columns is-vcentered"> - <div class="column is-12"> - <article - class={ - n.type === "ERROR" - ? "message is-danger" - : n.type === "WARN" - ? "message is-warning" - : "message is-info" - } - > - <div class="message-header"> - <p>{n.message}</p> - </div> - {n.description && ( - <div class="message-body"> - <div>{n.description}</div> - {n.details && <pre>{n.details}</pre>} - </div> - )} - </article> - </div> - </div> - </div> - ); -} diff --git a/packages/web-util/src/components/QR.tsx b/packages/web-util/src/components/QR.tsx @@ -1,292 +0,0 @@ -/* - This file is part of GNU Taler - (C) 2021-2024 Taler Systems S.A. - - GNU Taler is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> - */ - -import logo from "@assets/svg/logo/qr-logo.svg"; -import chFlag from "@assets/svg/swiss-qr-flag.svg"; -import { TalerUri, TalerUris, TranslatedString } from "@gnu-taler/taler-util"; -import { h, VNode } from "preact"; -import qrcode from "qrcode-generator"; - -function generate_qr( - text: string, - params: { - typeNumber?: TypeNumber; - errorCorrectionLevel?: ErrorCorrectionLevel; - } = {}, -) { - const qr = qrcode( - params.typeNumber ?? 0, - (params.errorCorrectionLevel = "H"), - ); - qr.addData(text, "Byte"); - qr.make(); - const image = qr.createSvgTag({ - scalable: true, - margin: 0, - }); - return `data:image/svg+xml,${encodeURIComponent(image)}`; -} - -export function QR_Taler({ uri }: { uri: TalerUri }): VNode { - const stringUri = TalerUris.stringify(uri); - return ( - <div - style={{ - width: "100%", - height: "100%", - maxWidth: 400, - margin: "auto", - padding: 10, // size of the animated border - borderRadius: 20, - background: `conic-gradient( - from var(--angle), - #0042B3 0deg, - #F1F1F4 20deg, - #F1F1F4 150deg, - #F1F1F4 160deg, - #0042B3 180deg, - #F1F1F4 200deg, - #F1F1F4 330deg, - #F1F1F4 340deg, - #0042B3) padding-box`, - animation: "rotate 10s linear infinite", - position: "relative", - }} - > - <div - style={{ - padding: 10, // separate the qr from the animated border - borderRadius: 20, // match the radius from the parent - backgroundColor: "white", // hide the background - }} - > - <img style={{ margin: 5 }} src={generate_qr(stringUri)} /> - </div> - <div - style={{ - position: "absolute", - top: "50%", - left: "50%", - transform: "translate(-50%, -50%)", - alignContent: "center", - display: "flex", - backgroundColor: "transparent", // section 19.90.4.3 - }} - > - <img src={logo} style={{ width: 100, height: 50 }} /> - </div> - </div> - ); -} - -export function QR_TOTP({ otpAuthURI }: { otpAuthURI: string }): VNode { - return ( - <div - style={{ - width: "90%", - maxWidth: 400, - margin: "auto", - padding: 10, - position: "relative", - }} - > - <div - style={{ - padding: 10, // separate the qr from the animated border - borderRadius: 20, // match the radius from the parent - backgroundColor: "white", // hide the background - }} - > - <img style={{ margin: 5 }} src={generate_qr(otpAuthURI)} /> - </div> - - <div - style={{ - position: "absolute", - top: "50%", - left: "50%", - transform: "translate(-50%, -50%)", - alignContent: "center", - }} - > - <div - style={{ - display: "flex", - border: "1px solid black", - backgroundColor: "white", - fontWeight: "bold", - padding: 5, - }} - > - T-OTP - </div> - </div> - </div> - ); -} - -export function QR_Generic({ - content, - title, -}: { - content: string; - title?: string; -}): VNode { - return ( - <div - style={{ - width: "90%", - maxWidth: 400, - margin: "auto", - padding: 10, - position: "relative", - }} - > - <div - style={{ - padding: 10, // separate the qr from the animated border - borderRadius: 20, // match the radius from the parent - backgroundColor: "white", // hide the background - }} - > - <img style={{ margin: 5 }} src={generate_qr(content)} /> - </div> - - {title === undefined ? undefined : ( - <div - style={{ - position: "absolute", - top: "50%", - left: "50%", - transform: "translate(-50%, -50%)", - alignContent: "center", - }} - > - <div - style={{ - display: "flex", - border: "1px solid black", - backgroundColor: "white", - fontWeight: "bold", - padding: 5, - }} - > - {title} - </div> - </div> - )} - </div> - ); -} -/** - * Based on the definition of Swiss Implementation Guidelines - * for the QR-bill - * @param param0 - * @returns - */ -export function QR_SwissBank({ text }: { text: string }): VNode { - return ( - <div - style={{ - width: "90%", - maxWidth: 300, - margin: "auto", - padding: 10, - position: "relative", - }} - > - <div - style={{ - padding: 10, // separate the qr from the animated border - borderRadius: 20, // match the radius from the parent - backgroundColor: "white", // hide the background - }} - > - <img - style={{ margin: 5 }} - src={generate_qr(text, { - typeNumber: 0, // section 6.2 - errorCorrectionLevel: "M", // section 6.1 - })} - /> - </div> - - <div - style={{ - position: "absolute", - top: "50%", - left: "50%", - transform: "translate(-50%, -50%)", - alignContent: "center", - }} - > - <div - style={{ - display: "flex", - backgroundColor: "white", - }} - > - <img src={chFlag} style={{ width: 50, height: 50 }} /> - </div> - </div> - </div> - ); -} - -export function QR_Bank({ - text, - label, -}: { - text: string; - label: TranslatedString; -}): VNode { - return ( - <div - style={{ - width: "90%", - maxWidth: 300, - margin: "auto", - position: "relative", - }} - > - <div - style={{ - padding: 10, // separate the qr from the animated border - borderRadius: 20, // match the radius from the parent - backgroundColor: "white", // hide the background - }} - > - <img style={{ margin: 5 }} src={generate_qr(text)} /> - </div> - - <div - style={{ - position: "absolute", - top: "50%", - left: "50%", - transform: "translate(-50%, -50%)", - alignContent: "center", - }} - > - <div - style={{ fontWeight: "bold", backgroundColor: "white", padding: 3 }} - > - {label} - </div> - </div> - </div> - ); -} diff --git a/packages/web-util/src/components/RenderAmount.tsx b/packages/web-util/src/components/RenderAmount.tsx @@ -54,44 +54,3 @@ export function RenderAmount({ </span> ); } - -export function RenderAmountBulma({ - value, - spec, - specMap, - negative, - withColor, - withSign, - hideSmall, -}: { - spec?: CurrencySpecification; - specMap?: Record<string, CurrencySpecification>; - value: AmountJson; - hideSmall?: boolean; - negative?: boolean; - withColor?: boolean; - withSign?: boolean; -}): VNode { - const neg = !!negative; - - const currentSpec = spec ?? (!specMap ? undefined : specMap[value.currency]); - - const { currency, normal, small } = Amounts.stringifyValueWithSpec( - value, - currentSpec, - ); - - return ( - <span - data-negative={withColor ? neg : undefined} - style={{ - whiteSpace: "nowrap", - color: withColor ? (negative ? "red" : "green") : undefined, - }} - > - {withSign && negative ? "- " : undefined} - {currency} {normal}{" "} - {!hideSmall && small && <sup style={{ marginLeft: -4 }}>{small}</sup>} - </span> - ); -} diff --git a/packages/web-util/src/components/index.ts b/packages/web-util/src/components/index.ts @@ -1,5 +1,5 @@ export * as utils from "./utils.js"; -export { onComponentUnload, preconnectAs, Preconnect } from "./utils.js"; +export { onComponentUnload } from "./utils.js"; export * from "./Attention.js"; export * from "./CopyButton.js"; export * from "./ErrorLoading.js"; @@ -13,5 +13,3 @@ export * from "./NotificationBanner.js"; export * from "./Time.js"; export * from "./RenderAmount.js"; export * from "./Pagination.js"; -export * from "./QR.js"; -export * from "./NotificationCardBulma.js"; diff --git a/packages/web-util/src/components/utils.ts b/packages/web-util/src/components/utils.ts @@ -83,30 +83,6 @@ export function onComponentUnload(callback: () => void) { }, []); } -const ownerDocument = typeof document === "undefined" ? null : document; -const preconnectsSet: Set<string> = new Set(); - -export type Preconnect = { - rel: "preconnect" | "dns-prefetch"; - href: string; - crossOrigin: string; -}; - -export function preconnectAs(pre: Preconnect[]) { - if (ownerDocument) { - pre.forEach(({ rel, href, crossOrigin }) => { - const key = `${rel}${href}${crossOrigin}`; - if (preconnectsSet.has(key)) return; - preconnectsSet.add(key); - const instance = ownerDocument.createElement("link"); - instance.setAttribute("rel", rel); - instance.setAttribute("crossOrigin", crossOrigin); - instance.setAttribute("href", href); - ownerDocument.head.appendChild(instance); - }); - } -} - export function composeRef<T>(...fn: ((e: T | null) => void)[]) { return (element: T | null) => { fn.forEach((handler) => { @@ -135,67 +111,3 @@ export function doAutoFocus<T extends HTMLElement>( }, 100); } } - -/** - * Show the element when the load ended - * @param element - */ -export function doAutoFocusWithScroll(element: HTMLElement | null) { - if (element) { - setTimeout(() => { - element.focus({ preventScroll: true }); - element.scrollIntoView({ - behavior: "smooth", - block: "center", - inline: "center", - }); - }, 100); - } -} - -/** - * - * @param obj VNode - * @returns - */ -export function saveVNodeForInspection<T>(obj: T): T { - // @ts-ignore - window["showVNodeInfo"] = function showVNodeInfo() { - inspect(obj); - }; - return obj; -} -function inspect(obj: any) { - if (!obj) return; - if (obj.__c && obj.__c.__H) { - const componentName = obj.__c.constructor.name; - const hookState = obj.__c.__H; - const stateList = hookState.__ as Array<any>; - console.log("==============", componentName); - stateList.forEach((hook) => { - const { __: value, c: context, __h: factory, __H: args } = hook; - if (typeof context !== "undefined") { - const { __c: contextId } = context; - console.log("context:", contextId, hook); - } else if (typeof factory === "function") { - console.log("memo:", value, "deps:", args); - } else if (typeof value === "function") { - const effectName = value.name; - console.log("effect:", effectName, "deps:", args); - } else if (typeof value.current !== "undefined") { - const ref = value.current; - console.log("ref:", ref instanceof Element ? ref.outerHTML : ref); - } else if (value instanceof Array) { - console.log("state:", value[0]); - } else { - console.log(hook); - } - }); - } - const children = obj.__k; - if (children instanceof Array) { - children.forEach((e) => inspect(e)); - } else { - inspect(children); - } -} diff --git a/packages/web-util/src/context/api.ts b/packages/web-util/src/context/api.ts @@ -1,49 +0,0 @@ -/* - This file is part of GNU Taler - (C) 2021-2025 Taler Systems S.A. - - GNU Taler is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> - */ - -/** - * - * @author Sebastian Javier Marchano (sebasjm) - */ - -import { - TalerBankIntegrationHttpClient, - TalerCoreBankHttpClient, - TalerRevenueHttpClient, - TalerWireGatewayHttpClient, -} from "@gnu-taler/taler-util"; -import { ComponentChildren, createContext, h, VNode } from "preact"; -import { useContext } from "preact/hooks"; - -interface Type { - bankCore: TalerCoreBankHttpClient; - bankIntegration: TalerBankIntegrationHttpClient; - bankWire: TalerWireGatewayHttpClient; - bankRevenue: TalerRevenueHttpClient; -} - -const Context = createContext<Type>(undefined as any); - -export const useApiContext = (): Type => useContext(Context); -export const ApiContextProvider = ({ - children, - value, -}: { - value: Type; - children: ComponentChildren; -}): VNode => { - return h(Context.Provider, { value, children }); -}; diff --git a/packages/web-util/src/context/common-preferences.ts b/packages/web-util/src/context/common-preferences.ts @@ -23,8 +23,6 @@ import { import { buildStorageKey } from "../hooks/useLocalStorage.js"; import { useMemoryStorage } from "../hooks/useMemoryStorage.js"; -const TALER_SCREEN_ID = 102; - interface Preferences { showDebugInfo: boolean; } diff --git a/packages/web-util/src/context/index.ts b/packages/web-util/src/context/index.ts @@ -1,4 +1,3 @@ -export { ApiContextProvider, useApiContext } from "./api.js"; export { InternationalizationAPI, TranslationProvider, @@ -6,7 +5,6 @@ export { } from "./translation.js"; export * from "./bank-api.js"; export * from "./challenger-api.js"; -export * from "./merchant-api.js"; export * from "./exchange-api.js"; export * from "./navigation.js"; export * from "./notification.js"; diff --git a/packages/web-util/src/context/merchant-api.ts b/packages/web-util/src/context/merchant-api.ts @@ -1,269 +0,0 @@ -/* - This file is part of GNU Taler - (C) 2022-2024 Taler Systems S.A. - - GNU Taler is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> - */ - -import { - CacheEvictor, - LibtoolVersion, - ObservabilityEvent, - ObservableHttpClientLibrary, - TalerError, - TalerErrorCode, - TalerMerchantApi, - TalerMerchantInstanceCacheEviction, - TalerMerchantManagementCacheEviction, - TalerMerchantManagementHttpClient, -} from "@gnu-taler/taler-util"; -import { - ComponentChildren, - FunctionComponent, - VNode, - createContext, - h, -} from "preact"; -import { useContext, useEffect, useMemo, useState } from "preact/hooks"; -import { ErrorLoading } from "../components/ErrorLoadingMerchant.js"; -import { BrowserFetchHttpLib } from "../utils/http-impl.sw.js"; -import { useTranslationContext } from "./translation.js"; -import { - APIClient, - ActiviyTracker, - MerchantLib, - Subscriber, -} from "./activity.js"; - -/** - * - * @author Sebastian Javier Marchano (sebasjm) - */ - -export type MerchantContextType = { - url: URL; - config: TalerMerchantApi.MerchantVersionResponse; - lib: MerchantLib; - hints: VersionHint[]; - onActivity: Subscriber<ObservabilityEvent>; - cancelRequest: (eventId: string) => void; - changeBackend: (url: URL) => void; -}; - -// FIXME: below -// @ts-expect-error default value to undefined, should it be another thing? -const MerchantContext = createContext<MerchantContextType>(undefined); - -export const useMerchantApiContext = (): MerchantContextType => - useContext(MerchantContext); - -enum VersionHint { - NONE, -} - -type Evictors = { - management?: CacheEvictor< - TalerMerchantManagementCacheEviction | TalerMerchantInstanceCacheEviction - >; -}; - -export type ConfigResult<T> = - | undefined - | { type: "ok"; config: T; hints: VersionHint[] } - | ConfigResultFail<T>; - -export type ConfigResultFail<T> = - | { type: "incompatible"; result: T; supported: string } - | { type: "error"; error: TalerError }; - -const CONFIG_FAIL_TRY_AGAIN_MS = 5000; - -export const MerchantApiProvider = ({ - baseUrl, - children, - evictors = {}, - frameOnError, -}: { - baseUrl: URL; - evictors?: Evictors; - children: ComponentChildren; - frameOnError: FunctionComponent<{ - status: ConfigResult<TalerMerchantApi.MerchantVersionResponse>; - children: ComponentChildren; - }>; -}): VNode => { - const [checked, setChecked] = - useState<ConfigResult<TalerMerchantApi.MerchantVersionResponse>>(); - const { i18n } = useTranslationContext(); - - const [merchantEndpoint, changeMerchantEndpoint] = useState(baseUrl); - - const { getRemoteConfig, VERSION, lib, cancelRequest, onActivity } = useMemo( - () => buildMerchantApiClient(merchantEndpoint, evictors), - [merchantEndpoint.href], - ); - - useEffect(() => { - let keepRetrying = true; - async function testConfig(): Promise<void> { - try { - const config = await getRemoteConfig(); - if (LibtoolVersion.compare(VERSION, config.version)) { - setChecked({ type: "ok", config, hints: [] }); - } else { - setChecked({ - type: "incompatible", - result: config, - supported: VERSION, - }); - } - } catch (error) { - if (error instanceof TalerError) { - if (keepRetrying) { - setTimeout(() => { - testConfig(); - }, CONFIG_FAIL_TRY_AGAIN_MS); - } - setChecked({ type: "error", error }); - } else { - setChecked({ type: "error", error: TalerError.fromException(error) }); - } - } - } - testConfig(); - return () => { - // on unload, stop retry - keepRetrying = false; - }; - }, []); - - if (checked === undefined) { - return h(frameOnError, { - status: checked, - children: h( - "div", - {}, - i18n.str`Checking compatibility of this webapp with backend service...`, - ), - }); - } - if (checked.type === "error") { - return h(frameOnError, { - status: checked, - children: h(ErrorLoading, { - title: i18n.str`There was an error trying to contact the backend service.`, - error: checked.error, - }), - }); - } - if (checked.type === "incompatible") { - const title = i18n.str`The server version is not supported. Supported version "${checked.supported}", server version "${checked.result.version}"`; - const error = TalerError.fromDetail( - TalerErrorCode.GENERIC_CLIENT_UNSUPPORTED_PROTOCOL_VERSION, - { - client: checked.supported, - server: checked.result.version, - }, - title, - ); - return h(frameOnError, { - status: checked, - children: h(ErrorLoading, { - title, - error, - }), - }); - } - - const value: MerchantContextType = { - url: merchantEndpoint, - config: checked.config, - onActivity: onActivity, - lib, - cancelRequest, - changeBackend: changeMerchantEndpoint, - hints: checked.hints, - }; - return h(MerchantContext.Provider, { - value, - children, - }); -}; - -function buildMerchantApiClient( - url: URL, - evictors: Evictors, -): APIClient<MerchantLib, TalerMerchantApi.MerchantVersionResponse> { - const httpFetch = new BrowserFetchHttpLib({ - enableThrottling: true, - requireTls: false, - }); - const tracker = new ActiviyTracker<ObservabilityEvent>(); - - const httpLib = new ObservableHttpClientLibrary(httpFetch, { - observe(ev) { - tracker.notify(ev); - }, - }); - - const instance = new TalerMerchantManagementHttpClient( - url.href, - httpLib, - evictors.management, - ); - - function getSubInstanceAPI(instanceId: string): MerchantLib { - const api = buildMerchantApiClient( - new URL(instance.getSubInstanceAPI(instanceId)), - evictors, - ); - return api.lib; - } - - async function getRemoteConfig(): Promise<TalerMerchantApi.MerchantVersionResponse> { - const resp = await instance.getConfig(); - if (resp.type === "fail") { - if (resp.detail) { - throw TalerError.fromUncheckedDetail(resp.detail); - } else { - throw TalerError.fromException( - new Error("failed to get merchant remote config"), - ); - } - } - return resp.body; - } - - return { - getRemoteConfig, - VERSION: TalerMerchantManagementHttpClient.PROTOCOL_VERSION, - lib: { - instance, - subInstanceApi: getSubInstanceAPI, - }, - onActivity: tracker.subscribe, - cancelRequest: httpLib.cancelRequest, - }; -} - -export const MerchantApiProviderTesting = ({ - children, - value, -}: { - value: MerchantContextType; - children: ComponentChildren; -}): VNode => { - return h(MerchantContext.Provider, { - value, - children, - }); -}; diff --git a/packages/web-util/src/keys/ca.crt b/packages/web-util/src/keys/ca.crt @@ -1,14 +0,0 @@ ------BEGIN CERTIFICATE----- -MIICODCCAaGgAwIBAgIUH8AY7kGN1yzGEwQOZKeL26ZOQHAwDQYJKoZIhvcNAQEL -BQAwLjEVMBMGA1UEAwwMbG9jYWxob3N0LWNhMRUwEwYDVQQKDAxsb2NhbGhvc3Qt -Y2EwHhcNMjIxMTMwMjIwNjAxWhcNMjIxMjMwMjIwNjAxWjAuMRUwEwYDVQQDDAxs -b2NhbGhvc3QtY2ExFTATBgNVBAoMDGxvY2FsaG9zdC1jYTCBnzANBgkqhkiG9w0B -AQEFAAOBjQAwgYkCgYEAo2gw/oYcKxrSeDbVTTFX8pZA8fojGMwcQlSmeYMUrhtn -+PkXEvCTyMWcreLg2Y4sgdOjvK0ZM7OXnf/jx4fDiMpGy5BHT2ZJRWPzSh6UmNUy -kyeRAkDB3gCyQSHmmL1rEFOuwmq1yoT0FlIyTQ+mWrs5yg7QTe1rRyFWXHIt1TMC -AwEAAaNTMFEwHQYDVR0OBBYEFO1Op1KRMkVkzadGy2TZFQlwG9FFMB8GA1UdIwQY -MBaAFO1Op1KRMkVkzadGy2TZFQlwG9FFMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI -hvcNAQELBQADgYEAIdePTdDsD8IBFfHze9YVU+VZg3aNO5F/6QJPy/8InejQU0V8 -9Cod19SEh3Kdlpa4QLvZH1cX+ac7bvhL0JaZg0dsz8UaZ8xrkEPx6JJAwgCiv/Ir -YqhoRd4fv/c6/B0yqD4Dhoy/jGkxfvc8XDnAuAP0uRttGwvsvHS9cSkHYFo= ------END CERTIFICATE----- diff --git a/packages/web-util/src/keys/ca.key b/packages/web-util/src/keys/ca.key @@ -1,16 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAKNoMP6GHCsa0ng2 -1U0xV/KWQPH6IxjMHEJUpnmDFK4bZ/j5FxLwk8jFnK3i4NmOLIHTo7ytGTOzl53/ -48eHw4jKRsuQR09mSUVj80oelJjVMpMnkQJAwd4AskEh5pi9axBTrsJqtcqE9BZS -Mk0Pplq7OcoO0E3ta0chVlxyLdUzAgMBAAECgYABkiDWcYeXynw3d595TH4h8NvS -96qatGuZH6MyC9aJDe5j8FEOd42UIoItEb9DmCBJZzVtvOQ/IPzWIf2Yj2+LvydI -qEA6ucroa9F9KG9T9ywNJfqM8fNzARQEAzK4/PglbT+n27hkNIm35BOA8PIUuBiD -pT6D0L0LHfNs6NkRAQJBAM9RS9ApnRmo4qV8kNJvysBJ/NO8PdLT47XIA2uPaAAT -O9NjrxGHaP0is+PIuwgTi9T5lyprpQss2yS9O7rN5PMCQQDJx0CMjkPDbelbWeH2 -nOvyxLLCev69ae6zVrMPcE7vRPohlJTSK/kgouLr0F6lomK9HVugD7VgrQHuj9am -UV7BAkBhCHnlejSvl95M+lqGRBCvo3GUYJzHGqmPoYgIRdy1fEsaC6QbHjfDkwSD -bqYrh4qBKjjYf/2Fl38SWQelzUyFAkBoht27cl9MN/3xIsjZ1kSsiJUKBmk8ekn7 -gWhVERry/EqPZscJcVonO/pNqq29JDf+O90hN8IACN+9U6ogknqBAkAr3SowHLyD -LfTrEDxeoAd2+K7gGKyrK3gyIISbuWtluONNPqenuFFHXxehwJ72VplNkpUZP4Bt -TQcIW9zIYT5r ------END PRIVATE KEY----- diff --git a/packages/web-util/src/keys/ca.srl b/packages/web-util/src/keys/ca.srl @@ -1 +0,0 @@ -7488FC4F9D5E2BB55DEA16CF051F4E99ACA25241 diff --git a/packages/web-util/src/keys/localhost.crt b/packages/web-util/src/keys/localhost.crt @@ -1,15 +0,0 @@ ------BEGIN CERTIFICATE----- -MIICRTCCAa6gAwIBAgIUdIj8T51eK7Vd6hbPBR9OmayiUkEwDQYJKoZIhvcNAQEL -BQAwLjEVMBMGA1UEAwwMbG9jYWxob3N0LWNhMRUwEwYDVQQKDAxsb2NhbGhvc3Qt -Y2EwHhcNMjIxMTMwMjIwNjAyWhcNMjMxMTMwMjIwNjAyWjArMRIwEAYDVQQDDAls -b2NhbGhvc3QxFTATBgNVBAoMDGxvY2FsaG9zdC1jYTCBnzANBgkqhkiG9w0BAQEF -AAOBjQAwgYkCgYEAvir90pl9q6qUsBsBz7jjdw0r1DDPeViqkSyDDTt4Lw2zYJbn -Z7kxcTvNHNRWdtsWSzY/43ERCJu6nX60kMiML3NV00ty2VpaYeW9J5ozXgNbb+5P -esLHrIHmnOIUj46jyiHjDKs+hgrfcrFg7W7ndjW3dCAvkeAV+mncz59pFvkCAwEA -AaNjMGEwCQYDVR0TBAIwADAdBgNVHQ4EFgQUXADNSPivlIUBpKyd/XirIcqxqFgw -HwYDVR0jBBgwFoAU7U6nUpEyRWTNp0bLZNkVCXAb0UUwFAYDVR0RBA0wC4IJbG9j -YWxob3N0MA0GCSqGSIb3DQEBCwUAA4GBAClcLuKFnRJjAgP8652jJscYMLWYEkv3 -j9kChErpKZNKiv+VlWKPiOvhZVAl+/YEsBOKXpRFX3CuLCdGtuv7b6NaH7yEXaZn -9MVIrYMRub3k0gVAhu3z3VXuvHFXdTms3KRlGdPdQV2xgpQJczDNnd7idp/GyI4j -KqBo0UxuWZBJ ------END CERTIFICATE----- diff --git a/packages/web-util/src/keys/localhost.csr b/packages/web-util/src/keys/localhost.csr @@ -1,10 +0,0 @@ ------BEGIN CERTIFICATE REQUEST----- -MIIBajCB1AIBADArMRIwEAYDVQQDDAlsb2NhbGhvc3QxFTATBgNVBAoMDGxvY2Fs -aG9zdC1jYTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAvir90pl9q6qUsBsB -z7jjdw0r1DDPeViqkSyDDTt4Lw2zYJbnZ7kxcTvNHNRWdtsWSzY/43ERCJu6nX60 -kMiML3NV00ty2VpaYeW9J5ozXgNbb+5PesLHrIHmnOIUj46jyiHjDKs+hgrfcrFg -7W7ndjW3dCAvkeAV+mncz59pFvkCAwEAAaAAMA0GCSqGSIb3DQEBCwUAA4GBADJW -Ww+l4E///54fz82AE5x8U114Yk32EbB1qOfGLyXgoXySGyLuiNu40SXxioKa/Gpn -Z92o5JIrMVWUroPzMKAMXdAsixkaBGrT5RYzR9ztfy59djxp0f7dlL3ZxDO8JHOw -aTJXJxKEfYdv0oFhkx/u4ki6BsaqG9mQfsFXtlUp ------END CERTIFICATE REQUEST----- diff --git a/packages/web-util/src/keys/localhost.key b/packages/web-util/src/keys/localhost.key @@ -1,16 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIICeQIBADANBgkqhkiG9w0BAQEFAASCAmMwggJfAgEAAoGBAL4q/dKZfauqlLAb -Ac+443cNK9Qwz3lYqpEsgw07eC8Ns2CW52e5MXE7zRzUVnbbFks2P+NxEQibup1+ -tJDIjC9zVdNLctlaWmHlvSeaM14DW2/uT3rCx6yB5pziFI+Oo8oh4wyrPoYK33Kx -YO1u53Y1t3QgL5HgFfpp3M+faRb5AgMBAAECgYEAh1xgqdxZqKzWA3hl1K7dMmus -q/BGbjCf0JAnhG61QID3EqS3eIxI1jnj6UZ3eUi/WK/3z/Q2VLNMpTiAXKJzrUP0 -8m7yO87AeUxhy0rvtWEVmd8NBQjJKD2iElgy6tR9QUsgTXer9xuQf0sHRQb1psNU -11WsBnwdzeEEzquORVUCQQDtJx/HjHDVTDF02W5B23J4oqwuu1EDCVDqNJiYSDSt -2Dh0IdvSKJyh9lXIoY+kbbEui8uPPnhPKM1LIRfiv7FHAkEAzUf1mvTBNUGCwjZu -qy/oKDR7TlEbdyDJY1F0JPquyim/CenRtM8VAH22Tni8+bSSpnHknytvKfaC0YFb -VN8VvwJBAKTdJgKbZ3Vg2qDY5wVxgUrMC9cQ8Wii+VVX6x0yVSzlu5lAUIjxIrKV -hV1Ms4cjmqE5HfIfA5REUTOBdhF0IdECQQC/1lia19Ha7/6/eljP17RQJkN5O+i7 -2kL5crxkdnRz7rFeFUlpfAB3dgOxr7mCbZKCw3rQmKmJAJreKNHuLZBHAkEAwYZ4 -tc4mWjtw4AMDK59o8d8ANObyuVaIy6I54NZ0ogg+0nzrXii9LkZZhAWwVSN9BdXa -TYVu0J5fGxDZVAm0zQ== ------END PRIVATE KEY----- diff --git a/packages/web-util/src/stories-utils.tsx b/packages/web-util/src/stories-utils.tsx @@ -26,7 +26,6 @@ import { FunctionalComponent, FunctionComponent, h, - JSX, render, VNode, } from "preact"; @@ -67,23 +66,6 @@ const SideBar: FunctionalComponent<{ width: number }> = ({ ); }; -const ResizeHandleDiv: FunctionalComponent< - JSX.HTMLAttributes<HTMLDivElement> -> = ({ children, ...props }): VNode => { - return ( - <div - {...props} - style={{ - width: 10, - backgroundColor: "#ddd", - cursor: "ew-resize", - }} - > - {children} - </div> - ); -}; - const Content: FunctionalComponent = ({ children }): VNode => { return ( <div diff --git a/packages/web-util/src/tests/hook.ts b/packages/web-util/src/tests/hook.ts @@ -226,11 +226,6 @@ function mountHook<T extends object>( }; } -export const nullFunction = (): void => {}; -export const nullAsyncFunction = (): Promise<void> => { - return Promise.resolve(); -}; - type HookTestResult = HookTestResultOk | HookTestResultError; interface HookTestResultOk { diff --git a/packages/web-util/src/utils/base64.ts b/packages/web-util/src/utils/base64.ts @@ -1,6 +1,6 @@ /* This file is part of GNU Taler - (C) 2021-2025 Taler Systems S.A. + (C) 2021-2026 Taler Systems S.A. GNU Taler is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -19,252 +19,10 @@ import { decodeCrock, encodeCrock } from "@gnu-taler/taler-util"; const utf8Encoder = new TextEncoder(); const utf8Decoder = new TextDecoder("utf-8", { ignoreBOM: true }); -export function encodeCrockForURI(string: string): string { - return encodeCrock(utf8Encoder.encode(string)); +export function encodeCrockForURI(value: string): string { + return encodeCrock(utf8Encoder.encode(value)); } -export function decodeCrockFromURI(enc: string): string { - return utf8Decoder.decode(decodeCrock(enc)); -} - -export function base64encode(str: string): string { - return base64EncArr(strToUTF8Arr(str)); -} - -export function base64decode(str: string): string { - return UTF8ArrToStr(base64DecToArr(str)); -} - -// from https://developer.mozilla.org/en-US/docs/Glossary/Base64 - -// Array of bytes to Base64 string decoding -function b64ToUint6(nChr: number): number { - return nChr > 64 && nChr < 91 - ? nChr - 65 - : nChr > 96 && nChr < 123 - ? nChr - 71 - : nChr > 47 && nChr < 58 - ? nChr + 4 - : nChr === 43 - ? 62 - : nChr === 47 - ? 63 - : 0; -} - -function base64DecToArr(sBase64: string, nBlocksSize?: number): Uint8Array { - const sB64Enc = sBase64.replace(/[^A-Za-z0-9+/]/g, ""); // Only necessary if the base64 includes whitespace such as line breaks. - const nInLen = sB64Enc.length; - const nOutLen = nBlocksSize - ? Math.ceil(((nInLen * 3 + 1) >> 2) / nBlocksSize) * nBlocksSize - : (nInLen * 3 + 1) >> 2; - const taBytes = new Uint8Array(nOutLen); - - let nMod3; - let nMod4; - let nUint24 = 0; - let nOutIdx = 0; - for (let nInIdx = 0; nInIdx < nInLen; nInIdx++) { - nMod4 = nInIdx & 3; - nUint24 |= b64ToUint6(sB64Enc.charCodeAt(nInIdx)) << (6 * (3 - nMod4)); - if (nMod4 === 3 || nInLen - nInIdx === 1) { - nMod3 = 0; - while (nMod3 < 3 && nOutIdx < nOutLen) { - taBytes[nOutIdx] = (nUint24 >>> ((16 >>> nMod3) & 24)) & 255; - nMod3++; - nOutIdx++; - } - nUint24 = 0; - } - } - - return taBytes; -} - -/* Base64 string to array encoding */ -function uint6ToB64(nUint6: number): number { - return nUint6 < 26 - ? nUint6 + 65 - : nUint6 < 52 - ? nUint6 + 71 - : nUint6 < 62 - ? nUint6 - 4 - : nUint6 === 62 - ? 43 - : nUint6 === 63 - ? 47 - : 65; -} - -function base64EncArr(aBytes: Uint8Array): string { - let nMod3 = 2; - let sB64Enc = ""; - - const nLen = aBytes.length; - let nUint24 = 0; - for (let nIdx = 0; nIdx < nLen; nIdx++) { - nMod3 = nIdx % 3; - // To break your base64 into several 80-character lines, add: - // if (nIdx > 0 && ((nIdx * 4) / 3) % 76 === 0) { - // sB64Enc += "\r\n"; - // } - - nUint24 |= aBytes[nIdx] << ((16 >>> nMod3) & 24); - if (nMod3 === 2 || aBytes.length - nIdx === 1) { - sB64Enc += String.fromCodePoint( - uint6ToB64((nUint24 >>> 18) & 63), - uint6ToB64((nUint24 >>> 12) & 63), - uint6ToB64((nUint24 >>> 6) & 63), - uint6ToB64(nUint24 & 63), - ); - nUint24 = 0; - } - } - return ( - sB64Enc.substring(0, sB64Enc.length - 2 + nMod3) + - (nMod3 === 2 ? "" : nMod3 === 1 ? "=" : "==") - ); -} - -/** - * UTF-8 array to JS string and vice versa - * - * @param aBytes - * @deprecated use textEncoder - * @returns - */ -function UTF8ArrToStr(aBytes: Uint8Array): string { - let sView = ""; - let nPart; - const nLen = aBytes.length; - for (let nIdx = 0; nIdx < nLen; nIdx++) { - nPart = aBytes[nIdx]; - sView += String.fromCodePoint( - nPart > 251 && nPart < 254 && nIdx + 5 < nLen /* six bytes */ - ? /* (nPart - 252 << 30) may be not so safe in ECMAScript! So…: */ - (nPart - 252) * 1073741824 + - ((aBytes[++nIdx] - 128) << 24) + - ((aBytes[++nIdx] - 128) << 18) + - ((aBytes[++nIdx] - 128) << 12) + - ((aBytes[++nIdx] - 128) << 6) + - aBytes[++nIdx] - - 128 - : nPart > 247 && nPart < 252 && nIdx + 4 < nLen /* five bytes */ - ? ((nPart - 248) << 24) + - ((aBytes[++nIdx] - 128) << 18) + - ((aBytes[++nIdx] - 128) << 12) + - ((aBytes[++nIdx] - 128) << 6) + - aBytes[++nIdx] - - 128 - : nPart > 239 && nPart < 248 && nIdx + 3 < nLen /* four bytes */ - ? ((nPart - 240) << 18) + - ((aBytes[++nIdx] - 128) << 12) + - ((aBytes[++nIdx] - 128) << 6) + - aBytes[++nIdx] - - 128 - : nPart > 223 && nPart < 240 && nIdx + 2 < nLen /* three bytes */ - ? ((nPart - 224) << 12) + - ((aBytes[++nIdx] - 128) << 6) + - aBytes[++nIdx] - - 128 - : nPart > 191 && nPart < 224 && nIdx + 1 < nLen /* two bytes */ - ? ((nPart - 192) << 6) + aBytes[++nIdx] - 128 - : /* nPart < 127 ? */ /* one byte */ - nPart, - ); - } - return sView; -} - -/** - * - * @param sDOMStr - * @deprecated use textEncoder - * @returns - */ -function strToUTF8Arr(sDOMStr: string): Uint8Array { - let nChr; - const nStrLen = sDOMStr.length; - let nArrLen = 0; - - /* mapping… */ - for (let nMapIdx = 0; nMapIdx < nStrLen; nMapIdx++) { - nChr = sDOMStr.codePointAt(nMapIdx); - if (nChr === undefined) { - throw Error( - `No char at ${nMapIdx} on string with length: ${sDOMStr.length}`, - ); - } - - if (nChr >= 0x10000) { - nMapIdx++; - } - - nArrLen += - nChr < 0x80 - ? 1 - : nChr < 0x800 - ? 2 - : nChr < 0x10000 - ? 3 - : nChr < 0x200000 - ? 4 - : nChr < 0x4000000 - ? 5 - : 6; - } - - const aBytes = new Uint8Array(nArrLen); - - /* transcription… */ - let nIdx = 0; - let nChrIdx = 0; - while (nIdx < nArrLen) { - nChr = sDOMStr.codePointAt(nChrIdx); - if (nChr === undefined) { - throw Error( - `No char at ${nChrIdx} on string with length: ${sDOMStr.length}`, - ); - } - if (nChr < 128) { - /* one byte */ - aBytes[nIdx++] = nChr; - } else if (nChr < 0x800) { - /* two bytes */ - aBytes[nIdx++] = 192 + (nChr >>> 6); - aBytes[nIdx++] = 128 + (nChr & 63); - } else if (nChr < 0x10000) { - /* three bytes */ - aBytes[nIdx++] = 224 + (nChr >>> 12); - aBytes[nIdx++] = 128 + ((nChr >>> 6) & 63); - aBytes[nIdx++] = 128 + (nChr & 63); - } else if (nChr < 0x200000) { - /* four bytes */ - aBytes[nIdx++] = 240 + (nChr >>> 18); - aBytes[nIdx++] = 128 + ((nChr >>> 12) & 63); - aBytes[nIdx++] = 128 + ((nChr >>> 6) & 63); - aBytes[nIdx++] = 128 + (nChr & 63); - nChrIdx++; - } else if (nChr < 0x4000000) { - /* five bytes */ - aBytes[nIdx++] = 248 + (nChr >>> 24); - aBytes[nIdx++] = 128 + ((nChr >>> 18) & 63); - aBytes[nIdx++] = 128 + ((nChr >>> 12) & 63); - aBytes[nIdx++] = 128 + ((nChr >>> 6) & 63); - aBytes[nIdx++] = 128 + (nChr & 63); - nChrIdx++; - } /* if (nChr <= 0x7fffffff) */ else { - /* six bytes */ - aBytes[nIdx++] = 252 + (nChr >>> 30); - aBytes[nIdx++] = 128 + ((nChr >>> 24) & 63); - aBytes[nIdx++] = 128 + ((nChr >>> 18) & 63); - aBytes[nIdx++] = 128 + ((nChr >>> 12) & 63); - aBytes[nIdx++] = 128 + ((nChr >>> 6) & 63); - aBytes[nIdx++] = 128 + (nChr & 63); - nChrIdx++; - } - nChrIdx++; - } - - return aBytes; +export function decodeCrockFromURI(encoded: string): string { + return utf8Decoder.decode(decodeCrock(encoded)); } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml @@ -785,9 +785,6 @@ importers: '@types/chrome': specifier: 0.0.197 version: 0.0.197 - qrcode-generator: - specifier: 1.4.4 - version: 1.4.4 tailwindcss: specifier: 3.4.17 version: 3.4.17(ts-node@10.9.1(@types/node@20.19.41)(typescript@7.0.2))