summaryrefslogtreecommitdiff
path: root/packages/taler-wallet-core/src/util
diff options
context:
space:
mode:
authorFlorian Dold <florian@dold.me>2021-03-17 17:56:37 +0100
committerFlorian Dold <florian@dold.me>2021-03-17 17:56:37 +0100
commit07cdfb2e4ec761021477271776b81f33af0e731d (patch)
treecb62b1d1a04e1e64b8ee47e78196e858727d2c0a /packages/taler-wallet-core/src/util
parent42a4d666f42ce94274995bfdae644444ff5f6d53 (diff)
downloadwallet-core-07cdfb2e4ec761021477271776b81f33af0e731d.tar.gz
wallet-core-07cdfb2e4ec761021477271776b81f33af0e731d.tar.bz2
wallet-core-07cdfb2e4ec761021477271776b81f33af0e731d.zip
towards wallet-core / util split
Diffstat (limited to 'packages/taler-wallet-core/src/util')
-rw-r--r--packages/taler-wallet-core/src/util/RequestThrottler.ts2
-rw-r--r--packages/taler-wallet-core/src/util/amounts-test.ts140
-rw-r--r--packages/taler-wallet-core/src/util/amounts.ts423
-rw-r--r--packages/taler-wallet-core/src/util/codec-test.ts78
-rw-r--r--packages/taler-wallet-core/src/util/codec.ts419
-rw-r--r--packages/taler-wallet-core/src/util/coinSelection-test.ts2
-rw-r--r--packages/taler-wallet-core/src/util/coinSelection.ts2
-rw-r--r--packages/taler-wallet-core/src/util/helpers.ts3
-rw-r--r--packages/taler-wallet-core/src/util/http.ts9
-rw-r--r--packages/taler-wallet-core/src/util/libtoolVersion-test.ts48
-rw-r--r--packages/taler-wallet-core/src/util/libtoolVersion.ts88
-rw-r--r--packages/taler-wallet-core/src/util/payto-test.ts31
-rw-r--r--packages/taler-wallet-core/src/util/payto.ts71
-rw-r--r--packages/taler-wallet-core/src/util/retries.ts2
-rw-r--r--packages/taler-wallet-core/src/util/talerconfig-test.ts124
-rw-r--r--packages/taler-wallet-core/src/util/talerconfig.ts318
-rw-r--r--packages/taler-wallet-core/src/util/taleruri-test.ts184
-rw-r--r--packages/taler-wallet-core/src/util/taleruri.ts220
-rw-r--r--packages/taler-wallet-core/src/util/testvectors.ts36
-rw-r--r--packages/taler-wallet-core/src/util/time.ts261
-rw-r--r--packages/taler-wallet-core/src/util/timer.ts2
-rw-r--r--packages/taler-wallet-core/src/util/wire.ts51
22 files changed, 10 insertions, 2504 deletions
diff --git a/packages/taler-wallet-core/src/util/RequestThrottler.ts b/packages/taler-wallet-core/src/util/RequestThrottler.ts
index 0bdd7cab7..b38e948fe 100644
--- a/packages/taler-wallet-core/src/util/RequestThrottler.ts
+++ b/packages/taler-wallet-core/src/util/RequestThrottler.ts
@@ -25,7 +25,7 @@ import {
getTimestampNow,
timestampDifference,
timestampCmp,
-} from "../util/time";
+} from "@gnu-taler/taler-util";
import { URL } from "./url";
import { Logger } from "./logging";
diff --git a/packages/taler-wallet-core/src/util/amounts-test.ts b/packages/taler-wallet-core/src/util/amounts-test.ts
deleted file mode 100644
index afd8caa51..000000000
--- a/packages/taler-wallet-core/src/util/amounts-test.ts
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2020 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 test from "ava";
-
-import { Amounts, AmountJson } from "../util/amounts";
-
-const jAmt = (
- value: number,
- fraction: number,
- currency: string,
-): AmountJson => ({ value, fraction, currency });
-
-const sAmt = (s: string): AmountJson => Amounts.parseOrThrow(s);
-
-test("amount addition (simple)", (t) => {
- const a1 = jAmt(1, 0, "EUR");
- const a2 = jAmt(1, 0, "EUR");
- const a3 = jAmt(2, 0, "EUR");
- t.true(0 === Amounts.cmp(Amounts.add(a1, a2).amount, a3));
- t.pass();
-});
-
-test("amount addition (saturation)", (t) => {
- const a1 = jAmt(1, 0, "EUR");
- const res = Amounts.add(jAmt(Amounts.maxAmountValue, 0, "EUR"), a1);
- t.true(res.saturated);
- t.pass();
-});
-
-test("amount subtraction (simple)", (t) => {
- const a1 = jAmt(2, 5, "EUR");
- const a2 = jAmt(1, 0, "EUR");
- const a3 = jAmt(1, 5, "EUR");
- t.true(0 === Amounts.cmp(Amounts.sub(a1, a2).amount, a3));
- t.pass();
-});
-
-test("amount subtraction (saturation)", (t) => {
- const a1 = jAmt(0, 0, "EUR");
- const a2 = jAmt(1, 0, "EUR");
- let res = Amounts.sub(a1, a2);
- t.true(res.saturated);
- res = Amounts.sub(a1, a1);
- t.true(!res.saturated);
- t.pass();
-});
-
-test("amount comparison", (t) => {
- t.is(Amounts.cmp(jAmt(1, 0, "EUR"), jAmt(1, 0, "EUR")), 0);
- t.is(Amounts.cmp(jAmt(1, 1, "EUR"), jAmt(1, 0, "EUR")), 1);
- t.is(Amounts.cmp(jAmt(1, 1, "EUR"), jAmt(1, 2, "EUR")), -1);
- t.is(Amounts.cmp(jAmt(1, 0, "EUR"), jAmt(0, 0, "EUR")), 1);
- t.is(Amounts.cmp(jAmt(0, 0, "EUR"), jAmt(1, 0, "EUR")), -1);
- t.is(Amounts.cmp(jAmt(1, 0, "EUR"), jAmt(0, 100000000, "EUR")), 0);
- t.throws(() => Amounts.cmp(jAmt(1, 0, "FOO"), jAmt(1, 0, "BAR")));
- t.pass();
-});
-
-test("amount parsing", (t) => {
- t.is(
- Amounts.cmp(Amounts.parseOrThrow("TESTKUDOS:0"), jAmt(0, 0, "TESTKUDOS")),
- 0,
- );
- t.is(
- Amounts.cmp(Amounts.parseOrThrow("TESTKUDOS:10"), jAmt(10, 0, "TESTKUDOS")),
- 0,
- );
- t.is(
- Amounts.cmp(
- Amounts.parseOrThrow("TESTKUDOS:0.1"),
- jAmt(0, 10000000, "TESTKUDOS"),
- ),
- 0,
- );
- t.is(
- Amounts.cmp(
- Amounts.parseOrThrow("TESTKUDOS:0.00000001"),
- jAmt(0, 1, "TESTKUDOS"),
- ),
- 0,
- );
- t.is(
- Amounts.cmp(
- Amounts.parseOrThrow("TESTKUDOS:4503599627370496.99999999"),
- jAmt(4503599627370496, 99999999, "TESTKUDOS"),
- ),
- 0,
- );
- t.throws(() => Amounts.parseOrThrow("foo:"));
- t.throws(() => Amounts.parseOrThrow("1.0"));
- t.throws(() => Amounts.parseOrThrow("42"));
- t.throws(() => Amounts.parseOrThrow(":1.0"));
- t.throws(() => Amounts.parseOrThrow(":42"));
- t.throws(() => Amounts.parseOrThrow("EUR:.42"));
- t.throws(() => Amounts.parseOrThrow("EUR:42."));
- t.throws(() => Amounts.parseOrThrow("TESTKUDOS:4503599627370497.99999999"));
- t.is(
- Amounts.cmp(
- Amounts.parseOrThrow("TESTKUDOS:0.99999999"),
- jAmt(0, 99999999, "TESTKUDOS"),
- ),
- 0,
- );
- t.throws(() => Amounts.parseOrThrow("TESTKUDOS:0.999999991"));
- t.pass();
-});
-
-test("amount stringification", (t) => {
- t.is(Amounts.stringify(jAmt(0, 0, "TESTKUDOS")), "TESTKUDOS:0");
- t.is(Amounts.stringify(jAmt(4, 94000000, "TESTKUDOS")), "TESTKUDOS:4.94");
- t.is(Amounts.stringify(jAmt(0, 10000000, "TESTKUDOS")), "TESTKUDOS:0.1");
- t.is(Amounts.stringify(jAmt(0, 1, "TESTKUDOS")), "TESTKUDOS:0.00000001");
- t.is(Amounts.stringify(jAmt(5, 0, "TESTKUDOS")), "TESTKUDOS:5");
- // denormalized
- t.is(Amounts.stringify(jAmt(1, 100000000, "TESTKUDOS")), "TESTKUDOS:2");
- t.pass();
-});
-
-test("amount multiplication", (t) => {
- t.is(Amounts.stringify(Amounts.mult(sAmt("EUR:1.11"), 0).amount), "EUR:0");
- t.is(Amounts.stringify(Amounts.mult(sAmt("EUR:1.11"), 1).amount), "EUR:1.11");
- t.is(Amounts.stringify(Amounts.mult(sAmt("EUR:1.11"), 2).amount), "EUR:2.22");
- t.is(Amounts.stringify(Amounts.mult(sAmt("EUR:1.11"), 3).amount), "EUR:3.33");
- t.is(Amounts.stringify(Amounts.mult(sAmt("EUR:1.11"), 4).amount), "EUR:4.44");
- t.is(Amounts.stringify(Amounts.mult(sAmt("EUR:1.11"), 5).amount), "EUR:5.55");
-});
diff --git a/packages/taler-wallet-core/src/util/amounts.ts b/packages/taler-wallet-core/src/util/amounts.ts
deleted file mode 100644
index 7a242f41d..000000000
--- a/packages/taler-wallet-core/src/util/amounts.ts
+++ /dev/null
@@ -1,423 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2019 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/>
- */
-
-/**
- * Types and helper functions for dealing with Taler amounts.
- */
-
-/**
- * Imports.
- */
-import {
- buildCodecForObject,
- codecForString,
- codecForNumber,
- Codec,
-} from "./codec";
-import { AmountString } from "../types/talerTypes";
-
-/**
- * Number of fractional units that one value unit represents.
- */
-export const fractionalBase = 1e8;
-
-/**
- * How many digits behind the comma are required to represent the
- * fractional value in human readable decimal format? Must match
- * lg(fractionalBase)
- */
-export const fractionalLength = 8;
-
-/**
- * Maximum allowed value field of an amount.
- */
-export const maxAmountValue = 2 ** 52;
-
-/**
- * Non-negative financial amount. Fractional values are expressed as multiples
- * of 1e-8.
- */
-export interface AmountJson {
- /**
- * Value, must be an integer.
- */
- readonly value: number;
-
- /**
- * Fraction, must be an integer. Represent 1/1e8 of a unit.
- */
- readonly fraction: number;
-
- /**
- * Currency of the amount.
- */
- readonly currency: string;
-}
-
-export const codecForAmountJson = (): Codec<AmountJson> =>
- buildCodecForObject<AmountJson>()
- .property("currency", codecForString())
- .property("value", codecForNumber())
- .property("fraction", codecForNumber())
- .build("AmountJson");
-
-export const codecForAmountString = (): Codec<AmountString> => codecForString();
-
-/**
- * Result of a possibly overflowing operation.
- */
-export interface Result {
- /**
- * Resulting, possibly saturated amount.
- */
- amount: AmountJson;
- /**
- * Was there an over-/underflow?
- */
- saturated: boolean;
-}
-
-/**
- * Get an amount that represents zero units of a currency.
- */
-export function getZero(currency: string): AmountJson {
- return {
- currency,
- fraction: 0,
- value: 0,
- };
-}
-
-export type AmountLike = AmountString | AmountJson;
-
-export function jsonifyAmount(amt: AmountLike): AmountJson {
- if (typeof amt === "string") {
- return parseOrThrow(amt);
- }
- return amt;
-}
-
-export function sum(amounts: AmountLike[]): Result {
- if (amounts.length <= 0) {
- throw Error("can't sum zero amounts");
- }
- const jsonAmounts = amounts.map((x) => jsonifyAmount(x));
- return add(jsonAmounts[0], ...jsonAmounts.slice(1));
-}
-
-/**
- * Add two amounts. Return the result and whether
- * the addition overflowed. The overflow is always handled
- * by saturating and never by wrapping.
- *
- * Throws when currencies don't match.
- */
-export function add(first: AmountJson, ...rest: AmountJson[]): Result {
- const currency = first.currency;
- let value = first.value + Math.floor(first.fraction / fractionalBase);
- if (value > maxAmountValue) {
- return {
- amount: { currency, value: maxAmountValue, fraction: fractionalBase - 1 },
- saturated: true,
- };
- }
- let fraction = first.fraction % fractionalBase;
- for (const x of rest) {
- if (x.currency !== currency) {
- throw Error(`Mismatched currency: ${x.currency} and ${currency}`);
- }
-
- value =
- value + x.value + Math.floor((fraction + x.fraction) / fractionalBase);
- fraction = Math.floor((fraction + x.fraction) % fractionalBase);
- if (value > maxAmountValue) {
- return {
- amount: {
- currency,
- value: maxAmountValue,
- fraction: fractionalBase - 1,
- },
- saturated: true,
- };
- }
- }
- return { amount: { currency, value, fraction }, saturated: false };
-}
-
-/**
- * Subtract two amounts. Return the result and whether
- * the subtraction overflowed. The overflow is always handled
- * by saturating and never by wrapping.
- *
- * Throws when currencies don't match.
- */
-export function sub(a: AmountJson, ...rest: AmountJson[]): Result {
- const currency = a.currency;
- let value = a.value;
- let fraction = a.fraction;
-
- for (const b of rest) {
- if (b.currency !== currency) {
- throw Error(`Mismatched currency: ${b.currency} and ${currency}`);
- }
- if (fraction < b.fraction) {
- if (value < 1) {
- return { amount: { currency, value: 0, fraction: 0 }, saturated: true };
- }
- value--;
- fraction += fractionalBase;
- }
- console.assert(fraction >= b.fraction);
- fraction -= b.fraction;
- if (value < b.value) {
- return { amount: { currency, value: 0, fraction: 0 }, saturated: true };
- }
- value -= b.value;
- }
-
- return { amount: { currency, value, fraction }, saturated: false };
-}
-
-/**
- * Compare two amounts. Returns 0 when equal, -1 when a < b
- * and +1 when a > b. Throws when currencies don't match.
- */
-export function cmp(a: AmountLike, b: AmountLike): -1 | 0 | 1 {
- a = jsonifyAmount(a);
- b = jsonifyAmount(b);
- if (a.currency !== b.currency) {
- throw Error(`Mismatched currency: ${a.currency} and ${b.currency}`);
- }
- const av = a.value + Math.floor(a.fraction / fractionalBase);
- const af = a.fraction % fractionalBase;
- const bv = b.value + Math.floor(b.fraction / fractionalBase);
- const bf = b.fraction % fractionalBase;
- switch (true) {
- case av < bv:
- return -1;
- case av > bv:
- return 1;
- case af < bf:
- return -1;
- case af > bf:
- return 1;
- case af === bf:
- return 0;
- default:
- throw Error("assertion failed");
- }
-}
-
-/**
- * Create a copy of an amount.
- */
-export function copy(a: AmountJson): AmountJson {
- return {
- currency: a.currency,
- fraction: a.fraction,
- value: a.value,
- };
-}
-
-/**
- * Divide an amount. Throws on division by zero.
- */
-export function divide(a: AmountJson, n: number): AmountJson {
- if (n === 0) {
- throw Error(`Division by 0`);
- }
- if (n === 1) {
- return { value: a.value, fraction: a.fraction, currency: a.currency };
- }
- const r = a.value % n;
- return {
- currency: a.currency,
- fraction: Math.floor((r * fractionalBase + a.fraction) / n),
- value: Math.floor(a.value / n),
- };
-}
-
-/**
- * Check if an amount is non-zero.
- */
-export function isNonZero(a: AmountJson): boolean {
- return a.value > 0 || a.fraction > 0;
-}
-
-export function isZero(a: AmountLike): boolean {
- a = jsonifyAmount(a);
- return a.value === 0 && a.fraction === 0;
-}
-
-/**
- * Parse an amount like 'EUR:20.5' for 20 Euros and 50 ct.
- */
-export function parse(s: string): AmountJson | undefined {
- const res = s.match(/^([a-zA-Z0-9_*-]+):([0-9]+)([.][0-9]+)?$/);
- if (!res) {
- return undefined;
- }
- const tail = res[3] || ".0";
- if (tail.length > fractionalLength + 1) {
- return undefined;
- }
- const value = Number.parseInt(res[2]);
- if (value > maxAmountValue) {
- return undefined;
- }
- return {
- currency: res[1],
- fraction: Math.round(fractionalBase * Number.parseFloat(tail)),
- value,
- };
-}
-
-/**
- * Parse amount in standard string form (like 'EUR:20.5'),
- * throw if the input is not a valid amount.
- */
-export function parseOrThrow(s: string): AmountJson {
- const res = parse(s);
- if (!res) {
- throw Error(`Can't parse amount: "${s}"`);
- }
- return res;
-}
-
-/**
- * Convert a float to a Taler amount.
- * Loss of precision possible.
- */
-export function fromFloat(floatVal: number, currency: string): AmountJson {
- return {
- currency,
- fraction: Math.floor((floatVal - Math.floor(floatVal)) * fractionalBase),
- value: Math.floor(floatVal),
- };
-}
-
-/**
- * Convert to standard human-readable string representation that's
- * also used in JSON formats.
- */
-export function stringify(a: AmountLike): string {
- a = jsonifyAmount(a);
- const av = a.value + Math.floor(a.fraction / fractionalBase);
- const af = a.fraction % fractionalBase;
- let s = av.toString();
-
- if (af) {
- s = s + ".";
- let n = af;
- for (let i = 0; i < fractionalLength; i++) {
- if (!n) {
- break;
- }
- s = s + Math.floor((n / fractionalBase) * 10).toString();
- n = (n * 10) % fractionalBase;
- }
- }
-
- return `${a.currency}:${s}`;
-}
-
-/**
- * Check if the argument is a valid amount in string form.
- */
-function check(a: any): boolean {
- if (typeof a !== "string") {
- return false;
- }
- try {
- const parsedAmount = parse(a);
- return !!parsedAmount;
- } catch {
- return false;
- }
-}
-
-function mult(a: AmountJson, n: number): Result {
- if (!Number.isInteger(n)) {
- throw Error("amount can only be multipied by an integer");
- }
- if (n < 0) {
- throw Error("amount can only be multiplied by a positive integer");
- }
- if (n == 0) {
- return { amount: getZero(a.currency), saturated: false };
- }
- let x = a;
- let acc = getZero(a.currency);
- while (n > 1) {
- if (n % 2 == 0) {
- n = n / 2;
- } else {
- n = (n - 1) / 2;
- const r2 = add(acc, x);
- if (r2.saturated) {
- return r2;
- }
- acc = r2.amount;
- }
- const r2 = add(x, x);
- if (r2.saturated) {
- return r2;
- }
- x = r2.amount;
- }
- return add(acc, x);
-}
-
-function max(a: AmountLike, b: AmountLike): AmountJson {
- const cr = Amounts.cmp(a, b);
- if (cr >= 0) {
- return jsonifyAmount(a);
- } else {
- return jsonifyAmount(b);
- }
-}
-
-function min(a: AmountLike, b: AmountLike): AmountJson {
- const cr = Amounts.cmp(a, b);
- if (cr >= 0) {
- return jsonifyAmount(b);
- } else {
- return jsonifyAmount(a);
- }
-}
-
-
-// Export all amount-related functions here for better IDE experience.
-export const Amounts = {
- stringify: stringify,
- parse: parse,
- parseOrThrow: parseOrThrow,
- cmp: cmp,
- add: add,
- sum: sum,
- sub: sub,
- mult: mult,
- max: max,
- min: min,
- check: check,
- getZero: getZero,
- isZero: isZero,
- maxAmountValue: maxAmountValue,
- fromFloat: fromFloat,
- copy: copy,
- fractionalBase: fractionalBase,
- divide: divide,
-};
diff --git a/packages/taler-wallet-core/src/util/codec-test.ts b/packages/taler-wallet-core/src/util/codec-test.ts
deleted file mode 100644
index f8f4c797c..000000000
--- a/packages/taler-wallet-core/src/util/codec-test.ts
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2018-2019 GNUnet e.V.
-
- 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/>
- */
-
-/**
- * Type-safe codecs for converting from/to JSON.
- */
-
-import test from "ava";
-import {
- Codec,
- buildCodecForObject,
- codecForConstString,
- codecForString,
- buildCodecForUnion,
-} from "./codec";
-
-interface MyObj {
- foo: string;
-}
-
-interface AltOne {
- type: "one";
- foo: string;
-}
-
-interface AltTwo {
- type: "two";
- bar: string;
-}
-
-type MyUnion = AltOne | AltTwo;
-
-test("basic codec", (t) => {
- const myObjCodec = buildCodecForObject<MyObj>()
- .property("foo", codecForString())
- .build("MyObj");
- const res = myObjCodec.decode({ foo: "hello" });
- t.assert(res.foo === "hello");
-
- t.throws(() => {
- myObjCodec.decode({ foo: 123 });
- });
-});
-
-test("union", (t) => {
- const altOneCodec: Codec<AltOne> = buildCodecForObject<AltOne>()
- .property("type", codecForConstString("one"))
- .property("foo", codecForString())
- .build("AltOne");
- const altTwoCodec: Codec<AltTwo> = buildCodecForObject<AltTwo>()
- .property("type", codecForConstString("two"))
- .property("bar", codecForString())
- .build("AltTwo");
- const myUnionCodec: Codec<MyUnion> = buildCodecForUnion<MyUnion>()
- .discriminateOn("type")
- .alternative("one", altOneCodec)
- .alternative("two", altTwoCodec)
- .build<MyUnion>("MyUnion");
-
- const res = myUnionCodec.decode({ type: "one", foo: "bla" });
- t.is(res.type, "one");
- if (res.type == "one") {
- t.is(res.foo, "bla");
- }
-});
diff --git a/packages/taler-wallet-core/src/util/codec.ts b/packages/taler-wallet-core/src/util/codec.ts
deleted file mode 100644
index 8605ff335..000000000
--- a/packages/taler-wallet-core/src/util/codec.ts
+++ /dev/null
@@ -1,419 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2018-2019 GNUnet e.V.
-
- 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/>
- */
-
-/**
- * Type-safe codecs for converting from/to JSON.
- */
-
-/* eslint-disable @typescript-eslint/ban-types */
-
-/**
- * Error thrown when decoding fails.
- */
-export class DecodingError extends Error {
- constructor(message: string) {
- super(message);
- Object.setPrototypeOf(this, DecodingError.prototype);
- this.name = "DecodingError";
- }
-}
-
-/**
- * Context information to show nicer error messages when decoding fails.
- */
-export interface Context {
- readonly path?: string[];
-}
-
-export function renderContext(c?: Context): string {
- const p = c?.path;
- if (p) {
- return p.join(".");
- } else {
- return "(unknown)";
- }
-}
-
-function joinContext(c: Context | undefined, part: string): Context {
- const path = c?.path ?? [];
- return {
- path: path.concat([part]),
- };
-}
-
-/**
- * A codec converts untyped JSON to a typed object.
- */
-export interface Codec<V> {
- /**
- * Decode untyped JSON to an object of type [[V]].
- */
- readonly decode: (x: any, c?: Context) => V;
-}
-
-type SingletonRecord<K extends keyof any, V> = { [Y in K]: V };
-
-interface Prop {
- name: string;
- codec: Codec<any>;
-}
-
-interface Alternative {
- tagValue: any;
- codec: Codec<any>;
-}
-
-class ObjectCodecBuilder<OutputType, PartialOutputType> {
- private propList: Prop[] = [];
-
- /**
- * Define a property for the object.
- */
- property<K extends keyof OutputType & string, V extends OutputType[K]>(
- x: K,
- codec: Codec<V>,
- ): ObjectCodecBuilder<OutputType, PartialOutputType & SingletonRecord<K, V>> {
- if (!codec) {
- throw Error("inner codec must be defined");
- }
- this.propList.push({ name: x, codec: codec });
- return this as any;
- }
-
- /**
- * Return the built codec.
- *
- * @param objectDisplayName name of the object that this codec operates on,
- * used in error messages.
- */
- build(objectDisplayName: string): Codec<PartialOutputType> {
- const propList = this.propList;
- return {
- decode(x: any, c?: Context): PartialOutputType {
- if (!c) {
- c = {
- path: [`(${objectDisplayName})`],
- };
- }
- if (typeof x !== "object") {
- throw new DecodingError(
- `expected object for ${objectDisplayName} at ${renderContext(
- c,
- )} but got ${typeof x}`,
- );
- }
- const obj: any = {};
- for (const prop of propList) {
- const propRawVal = x[prop.name];
- const propVal = prop.codec.decode(
- propRawVal,
- joinContext(c, prop.name),
- );
- obj[prop.name] = propVal;
- }
- return obj as PartialOutputType;
- },
- };
- }
-}
-
-class UnionCodecBuilder<
- TargetType,
- TagPropertyLabel extends keyof TargetType,
- CommonBaseType,
- PartialTargetType
-> {
- private alternatives = new Map<any, Alternative>();
-
- constructor(
- private discriminator: TagPropertyLabel,
- private baseCodec?: Codec<CommonBaseType>,
- ) {}
-
- /**
- * Define a property for the object.
- */
- alternative<V>(
- tagValue: TargetType[TagPropertyLabel],
- codec: Codec<V>,
- ): UnionCodecBuilder<
- TargetType,
- TagPropertyLabel,
- CommonBaseType,
- PartialTargetType | V
- > {
- if (!codec) {
- throw Error("inner codec must be defined");
- }
- this.alternatives.set(tagValue, { codec, tagValue });
- return this as any;
- }
-
- /**
- * Return the built codec.
- *
- * @param objectDisplayName name of the object that this codec operates on,
- * used in error messages.
- */
- build<R extends PartialTargetType & CommonBaseType = never>(
- objectDisplayName: string,
- ): Codec<R> {
- const alternatives = this.alternatives;
- const discriminator = this.discriminator;
- const baseCodec = this.baseCodec;
- return {
- decode(x: any, c?: Context): R {
- if (!c) {
- c = {
- path: [`(${objectDisplayName})`],
- };
- }
- const d = x[discriminator];
- if (d === undefined) {
- throw new DecodingError(
- `expected tag for ${objectDisplayName} at ${renderContext(
- c,
- )}.${discriminator}`,
- );
- }
- const alt = alternatives.get(d);
- if (!alt) {
- throw new DecodingError(
- `unknown tag for ${objectDisplayName} ${d} at ${renderContext(
- c,
- )}.${discriminator}`,
- );
- }
- const altDecoded = alt.codec.decode(x);
- if (baseCodec) {
- const baseDecoded = baseCodec.decode(x, c);
- return { ...baseDecoded, ...altDecoded };
- } else {
- return altDecoded;
- }
- },
- };
- }
-}
-
-export class UnionCodecPreBuilder<T> {
- discriminateOn<D extends keyof T, B = {}>(
- discriminator: D,
- baseCodec?: Codec<B>,
- ): UnionCodecBuilder<T, D, B, never> {
- return new UnionCodecBuilder<T, D, B, never>(discriminator, baseCodec);
- }
-}
-
-/**
- * Return a builder for a codec that decodes an object with properties.
- */
-export function buildCodecForObject<T>(): ObjectCodecBuilder<T, {}> {
- return new ObjectCodecBuilder<T, {}>();
-}
-
-export function buildCodecForUnion<T>(): UnionCodecPreBuilder<T> {
- return new UnionCodecPreBuilder<T>();
-}
-
-/**
- * Return a codec for a mapping from a string to values described by the inner codec.
- */
-export function codecForMap<T>(
- innerCodec: Codec<T>,
-): Codec<{ [x: string]: T }> {
- if (!innerCodec) {
- throw Error("inner codec must be defined");
- }
- return {
- decode(x: any, c?: Context): { [x: string]: T } {
- const map: { [x: string]: T } = {};
- if (typeof x !== "object") {
- throw new DecodingError(`expected object at ${renderContext(c)}`);
- }
- for (const i in x) {
- map[i] = innerCodec.decode(x[i], joinContext(c, `[${i}]`));
- }
- return map;
- },
- };
-}
-
-/**
- * Return a codec for a list, containing values described by the inner codec.
- */
-export function codecForList<T>(innerCodec: Codec<T>): Codec<T[]> {
- if (!innerCodec) {
- throw Error("inner codec must be defined");
- }
- return {
- decode(x: any, c?: Context): T[] {
- const arr: T[] = [];
- if (!Array.isArray(x)) {
- throw new DecodingError(`expected array at ${renderContext(c)}`);
- }
- for (const i in x) {
- arr.push(innerCodec.decode(x[i], joinContext(c, `[${i}]`)));
- }
- return arr;
- },
- };
-}
-
-/**
- * Return a codec for a value that must be a number.
- */
-export function codecForNumber(): Codec<number> {
- return {
- decode(x: any, c?: Context): number {
- if (typeof x === "number") {
- return x;
- }
- throw new DecodingError(
- `expected number at ${renderContext(c)} but got ${typeof x}`,
- );
- },
- };
-}
-
-/**
- * Return a codec for a value that must be a number.
- */
-export function codecForBoolean(): Codec<boolean> {
- return {
- decode(x: any, c?: Context): boolean {
- if (typeof x === "boolean") {
- return x;
- }
- throw new DecodingError(
- `expected boolean at ${renderContext(c)} but got ${typeof x}`,
- );
- },
- };
-}
-
-/**
- * Return a codec for a value that must be a string.
- */
-export function codecForString(): Codec<string> {
- return {
- decode(x: any, c?: Context): string {
- if (typeof x === "string") {
- return x;
- }
- throw new DecodingError(
- `expected string at ${renderContext(c)} but got ${typeof x}`,
- );
- },
- };
-}
-
-/**
- * Codec that allows any value.
- */
-export function codecForAny(): Codec<any> {
- return {
- decode(x: any, c?: Context): any {
- return x;
- },
- };
-}
-
-/**
- * Return a codec for a value that must be a string.
- */
-export function codecForConstString<V extends string>(s: V): Codec<V> {
- return {
- decode(x: any, c?: Context): V {
- if (x === s) {
- return x;
- }
- if (typeof x !== "string") {
- throw new DecodingError(
- `expected string constant "${s}" at ${renderContext(
- c,
- )} but got ${typeof x}`,
- );
- }
- throw new DecodingError(
- `expected string constant "${s}" at ${renderContext(
- c,
- )} but got string value "${x}"`,
- );
- },
- };
-}
-
-/**
- * Return a codec for a boolean true constant.
- */
-export function codecForConstTrue(): Codec<true> {
- return {
- decode(x: any, c?: Context): true {
- if (x === true) {
- return x;
- }
- throw new DecodingError(
- `expected boolean true at ${renderContext(c)} but got ${typeof x}`,
- );
- },
- };
-}
-
-/**
- * Return a codec for a boolean true constant.
- */
-export function codecForConstFalse(): Codec<false> {
- return {
- decode(x: any, c?: Context): false {
- if (x === false) {
- return x;
- }
- throw new DecodingError(
- `expected boolean false at ${renderContext(c)} but got ${typeof x}`,
- );
- },
- };
-}
-
-/**
- * Return a codec for a value that must be a constant number.
- */
-export function codecForConstNumber<V extends number>(n: V): Codec<V> {
- return {
- decode(x: any, c?: Context): V {
- if (x === n) {
- return x;
- }
- throw new DecodingError(
- `expected number constant "${n}" at ${renderContext(
- c,
- )} but got ${typeof x}`,
- );
- },
- };
-}
-
-export function codecOptional<V>(innerCodec: Codec<V>): Codec<V | undefined> {
- return {
- decode(x: any, c?: Context): V | undefined {
- if (x === undefined || x === null) {
- return undefined;
- }
- return innerCodec.decode(x, c);
- },
- };
-}
diff --git a/packages/taler-wallet-core/src/util/coinSelection-test.ts b/packages/taler-wallet-core/src/util/coinSelection-test.ts
index 3ac718aaf..962a14835 100644
--- a/packages/taler-wallet-core/src/util/coinSelection-test.ts
+++ b/packages/taler-wallet-core/src/util/coinSelection-test.ts
@@ -17,8 +17,8 @@
/**
* Imports.
*/
+import { AmountJson, Amounts } from "@gnu-taler/taler-util";
import test from "ava";
-import { AmountJson, Amounts } from "..";
import { AvailableCoinInfo, selectPayCoins } from "./coinSelection";
function a(x: string): AmountJson {
diff --git a/packages/taler-wallet-core/src/util/coinSelection.ts b/packages/taler-wallet-core/src/util/coinSelection.ts
index d32ab6f3c..e9cec6144 100644
--- a/packages/taler-wallet-core/src/util/coinSelection.ts
+++ b/packages/taler-wallet-core/src/util/coinSelection.ts
@@ -23,7 +23,7 @@
/**
* Imports.
*/
-import { AmountJson, Amounts } from "./amounts";
+import { AmountJson, Amounts } from "@gnu-taler/taler-util";
import { strcmp } from "./helpers";
/**
diff --git a/packages/taler-wallet-core/src/util/helpers.ts b/packages/taler-wallet-core/src/util/helpers.ts
index f5c204310..36ecc83fe 100644
--- a/packages/taler-wallet-core/src/util/helpers.ts
+++ b/packages/taler-wallet-core/src/util/helpers.ts
@@ -21,8 +21,7 @@
/**
* Imports.
*/
-import { AmountJson } from "./amounts";
-import * as Amounts from "./amounts";
+import { AmountJson, Amounts } from "@gnu-taler/taler-util";
import { URL } from "./url";
/**
diff --git a/packages/taler-wallet-core/src/util/http.ts b/packages/taler-wallet-core/src/util/http.ts
index 73f08d407..ee6ff80a2 100644
--- a/packages/taler-wallet-core/src/util/http.ts
+++ b/packages/taler-wallet-core/src/util/http.ts
@@ -24,19 +24,18 @@
/**
* Imports
*/
-import { Codec } from "./codec";
import { OperationFailedError, makeErrorDetails } from "../operations/errors";
-import { TalerErrorCode } from "../TalerErrorCode";
import { Logger } from "./logging";
import {
Duration,
Timestamp,
getTimestampNow,
timestampAddDuration,
- timestampMin,
timestampMax,
-} from "./time";
-import { TalerErrorDetails } from "..";
+ TalerErrorDetails,
+ Codec,
+} from "@gnu-taler/taler-util";
+import { TalerErrorCode } from "@gnu-taler/taler-util";
const logger = new Logger("http.ts");
diff --git a/packages/taler-wallet-core/src/util/libtoolVersion-test.ts b/packages/taler-wallet-core/src/util/libtoolVersion-test.ts
deleted file mode 100644
index e58e94759..000000000
--- a/packages/taler-wallet-core/src/util/libtoolVersion-test.ts
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- This file is part of TALER
- (C) 2017 GNUnet e.V.
-
- 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.
-
- 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
- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-import * as LibtoolVersion from "./libtoolVersion";
-
-import test from "ava";
-
-test("version comparison", (t) => {
- t.deepEqual(LibtoolVersion.compare("0:0:0", "0:0:0"), {
- compatible: true,
- currentCmp: 0,
- });
- t.deepEqual(LibtoolVersion.compare("0:0:0", ""), undefined);
- t.deepEqual(LibtoolVersion.compare("foo", "0:0:0"), undefined);
- t.deepEqual(LibtoolVersion.compare("0:0:0", "1:0:1"), {
- compatible: true,
- currentCmp: -1,
- });
- t.deepEqual(LibtoolVersion.compare("0:0:0", "1:5:1"), {
- compatible: true,
- currentCmp: -1,
- });
- t.deepEqual(LibtoolVersion.compare("0:0:0", "1:5:0"), {
- compatible: false,
- currentCmp: -1,
- });
- t.deepEqual(LibtoolVersion.compare("1:0:0", "0:5:0"), {
- compatible: false,
- currentCmp: 1,
- });
- t.deepEqual(LibtoolVersion.compare("1:0:1", "1:5:1"), {
- compatible: true,
- currentCmp: 0,
- });
-});
diff --git a/packages/taler-wallet-core/src/util/libtoolVersion.ts b/packages/taler-wallet-core/src/util/libtoolVersion.ts
deleted file mode 100644
index 5e9d0b74e..000000000
--- a/packages/taler-wallet-core/src/util/libtoolVersion.ts
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- This file is part of TALER
- (C) 2017 GNUnet e.V.
-
- 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.
-
- 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
- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-/**
- * Semantic versioning, but libtool-style.
- * See https://www.gnu.org/software/libtool/manual/html_node/Libtool-versioning.html
- */
-
-/**
- * Result of comparing two libtool versions.
- */
-export interface VersionMatchResult {
- /**
- * Is the first version compatible with the second?
- */
- compatible: boolean;
- /**
- * Is the first version older (-1), newser (+1) or
- * identical (0)?
- */
- currentCmp: number;
-}
-
-interface Version {
- current: number;
- revision: number;
- age: number;
-}
-
-/**
- * Compare two libtool-style version strings.
- */
-export function compare(
- me: string,
- other: string,
-): VersionMatchResult | undefined {
- const meVer = parseVersion(me);
- const otherVer = parseVersion(other);
-
- if (!(meVer && otherVer)) {
- return undefined;
- }
-
- const compatible =
- meVer.current - meVer.age <= otherVer.current &&
- meVer.current >= otherVer.current - otherVer.age;
-
- const currentCmp = Math.sign(meVer.current - otherVer.current);
-
- return { compatible, currentCmp };
-}
-
-function parseVersion(v: string): Version | undefined {
- const [currentStr, revisionStr, ageStr, ...rest] = v.split(":");
- if (rest.length !== 0) {
- return undefined;
- }
- const current = Number.parseInt(currentStr);
- const revision = Number.parseInt(revisionStr);
- const age = Number.parseInt(ageStr);
-
- if (Number.isNaN(current)) {
- return undefined;
- }
-
- if (Number.isNaN(revision)) {
- return undefined;
- }
-
- if (Number.isNaN(age)) {
- return undefined;
- }
-
- return { current, revision, age };
-}
diff --git a/packages/taler-wallet-core/src/util/payto-test.ts b/packages/taler-wallet-core/src/util/payto-test.ts
deleted file mode 100644
index 01280b650..000000000
--- a/packages/taler-wallet-core/src/util/payto-test.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2019 GNUnet e.V.
-
- 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 test from "ava";
-
-import { parsePaytoUri } from "./payto";
-
-test("basic payto parsing", (t) => {
- const r1 = parsePaytoUri("https://example.com/");
- t.is(r1, undefined);
-
- const r2 = parsePaytoUri("payto:blabla");
- t.is(r2, undefined);
-
- const r3 = parsePaytoUri("payto://x-taler-bank/123");
- t.is(r3?.targetType, "x-taler-bank");
- t.is(r3?.targetPath, "123");
-});
diff --git a/packages/taler-wallet-core/src/util/payto.ts b/packages/taler-wallet-core/src/util/payto.ts
deleted file mode 100644
index a1c47eb2f..000000000
--- a/packages/taler-wallet-core/src/util/payto.ts
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2019 GNUnet e.V.
-
- 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 { URLSearchParams } from "./url";
-
-interface PaytoUri {
- targetType: string;
- targetPath: string;
- params: { [name: string]: string };
-}
-
-const paytoPfx = "payto://";
-
-/**
- * Add query parameters to a payto URI
- */
-export function addPaytoQueryParams(
- s: string,
- params: { [name: string]: string },
-): string {
- const [acct, search] = s.slice(paytoPfx.length).split("?");
- const searchParams = new URLSearchParams(search || "");
- for (const k of Object.keys(params)) {
- searchParams.set(k, params[k]);
- }
- return paytoPfx + acct + "?" + searchParams.toString();
-}
-
-export function parsePaytoUri(s: string): PaytoUri | undefined {
- if (!s.startsWith(paytoPfx)) {
- return undefined;
- }
-
- const [acct, search] = s.slice(paytoPfx.length).split("?");
-
- const firstSlashPos = acct.indexOf("/");
-
- if (firstSlashPos === -1) {
- return undefined;
- }
-
- const targetType = acct.slice(0, firstSlashPos);
- const targetPath = acct.slice(firstSlashPos + 1);
-
- const params: { [k: string]: string } = {};
-
- const searchParams = new URLSearchParams(search || "");
-
- searchParams.forEach((v, k) => {
- params[v] = k;
- });
-
- return {
- targetPath,
- targetType,
- params,
- };
-}
diff --git a/packages/taler-wallet-core/src/util/retries.ts b/packages/taler-wallet-core/src/util/retries.ts
index 8be78cfc8..54bb0b2ee 100644
--- a/packages/taler-wallet-core/src/util/retries.ts
+++ b/packages/taler-wallet-core/src/util/retries.ts
@@ -21,7 +21,7 @@
/**
* Imports.
*/
-import { Timestamp, Duration, getTimestampNow } from "./time";
+import { Timestamp, Duration, getTimestampNow } from "@gnu-taler/taler-util";
export interface RetryInfo {
firstTry: Timestamp;
diff --git a/packages/taler-wallet-core/src/util/talerconfig-test.ts b/packages/taler-wallet-core/src/util/talerconfig-test.ts
deleted file mode 100644
index 2f920fccf..000000000
--- a/packages/taler-wallet-core/src/util/talerconfig-test.ts
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2020 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/>
- */
-
-/**
- * Imports
- */
-import test from "ava";
-import { pathsub, Configuration } from "./talerconfig";
-
-test("pathsub", (t) => {
- t.assert("foo" === pathsub("foo", () => undefined));
-
- t.assert("fo${bla}o" === pathsub("fo${bla}o", () => undefined));
-
- const d: Record<string, string> = {
- w: "world",
- f: "foo",
- "1foo": "x",
- foo_bar: "quux",
- };
-
- t.is(
- pathsub("hello ${w}!", (v) => d[v]),
- "hello world!",
- );
-
- t.is(
- pathsub("hello ${w} ${w}!", (v) => d[v]),
- "hello world world!",
- );
-
- t.is(
- pathsub("hello ${x:-blabla}!", (v) => d[v]),
- "hello blabla!",
- );
-
- // No braces
- t.is(
- pathsub("hello $w!", (v) => d[v]),
- "hello world!",
- );
- t.is(
- pathsub("hello $foo!", (v) => d[v]),
- "hello $foo!",
- );
- t.is(
- pathsub("hello $1foo!", (v) => d[v]),
- "hello $1foo!",
- );
- t.is(
- pathsub("hello $$ world!", (v) => d[v]),
- "hello $$ world!",
- );
- t.is(
- pathsub("hello $$ world!", (v) => d[v]),
- "hello $$ world!",
- );
-
- t.is(
- pathsub("hello $foo_bar!", (v) => d[v]),
- "hello quux!",
- );
-
- // Recursive lookup in default
- t.is(
- pathsub("hello ${x:-${w}}!", (v) => d[v]),
- "hello world!",
- );
-
- // No variables in variable name part
- t.is(
- pathsub("hello ${${w}:-x}!", (v) => d[v]),
- "hello ${${w}:-x}!",
- );
-
- // Missing closing brace
- t.is(
- pathsub("hello ${w!", (v) => d[v]),
- "hello ${w!",
- );
-});
-
-test("path expansion", (t) => {
- const config = new Configuration();
- config.setString("paths", "taler_home", "foo/bar");
- config.setString(
- "paths",
- "taler_data_home",
- "$TALER_HOME/.local/share/taler/",
- );
- config.setString(
- "exchange",
- "master_priv_file",
- "${TALER_DATA_HOME}/exchange/offline-keys/master.priv",
- );
- t.is(
- config.getPath("exchange", "MaStER_priv_file").required(),
- "foo/bar/.local/share/taler//exchange/offline-keys/master.priv",
- );
-});
-
-test("recursive path resolution", (t) => {
- console.log("recursive test");
- const config = new Configuration();
- config.setString("paths", "a", "x${b}");
- config.setString("paths", "b", "y${a}");
- config.setString("foo", "x", "z${a}");
- t.throws(() => {
- config.getPath("foo", "a").required();
- });
-});
diff --git a/packages/taler-wallet-core/src/util/talerconfig.ts b/packages/taler-wallet-core/src/util/talerconfig.ts
deleted file mode 100644
index fa8c2d40f..000000000
--- a/packages/taler-wallet-core/src/util/talerconfig.ts
+++ /dev/null
@@ -1,318 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2020 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/>
- */
-
-/**
- * Utilities to handle Taler-style configuration files.
- *
- * @author Florian Dold <dold@taler.net>
- */
-
-/**
- * Imports
- */
-import { AmountJson } from "./amounts";
-import * as Amounts from "./amounts";
-import fs from "fs";
-
-export class ConfigError extends Error {
- constructor(message: string) {
- super();
- Object.setPrototypeOf(this, ConfigError.prototype);
- this.name = "ConfigError";
- this.message = message;
- }
-}
-
-type OptionMap = { [optionName: string]: string };
-type SectionMap = { [sectionName: string]: OptionMap };
-
-export class ConfigValue<T> {
- constructor(
- private sectionName: string,
- private optionName: string,
- private val: string | undefined,
- private converter: (x: string) => T,
- ) {}
-
- required(): T {
- if (!this.val) {
- throw new ConfigError(
- `required option [${this.sectionName}]/${this.optionName} not found`,
- );
- }
- return this.converter(this.val);
- }
-
- orUndefined(): T | undefined {
- if (this.val !== undefined) {
- return this.converter(this.val);
- } else {
- return undefined;
- }
- }
-
- orDefault(v: T): T | undefined {
- if (this.val !== undefined) {
- return this.converter(this.val);
- } else {
- return v;
- }
- }
-
- isDefined(): boolean {
- return this.val !== undefined;
- }
-}
-
-/**
- * Shell-style path substitution.
- *
- * Supported patterns:
- * "$x" (look up "x")
- * "${x}" (look up "x")
- * "${x:-y}" (look up "x", fall back to expanded y)
- */
-export function pathsub(
- x: string,
- lookup: (s: string, depth: number) => string | undefined,
- depth = 0,
-): string {
- if (depth >= 10) {
- throw Error("recursion in path substitution");
- }
- let s = x;
- let l = 0;
- while (l < s.length) {
- if (s[l] === "$") {
- if (s[l + 1] === "{") {
- let depth = 1;
- const start = l;
- let p = start + 2;
- let insideNamePart = true;
- let hasDefault = false;
- for (; p < s.length; p++) {
- if (s[p] == "}") {
- insideNamePart = false;
- depth--;
- } else if (s[p] === "$" && s[p + 1] === "{") {
- insideNamePart = false;
- depth++;
- }
- if (insideNamePart && s[p] === ":" && s[p + 1] === "-") {
- hasDefault = true;
- }
- if (depth == 0) {
- break;
- }
- }
- if (depth == 0) {
- const inner = s.slice(start + 2, p);
- let varname: string;
- let defaultValue: string | undefined;
- if (hasDefault) {
- [varname, defaultValue] = inner.split(":-", 2);
- } else {
- varname = inner;
- defaultValue = undefined;
- }
-
- const r = lookup(inner, depth + 1);
- if (r !== undefined) {
- s = s.substr(0, start) + r + s.substr(p + 1);
- l = start + r.length;
- continue;
- } else if (defaultValue !== undefined) {
- const resolvedDefault = pathsub(defaultValue, lookup, depth + 1);
- s = s.substr(0, start) + resolvedDefault + s.substr(p + 1);
- l = start + resolvedDefault.length;
- continue;
- }
- }
- l = p;
- continue;
- } else {
- const m = /^[a-zA-Z-_][a-zA-Z0-9-_]*/.exec(s.substring(l + 1));
- if (m && m[0]) {
- const r = lookup(m[0], depth + 1);
- if (r !== undefined) {
- s = s.substr(0, l) + r + s.substr(l + 1 + m[0].length);
- l = l + r.length;
- continue;
- }
- }
- }
- }
- l++;
- }
- return s;
-}
-
-export class Configuration {
- private sectionMap: SectionMap = {};
-
- loadFromString(s: string): void {
- const reComment = /^\s*#.*$/;
- const reSection = /^\s*\[\s*([^\]]*)\s*\]\s*$/;
- const reParam = /^\s*([^=]+?)\s*=\s*(.*?)\s*$/;
- const reEmptyLine = /^\s*$/;
-
- let currentSection: string | undefined = undefined;
-
- const lines = s.split("\n");
- for (const line of lines) {
- if (reEmptyLine.test(line)) {
- continue;
- }
- if (reComment.test(line)) {
- continue;
- }
- const secMatch = line.match(reSection);
- if (secMatch) {
- currentSection = secMatch[1];
- continue;
- }
- if (currentSection === undefined) {
- throw Error("invalid configuration, expected section header");
- }
- currentSection = currentSection.toUpperCase();
- const paramMatch = line.match(reParam);
- if (paramMatch) {
- const optName = paramMatch[1].toUpperCase();
- let val = paramMatch[2];
- if (val.startsWith('"') && val.endsWith('"')) {
- val = val.slice(1, val.length - 1);
- }
- const sec = this.sectionMap[currentSection] ?? {};
- this.sectionMap[currentSection] = Object.assign(sec, {
- [optName]: val,
- });
- continue;
- }
- throw Error(
- "invalid configuration, expected section header or option assignment",
- );
- }
- }
-
- setString(section: string, option: string, value: string): void {
- const secNorm = section.toUpperCase();
- const sec = this.sectionMap[secNorm] ?? (this.sectionMap[secNorm] = {});
- sec[option.toUpperCase()] = value;
- }
-
- /**
- * Get lower-cased section names.
- */
- getSectionNames(): string[] {
- return Object.keys(this.sectionMap).map((x) => x.toLowerCase());
- }
-
- getString(section: string, option: string): ConfigValue<string> {
- const secNorm = section.toUpperCase();
- const optNorm = option.toUpperCase();
- const val = (this.sectionMap[secNorm] ?? {})[optNorm];
- return new ConfigValue(secNorm, optNorm, val, (x) => x);
- }
-
- getPath(section: string, option: string): ConfigValue<string> {
- const secNorm = section.toUpperCase();
- const optNorm = option.toUpperCase();
- const val = (this.sectionMap[secNorm] ?? {})[optNorm];
- return new ConfigValue(secNorm, optNorm, val, (x) =>
- pathsub(x, (v, d) => this.lookupVariable(v, d + 1)),
- );
- }
-
- getYesNo(section: string, option: string): ConfigValue<boolean> {
- const secNorm = section.toUpperCase();
- const optNorm = option.toUpperCase();
- const val = (this.sectionMap[secNorm] ?? {})[optNorm];
- const convert = (x: string): boolean => {
- x = x.toLowerCase();
- if (x === "yes") {
- return true;
- } else if (x === "no") {
- return false;
- }
- throw Error(
- `invalid config value for [${secNorm}]/${optNorm}, expected yes/no`,
- );
- };
- return new ConfigValue(secNorm, optNorm, val, convert);
- }
-
- getNumber(section: string, option: string): ConfigValue<number> {
- const secNorm = section.toUpperCase();
- const optNorm = option.toUpperCase();
- const val = (this.sectionMap[secNorm] ?? {})[optNorm];
- const convert = (x: string): number => {
- try {
- return Number.parseInt(x, 10);
- } catch (e) {
- throw Error(
- `invalid config value for [${secNorm}]/${optNorm}, expected number`,
- );
- }
- };
- return new ConfigValue(secNorm, optNorm, val, convert);
- }
-
- lookupVariable(x: string, depth: number = 0): string | undefined {
- // We loop up options in PATHS in upper case, as option names
- // are case insensitive
- const val = (this.sectionMap["PATHS"] ?? {})[x.toUpperCase()];
- if (val !== undefined) {
- return pathsub(val, (v, d) => this.lookupVariable(v, d), depth);
- }
- // Environment variables can be case sensitive, respect that.
- const envVal = process.env[x];
- if (envVal !== undefined) {
- return envVal;
- }
- return;
- }
-
- getAmount(section: string, option: string): ConfigValue<AmountJson> {
- const val = (this.sectionMap[section] ?? {})[option];
- return new ConfigValue(section, option, val, (x) =>
- Amounts.parseOrThrow(x),
- );
- }
-
- static load(filename: string): Configuration {
- const s = fs.readFileSync(filename, "utf-8");
- const cfg = new Configuration();
- cfg.loadFromString(s);
- return cfg;
- }
-
- write(filename: string): void {
- let s = "";
- for (const sectionName of Object.keys(this.sectionMap)) {
- s += `[${sectionName}]\n`;
- for (const optionName of Object.keys(
- this.sectionMap[sectionName] ?? {},
- )) {
- const val = this.sectionMap[sectionName][optionName];
- if (val !== undefined) {
- s += `${optionName} = ${val}\n`;
- }
- }
- s += "\n";
- }
- fs.writeFileSync(filename, s);
- }
-}
diff --git a/packages/taler-wallet-core/src/util/taleruri-test.ts b/packages/taler-wallet-core/src/util/taleruri-test.ts
deleted file mode 100644
index e80acc5c3..000000000
--- a/packages/taler-wallet-core/src/util/taleruri-test.ts
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2019 GNUnet e.V.
-
- 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 test from "ava";
-import {
- parsePayUri,
- parseWithdrawUri,
- parseRefundUri,
- parseTipUri,
-} from "./taleruri";
-
-test("taler pay url parsing: wrong scheme", (t) => {
- const url1 = "talerfoo://";
- const r1 = parsePayUri(url1);
- t.is(r1, undefined);
-
- const url2 = "taler://refund/a/b/c/d/e/f";
- const r2 = parsePayUri(url2);
- t.is(r2, undefined);
-});
-
-test("taler pay url parsing: defaults", (t) => {
- const url1 = "taler://pay/example.com/myorder/";
- const r1 = parsePayUri(url1);
- if (!r1) {
- t.fail();
- return;
- }
- t.is(r1.merchantBaseUrl, "https://example.com/");
- t.is(r1.sessionId, "");
-
- const url2 = "taler://pay/example.com/myorder/mysession";
- const r2 = parsePayUri(url2);
- if (!r2) {
- t.fail();
- return;
- }
- t.is(r2.merchantBaseUrl, "https://example.com/");
- t.is(r2.sessionId, "mysession");
-});
-
-test("taler pay url parsing: instance", (t) => {
- const url1 = "taler://pay/example.com/instances/myinst/myorder/";
- const r1 = parsePayUri(url1);
- if (!r1) {
- t.fail();
- return;
- }
- t.is(r1.merchantBaseUrl, "https://example.com/instances/myinst/");
- t.is(r1.orderId, "myorder");
-});
-
-test("taler pay url parsing (claim token)", (t) => {
- const url1 = "taler://pay/example.com/instances/myinst/myorder/?c=ASDF";
- const r1 = parsePayUri(url1);
- if (!r1) {
- t.fail();
- return;
- }
- t.is(r1.merchantBaseUrl, "https://example.com/instances/myinst/");
- t.is(r1.orderId, "myorder");
- t.is(r1.claimToken, "ASDF");
-});
-
-test("taler refund uri parsing: non-https #1", (t) => {
- const url1 = "taler+http://refund/example.com/myorder/";
- const r1 = parseRefundUri(url1);
- if (!r1) {
- t.fail();
- return;
- }
- t.is(r1.merchantBaseUrl, "http://example.com/");
- t.is(r1.orderId, "myorder");
-});
-
-test("taler pay uri parsing: non-https", (t) => {
- const url1 = "taler+http://pay/example.com/myorder/";
- const r1 = parsePayUri(url1);
- if (!r1) {
- t.fail();
- return;
- }
- t.is(r1.merchantBaseUrl, "http://example.com/");
- t.is(r1.orderId, "myorder");
-});
-
-test("taler pay uri parsing: missing session component", (t) => {
- const url1 = "taler+http://pay/example.com/myorder";
- const r1 = parsePayUri(url1);
- if (r1) {
- t.fail();
- return;
- }
- t.pass();
-});
-
-test("taler withdraw uri parsing", (t) => {
- const url1 = "taler://withdraw/bank.example.com/12345";
- const r1 = parseWithdrawUri(url1);
- if (!r1) {
- t.fail();
- return;
- }
- t.is(r1.withdrawalOperationId, "12345");
- t.is(r1.bankIntegrationApiBaseUrl, "https://bank.example.com/");
-});
-
-test("taler withdraw uri parsing (http)", (t) => {
- const url1 = "taler+http://withdraw/bank.example.com/12345";
- const r1 = parseWithdrawUri(url1);
- if (!r1) {
- t.fail();
- return;
- }
- t.is(r1.withdrawalOperationId, "12345");
- t.is(r1.bankIntegrationApiBaseUrl, "http://bank.example.com/");
-});
-
-test("taler refund uri parsing", (t) => {
- const url1 = "taler://refund/merchant.example.com/1234/";
- const r1 = parseRefundUri(url1);
- if (!r1) {
- t.fail();
- return;
- }
- t.is(r1.merchantBaseUrl, "https://merchant.example.com/");
- t.is(r1.orderId, "1234");
-});
-
-test("taler refund uri parsing with instance", (t) => {
- const url1 = "taler://refund/merchant.example.com/instances/myinst/1234/";
- const r1 = parseRefundUri(url1);
- if (!r1) {
- t.fail();
- return;
- }
- t.is(r1.orderId, "1234");
- t.is(r1.merchantBaseUrl, "https://merchant.example.com/instances/myinst/");
-});
-
-test("taler tip pickup uri", (t) => {
- const url1 = "taler://tip/merchant.example.com/tipid";
- const r1 = parseTipUri(url1);
- if (!r1) {
- t.fail();
- return;
- }
- t.is(r1.merchantBaseUrl, "https://merchant.example.com/");
-});
-
-test("taler tip pickup uri with instance", (t) => {
- const url1 = "taler://tip/merchant.example.com/instances/tipm/tipid";
- const r1 = parseTipUri(url1);
- if (!r1) {
- t.fail();
- return;
- }
- t.is(r1.merchantBaseUrl, "https://merchant.example.com/instances/tipm/");
- t.is(r1.merchantTipId, "tipid");
-});
-
-test("taler tip pickup uri with instance and prefix", (t) => {
- const url1 = "taler://tip/merchant.example.com/my/pfx/tipm/tipid";
- const r1 = parseTipUri(url1);
- if (!r1) {
- t.fail();
- return;
- }
- t.is(r1.merchantBaseUrl, "https://merchant.example.com/my/pfx/tipm/");
- t.is(r1.merchantTipId, "tipid");
-});
diff --git a/packages/taler-wallet-core/src/util/taleruri.ts b/packages/taler-wallet-core/src/util/taleruri.ts
deleted file mode 100644
index d8366fd0f..000000000
--- a/packages/taler-wallet-core/src/util/taleruri.ts
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2019-2020 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 { canonicalizeBaseUrl } from "./helpers";
-import { URLSearchParams } from "./url";
-
-export interface PayUriResult {
- merchantBaseUrl: string;
- orderId: string;
- sessionId: string;
- claimToken: string | undefined;
-}
-
-export interface WithdrawUriResult {
- bankIntegrationApiBaseUrl: string;
- withdrawalOperationId: string;
-}
-
-export interface RefundUriResult {
- merchantBaseUrl: string;
- orderId: string;
-}
-
-export interface TipUriResult {
- merchantTipId: string;
- merchantBaseUrl: string;
-}
-
-/**
- * Parse a taler[+http]://withdraw URI.
- * Return undefined if not passed a valid URI.
- */
-export function parseWithdrawUri(s: string): WithdrawUriResult | undefined {
- const pi = parseProtoInfo(s, "withdraw");
- if (!pi) {
- return undefined;
- }
- const parts = pi.rest.split("/");
-
- if (parts.length < 2) {
- return undefined;
- }
-
- const host = parts[0].toLowerCase();
- const pathSegments = parts.slice(1, parts.length - 1);
- const withdrawId = parts[parts.length - 1];
- const p = [host, ...pathSegments].join("/");
-
- return {
- bankIntegrationApiBaseUrl: canonicalizeBaseUrl(`${pi.innerProto}://${p}/`),
- withdrawalOperationId: withdrawId,
- };
-}
-
-export enum TalerUriType {
- TalerPay = "taler-pay",
- TalerWithdraw = "taler-withdraw",
- TalerTip = "taler-tip",
- TalerRefund = "taler-refund",
- TalerNotifyReserve = "taler-notify-reserve",
- Unknown = "unknown",
-}
-
-/**
- * Classify a taler:// URI.
- */
-export function classifyTalerUri(s: string): TalerUriType {
- const sl = s.toLowerCase();
- if (sl.startsWith("taler://pay/")) {
- return TalerUriType.TalerPay;
- }
- if (sl.startsWith("taler+http://pay/")) {
- return TalerUriType.TalerPay;
- }
- if (sl.startsWith("taler://tip/")) {
- return TalerUriType.TalerTip;
- }
- if (sl.startsWith("taler+http://tip/")) {
- return TalerUriType.TalerTip;
- }
- if (sl.startsWith("taler://refund/")) {
- return TalerUriType.TalerRefund;
- }
- if (sl.startsWith("taler+http://refund/")) {
- return TalerUriType.TalerRefund;
- }
- if (sl.startsWith("taler://withdraw/")) {
- return TalerUriType.TalerWithdraw;
- }
- if (sl.startsWith("taler+http://withdraw/")) {
- return TalerUriType.TalerWithdraw;
- }
- if (sl.startsWith("taler://notify-reserve/")) {
- return TalerUriType.TalerNotifyReserve;
- }
- return TalerUriType.Unknown;
-}
-
-interface TalerUriProtoInfo {
- innerProto: "http" | "https";
- rest: string;
-}
-
-function parseProtoInfo(
- s: string,
- action: string,
-): TalerUriProtoInfo | undefined {
- const pfxPlain = `taler://${action}/`;
- const pfxHttp = `taler+http://${action}/`;
- if (s.toLowerCase().startsWith(pfxPlain)) {
- return {
- innerProto: "https",
- rest: s.substring(pfxPlain.length),
- };
- } else if (s.toLowerCase().startsWith(pfxHttp)) {
- return {
- innerProto: "http",
- rest: s.substring(pfxHttp.length),
- };
- } else {
- return undefined;
- }
-}
-
-/**
- * Parse a taler[+http]://pay URI.
- * Return undefined if not passed a valid URI.
- */
-export function parsePayUri(s: string): PayUriResult | undefined {
- const pi = parseProtoInfo(s, "pay");
- if (!pi) {
- return undefined;
- }
- const c = pi?.rest.split("?");
- const q = new URLSearchParams(c[1] ?? "");
- const claimToken = q.get("c") ?? undefined;
- const parts = c[0].split("/");
- if (parts.length < 3) {
- return undefined;
- }
- const host = parts[0].toLowerCase();
- const sessionId = parts[parts.length - 1];
- const orderId = parts[parts.length - 2];
- const pathSegments = parts.slice(1, parts.length - 2);
- const p = [host, ...pathSegments].join("/");
- const merchantBaseUrl = canonicalizeBaseUrl(`${pi.innerProto}://${p}/`);
-
- return {
- merchantBaseUrl,
- orderId,
- sessionId: sessionId,
- claimToken,
- };
-}
-
-/**
- * Parse a taler[+http]://tip URI.
- * Return undefined if not passed a valid URI.
- */
-export function parseTipUri(s: string): TipUriResult | undefined {
- const pi = parseProtoInfo(s, "tip");
- if (!pi) {
- return undefined;
- }
- const c = pi?.rest.split("?");
- const parts = c[0].split("/");
- if (parts.length < 2) {
- return undefined;
- }
- const host = parts[0].toLowerCase();
- const tipId = parts[parts.length - 1];
- const pathSegments = parts.slice(1, parts.length - 1);
- const p = [host, ...pathSegments].join("/");
- const merchantBaseUrl = canonicalizeBaseUrl(`${pi.innerProto}://${p}/`);
-
- return {
- merchantBaseUrl,
- merchantTipId: tipId,
- };
-}
-
-/**
- * Parse a taler[+http]://refund URI.
- * Return undefined if not passed a valid URI.
- */
-export function parseRefundUri(s: string): RefundUriResult | undefined {
- const pi = parseProtoInfo(s, "refund");
- if (!pi) {
- return undefined;
- }
- const c = pi?.rest.split("?");
- const parts = c[0].split("/");
- if (parts.length < 3) {
- return undefined;
- }
- const host = parts[0].toLowerCase();
- const sessionId = parts[parts.length - 1];
- const orderId = parts[parts.length - 2];
- const pathSegments = parts.slice(1, parts.length - 2);
- const p = [host, ...pathSegments].join("/");
- const merchantBaseUrl = canonicalizeBaseUrl(`${pi.innerProto}://${p}/`);
-
- return {
- merchantBaseUrl,
- orderId,
- };
-}
diff --git a/packages/taler-wallet-core/src/util/testvectors.ts b/packages/taler-wallet-core/src/util/testvectors.ts
deleted file mode 100644
index 57ac6e992..000000000
--- a/packages/taler-wallet-core/src/util/testvectors.ts
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2020 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/>
- */
-
-/**
- * Imports
- */
-import {
- setupRefreshPlanchet,
- encodeCrock,
- getRandomBytes,
-} from "../crypto/talerCrypto";
-
-export function printTestVectors() {
- const secretSeed = getRandomBytes(64);
- const coinIndex = Math.ceil(Math.random() * 100);
- const p = setupRefreshPlanchet(secretSeed, coinIndex);
- console.log("setupRefreshPlanchet");
- console.log(` (in) secret seed: ${encodeCrock(secretSeed)}`);
- console.log(` (in) coin index: ${coinIndex}`);
- console.log(` (out) blinding secret: ${encodeCrock(p.bks)}`);
- console.log(` (out) coin priv: ${encodeCrock(p.coinPriv)}`);
- console.log(` (out) coin pub: ${encodeCrock(p.coinPub)}`);
-}
diff --git a/packages/taler-wallet-core/src/util/time.ts b/packages/taler-wallet-core/src/util/time.ts
deleted file mode 100644
index be63aef6b..000000000
--- a/packages/taler-wallet-core/src/util/time.ts
+++ /dev/null
@@ -1,261 +0,0 @@
-import { Codec, renderContext, Context } from "./codec";
-
-/*
- This file is part of GNU Taler
- (C) 2017-2019 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/>
- */
-
-/**
- * Helpers for relative and absolute time.
- */
-
-export class Timestamp {
- /**
- * Timestamp in milliseconds.
- */
- readonly t_ms: number | "never";
-}
-
-export interface Duration {
- /**
- * Duration in milliseconds.
- */
- readonly d_ms: number | "forever";
-}
-
-let timeshift = 0;
-
-export function setDangerousTimetravel(dt: number): void {
- timeshift = dt;
-}
-
-export function getTimestampNow(): Timestamp {
- return {
- t_ms: new Date().getTime() + timeshift,
- };
-}
-
-export function isTimestampExpired(t: Timestamp) {
- return timestampCmp(t, getTimestampNow()) <= 0;
-}
-
-export function getDurationRemaining(
- deadline: Timestamp,
- now = getTimestampNow(),
-): Duration {
- if (deadline.t_ms === "never") {
- return { d_ms: "forever" };
- }
- if (now.t_ms === "never") {
- throw Error("invalid argument for 'now'");
- }
- if (deadline.t_ms < now.t_ms) {
- return { d_ms: 0 };
- }
- return { d_ms: deadline.t_ms - now.t_ms };
-}
-
-export function timestampMin(t1: Timestamp, t2: Timestamp): Timestamp {
- if (t1.t_ms === "never") {
- return { t_ms: t2.t_ms };
- }
- if (t2.t_ms === "never") {
- return { t_ms: t2.t_ms };
- }
- return { t_ms: Math.min(t1.t_ms, t2.t_ms) };
-}
-
-export function timestampMax(t1: Timestamp, t2: Timestamp): Timestamp {
- if (t1.t_ms === "never") {
- return { t_ms: "never" };
- }
- if (t2.t_ms === "never") {
- return { t_ms: "never" };
- }
- return { t_ms: Math.max(t1.t_ms, t2.t_ms) };
-}
-
-const SECONDS = 1000;
-const MINUTES = SECONDS * 60;
-const HOURS = MINUTES * 60;
-const DAYS = HOURS * 24;
-const MONTHS = DAYS * 30;
-const YEARS = DAYS * 365;
-
-export function durationFromSpec(spec: {
- seconds?: number;
- minutes?: number;
- hours?: number;
- days?: number;
- months?: number;
- years?: number;
-}): Duration {
- let d_ms = 0;
- d_ms += (spec.seconds ?? 0) * SECONDS;
- d_ms += (spec.minutes ?? 0) * MINUTES;
- d_ms += (spec.hours ?? 0) * HOURS;
- d_ms += (spec.days ?? 0) * DAYS;
- d_ms += (spec.months ?? 0) * MONTHS;
- d_ms += (spec.years ?? 0) * YEARS;
- return { d_ms };
-}
-
-/**
- * Truncate a timestamp so that that it represents a multiple
- * of seconds. The timestamp is always rounded down.
- */
-export function timestampTruncateToSecond(t1: Timestamp): Timestamp {
- if (t1.t_ms === "never") {
- return { t_ms: "never" };
- }
- return {
- t_ms: Math.floor(t1.t_ms / 1000) * 1000,
- };
-}
-
-export function durationMin(d1: Duration, d2: Duration): Duration {
- if (d1.d_ms === "forever") {
- return { d_ms: d2.d_ms };
- }
- if (d2.d_ms === "forever") {
- return { d_ms: d2.d_ms };
- }
- return { d_ms: Math.min(d1.d_ms, d2.d_ms) };
-}
-
-export function durationMax(d1: Duration, d2: Duration): Duration {
- if (d1.d_ms === "forever") {
- return { d_ms: "forever" };
- }
- if (d2.d_ms === "forever") {
- return { d_ms: "forever" };
- }
- return { d_ms: Math.max(d1.d_ms, d2.d_ms) };
-}
-
-export function durationMul(d: Duration, n: number): Duration {
- if (d.d_ms === "forever") {
- return { d_ms: "forever" };
- }
- return { d_ms: Math.round(d.d_ms * n) };
-}
-
-export function durationAdd(d1: Duration, d2: Duration): Duration {
- if (d1.d_ms === "forever" || d2.d_ms === "forever") {
- return { d_ms: "forever" };
- }
- return { d_ms: d1.d_ms + d2.d_ms };
-}
-
-export function timestampCmp(t1: Timestamp, t2: Timestamp): number {
- if (t1.t_ms === "never") {
- if (t2.t_ms === "never") {
- return 0;
- }
- return 1;
- }
- if (t2.t_ms === "never") {
- return -1;
- }
- if (t1.t_ms == t2.t_ms) {
- return 0;
- }
- if (t1.t_ms > t2.t_ms) {
- return 1;
- }
- return -1;
-}
-
-export function timestampAddDuration(t1: Timestamp, d: Duration): Timestamp {
- if (t1.t_ms === "never" || d.d_ms === "forever") {
- return { t_ms: "never" };
- }
- return { t_ms: t1.t_ms + d.d_ms };
-}
-
-export function timestampSubtractDuraction(
- t1: Timestamp,
- d: Duration,
-): Timestamp {
- if (t1.t_ms === "never") {
- return { t_ms: "never" };
- }
- if (d.d_ms === "forever") {
- return { t_ms: 0 };
- }
- return { t_ms: Math.max(0, t1.t_ms - d.d_ms) };
-}
-
-export function stringifyTimestamp(t: Timestamp): string {
- if (t.t_ms === "never") {
- return "never";
- }
- return new Date(t.t_ms).toISOString();
-}
-
-export function timestampDifference(t1: Timestamp, t2: Timestamp): Duration {
- if (t1.t_ms === "never") {
- return { d_ms: "forever" };
- }
- if (t2.t_ms === "never") {
- return { d_ms: "forever" };
- }
- return { d_ms: Math.abs(t1.t_ms - t2.t_ms) };
-}
-
-export function timestampIsBetween(
- t: Timestamp,
- start: Timestamp,
- end: Timestamp,
-): boolean {
- if (timestampCmp(t, start) < 0) {
- return false;
- }
- if (timestampCmp(t, end) > 0) {
- return false;
- }
- return true;
-}
-
-export const codecForTimestamp: Codec<Timestamp> = {
- decode(x: any, c?: Context): Timestamp {
- const t_ms = x.t_ms;
- if (typeof t_ms === "string") {
- if (t_ms === "never") {
- return { t_ms: "never" };
- }
- throw Error(`expected timestamp at ${renderContext(c)}`);
- }
- if (typeof t_ms === "number") {
- return { t_ms };
- }
- throw Error(`expected timestamp at ${renderContext(c)}`);
- },
-};
-
-export const codecForDuration: Codec<Duration> = {
- decode(x: any, c?: Context): Duration {
- const d_ms = x.d_ms;
- if (typeof d_ms === "string") {
- if (d_ms === "forever") {
- return { d_ms: "forever" };
- }
- throw Error(`expected duration at ${renderContext(c)}`);
- }
- if (typeof d_ms === "number") {
- return { d_ms };
- }
- throw Error(`expected duration at ${renderContext(c)}`);
- },
-};
diff --git a/packages/taler-wallet-core/src/util/timer.ts b/packages/taler-wallet-core/src/util/timer.ts
index 75fb5c9c0..9133bd572 100644
--- a/packages/taler-wallet-core/src/util/timer.ts
+++ b/packages/taler-wallet-core/src/util/timer.ts
@@ -24,7 +24,7 @@
/**
* Imports.
*/
-import { Duration } from "./time";
+import { Duration } from "@gnu-taler/taler-util";
import { Logger } from "./logging";
const logger = new Logger("timer.ts");
diff --git a/packages/taler-wallet-core/src/util/wire.ts b/packages/taler-wallet-core/src/util/wire.ts
deleted file mode 100644
index 95e324f3c..000000000
--- a/packages/taler-wallet-core/src/util/wire.ts
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- This file is part of TALER
- (C) 2017 GNUnet e.V.
-
- 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.
-
- 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
- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-/**
- * Display and manipulate wire information.
- *
- * Right now, all types are hard-coded. In the future, there might be plugins / configurable
- * methods or support for the "payto://" URI scheme.
- */
-
-/**
- * Imports.
- */
-import * as i18n from "../i18n";
-
-/**
- * Short summary of the wire information.
- *
- * Might abbreviate and return the same summary for different
- * wire details.
- */
-export function summarizeWire(w: any): string {
- if (!w.type) {
- return i18n.str`Invalid Wire`;
- }
- switch (w.type.toLowerCase()) {
- case "test":
- if (!w.account_number && w.account_number !== 0) {
- return i18n.str`Invalid Test Wire Detail`;
- }
- if (!w.bank_uri) {
- return i18n.str`Invalid Test Wire Detail`;
- }
- return i18n.str`Test Wire Acct #${w.account_number} on ${w.bank_uri}`;
- default:
- return i18n.str`Unknown Wire Detail`;
- }
-}