diff options
92 files changed, 2125 insertions, 2682 deletions
diff --git a/package.json b/package.json index 33be165a1..a13dbded6 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ }, "scripts": { "build": "make tsc", - "pretty": "prettier --config .prettierrc --write 'src/**.ts'" + "pretty": "prettier --config .prettierrc --write src" }, "files": [ "AUTHORS", diff --git a/src/android/index.ts b/src/android/index.ts index 351d89249..6e43fe317 100644 --- a/src/android/index.ts +++ b/src/android/index.ts @@ -151,7 +151,7 @@ class AndroidWalletMessageHandler { }; const w = await getDefaultNodeWallet(this.walletArgs); this.maybeWallet = w; - w.runRetryLoop().catch(e => { + w.runRetryLoop().catch((e) => { console.error("Error during wallet retry loop", e); }); this.wp.resolve(w); @@ -250,7 +250,7 @@ class AndroidWalletMessageHandler { this.maybeWallet = undefined; const w = await getDefaultNodeWallet(this.walletArgs); this.maybeWallet = w; - w.runRetryLoop().catch(e => { + w.runRetryLoop().catch((e) => { console.error("Error during wallet retry loop", e); }); this.wp.resolve(w); diff --git a/src/crypto/primitives/nacl-fast.ts b/src/crypto/primitives/nacl-fast.ts index 66ab78162..14cf569db 100644 --- a/src/crypto/primitives/nacl-fast.ts +++ b/src/crypto/primitives/nacl-fast.ts @@ -5,14 +5,14 @@ // Implementation derived from TweetNaCl version 20140427. // See for details: http://tweetnacl.cr.yp.to/ -const gf = function(init: number[] = []) { +const gf = function (init: number[] = []) { const r = new Float64Array(16); if (init) for (let i = 0; i < init.length; i++) r[i] = init[i]; return r; }; // Pluggable, initialized in high-level API below. -let randombytes = function(x: Uint8Array, n: number): void { +let randombytes = function (x: Uint8Array, n: number): void { throw new Error("no PRNG"); }; @@ -2373,13 +2373,11 @@ function crypto_hash(out: Uint8Array, m: Uint8Array, n: number) { ts64(x, n - 8, (b / 0x20000000) | 0, b << 3); crypto_hashblocks_hl(hh, hl, x, n); - for (let i = 0; i < 8; i++) - ts64(out, 8 * i, hh[i], hl[i]); + for (let i = 0; i < 8; i++) ts64(out, 8 * i, hh[i], hl[i]); return 0; } - /** * Incremental version of crypto_hash. */ @@ -2400,7 +2398,7 @@ export class HashState { this.hh[5] = 0x9b05688c; this.hh[6] = 0x1f83d9ab; this.hh[7] = 0x5be0cd19; - + this.hl[0] = 0xf3bcc908; this.hl[1] = 0x84caa73b; this.hl[2] = 0xfe94f82b; @@ -2416,7 +2414,7 @@ export class HashState { let i = 0; while (i < data.length) { const r = 128 - this.p; - if (r > (data.length - i)) { + if (r > data.length - i) { for (let j = 0; i + j < data.length; j++) { this.next[this.p + j] = data[i + j]; } @@ -2441,14 +2439,13 @@ export class HashState { let b = this.total; for (let i = 0; i < n; i++) x[i] = this.next[i]; x[n] = 128; - + n = 256 - 128 * (n < 112 ? 1 : 0); x[n - 9] = 0; ts64(x, n - 8, (b / 0x20000000) | 0, b << 3); crypto_hashblocks_hl(this.hh, this.hl, x, n); - - for (let i = 0; i < 8; i++) - ts64(out, 8 * i, this.hh[i], this.hl[i]); + + for (let i = 0; i < 8; i++) ts64(out, 8 * i, this.hh[i], this.hl[i]); return out; } } @@ -3078,7 +3075,7 @@ export function sign_ed25519_pk_to_curve25519( return x25519_pk; } -(function() { +(function () { // Initialize PRNG if environment provides CSPRNG. // If not, methods calling randombytes will throw. const crypto = @@ -3086,7 +3083,7 @@ export function sign_ed25519_pk_to_curve25519( if (crypto && crypto.getRandomValues) { // Browsers. var QUOTA = 65536; - setPRNG(function(x: Uint8Array, n: number) { + setPRNG(function (x: Uint8Array, n: number) { var i, v = new Uint8Array(n); for (i = 0; i < n; i += QUOTA) { @@ -3099,7 +3096,7 @@ export function sign_ed25519_pk_to_curve25519( // Node.js. const cr = require("crypto"); if (cr && cr.randomBytes) { - setPRNG(function(x: Uint8Array, n: number) { + setPRNG(function (x: Uint8Array, n: number) { var i, v = cr.randomBytes(n); for (i = 0; i < n; i++) x[i] = v[i]; diff --git a/src/crypto/primitives/sha256.ts b/src/crypto/primitives/sha256.ts index f4f6690c7..c0f245bb3 100644 --- a/src/crypto/primitives/sha256.ts +++ b/src/crypto/primitives/sha256.ts @@ -339,10 +339,7 @@ export class HMAC { constructor(key: Uint8Array) { const pad = new Uint8Array(this.blockSize); if (key.length > this.blockSize) { - new HashSha256() - .update(key) - .finish(pad) - .clean(); + new HashSha256().update(key).finish(pad).clean(); } else { for (let i = 0; i < key.length; i++) { pad[i] = key[i]; diff --git a/src/crypto/talerCrypto-test.ts b/src/crypto/talerCrypto-test.ts index 59949dbd3..85c22d608 100644 --- a/src/crypto/talerCrypto-test.ts +++ b/src/crypto/talerCrypto-test.ts @@ -47,7 +47,7 @@ function bytesToHex(bytes: Uint8Array): string { return hex.join(""); } -test("encoding", t => { +test("encoding", (t) => { const utf8decoder = new TextDecoder("utf-8"); const utf8encoder = new TextEncoder(); const s = "Hello, World"; @@ -57,7 +57,7 @@ test("encoding", t => { t.deepEqual(s, sOut); }); -test("taler-exchange-tvg hash code", t => { +test("taler-exchange-tvg hash code", (t) => { const input = "91JPRV3F5GG4EKJN41A62V35E8"; const output = "CW96WR74JS8T53EC8GKSGD49QKH4ZNFTZXDAWMMV5GJ1E4BM6B8GPN5NVHDJ8ZVXNCW7Q4WBYCV61HCA3PZC2YJD850DT29RHHN7ESR"; @@ -67,7 +67,7 @@ test("taler-exchange-tvg hash code", t => { t.deepEqual(myOutput, output); }); -test("taler-exchange-tvg ecdhe key", t => { +test("taler-exchange-tvg ecdhe key", (t) => { const priv1 = "X4T4N0M8PVQXQEBW2BA7049KFSM7J437NSDFC6GDNM3N5J9367A0"; const pub1 = "M997P494MS6A95G1P0QYWW2VNPSHSX5Q6JBY5B9YMNYWP0B50X3G"; const priv2 = "14A0MMQ64DCV8HE0CS3WBC9DHFJAHXRGV7NEARFJPC5R5E1697E0"; @@ -83,7 +83,7 @@ test("taler-exchange-tvg ecdhe key", t => { t.deepEqual(encodeCrock(mySkm), skm); }); -test("taler-exchange-tvg eddsa key", t => { +test("taler-exchange-tvg eddsa key", (t) => { const priv = "9TM70AKDTS57AWY9JK2J4TMBTMW6K62WHHGZWYDG0VM5ABPZKD40"; const pub = "8GSJZ649T2PXMKZC01Y4ANNBE7MF14QVK9SQEC4E46ZHKCVG8AS0"; @@ -91,7 +91,7 @@ test("taler-exchange-tvg eddsa key", t => { t.deepEqual(encodeCrock(pair.publicKey), pub); }); -test("taler-exchange-tvg kdf", t => { +test("taler-exchange-tvg kdf", (t) => { const salt = "94KPT83PCNS7J83KC5P78Y8"; const ikm = "94KPT83MD1JJ0WV5CDS6AX10D5Q70XBM41NPAY90DNGQ8SBJD5GPR"; const ctx = @@ -110,7 +110,7 @@ test("taler-exchange-tvg kdf", t => { t.deepEqual(encodeCrock(myOut), out); }); -test("taler-exchange-tvg eddsa_ecdh", t => { +test("taler-exchange-tvg eddsa_ecdh", (t) => { const priv_ecdhe = "4AFZWMSGTVCHZPQ0R81NWXDCK4N58G7SDBBE5KXE080Y50370JJG"; const pub_ecdhe = "FXFN5GPAFTKVPWJDPVXQ87167S8T82T5ZV8CDYC0NH2AE14X0M30"; const priv_eddsa = "1KG54M8T3X8BSFSZXCR3SQBSR7Y9P53NX61M864S7TEVMJ2XVPF0"; @@ -137,7 +137,7 @@ test("taler-exchange-tvg eddsa_ecdh", t => { t.deepEqual(encodeCrock(myKm2), key_material); }); -test("taler-exchange-tvg blind signing", t => { +test("taler-exchange-tvg blind signing", (t) => { const messageHash = "TT1R28D79EJEJ9PC35AQS35CCG85DSXSZ508MV2HS2FN4ME6AHESZX5WP485R8A75KG53FN6F1YNW95008663TKAPWB81420VG17BY8"; const rsaPublicKey = @@ -149,18 +149,29 @@ test("taler-exchange-tvg blind signing", t => { "5VW0MS5PRBA3W8TPATSTDA2YRFQM1Z7F2DWKQ8ATMZYYY768Q3STZ3HGNVYQ6JB5NKP80G5HGE58616FPA70SX9PTW7EN8EJ23E26FASBWZBP8E2RWQQ5E0F72B2PWRP5ZCA2J3AB3F6P86XK4PZYT64RF94MDGHY0GSDSSBH5YSFB3VM0KVXA52H2Y2G9S85AVCSD3BTMHQRF5BJJ8JE00T4GK70PSTVCGMRKRNA7DGW7GD2F35W55AXF7R2YJC8PAGNSJYWKC3PC75A5N8H69K299AK5PM3CDDHNS4BMRNGF7K49CR4ZBFRXDAWMB3X6T05Q4NKSG0F1KP5JA0XBMF2YJK7KEPRD1EWCHJE44T9YXBTK4W9CV77X7Z9P407ZC6YB3M2ARANZXHJKSM3XC33M"; const sig = "PFT6WQJGCM9DE6264DJS6RMG4XDMCDBJKZGSXAF3BEXWZ979Q13NETKK05S1YV91CX3Y034FSS86SSHZTTE8097RRESQP52EKFGTWJXKHZJEQJ49YHMBNQDHW4CFBJECNJSV2PMHWVGXV7HB84R6P0S3ES559HWQX01Q9MYDEGRNHKW87QR2BNSG951D5NQGAKEJ2SSJBE18S6WYAC24FAP8TT8ANECH5371J0DJY0YR0VWAFWVJDV8XQSFXWMJ80N3A80SPSHPYJY3WZZXW63WQ46WHYY56ZSNE5G1RZ5CR0XYV2ECKPM8R0FS58EV16WTRAM1ABBFVNAT3CAEFAZCWP3XHPVBQY5NZVTD5QS2Q8SKJQ2XB30E11CWDN9KTV5CBK4DN72EVG73F3W3BATAKHG"; - - const myBm = rsaBlind(decodeCrock(messageHash), decodeCrock(bks), decodeCrock(rsaPublicKey)); + + const myBm = rsaBlind( + decodeCrock(messageHash), + decodeCrock(bks), + decodeCrock(rsaPublicKey), + ); t.deepEqual(encodeCrock(myBm), bm); - const mySig = rsaUnblind(decodeCrock(bs), decodeCrock(rsaPublicKey), decodeCrock(bks)); + const mySig = rsaUnblind( + decodeCrock(bs), + decodeCrock(rsaPublicKey), + decodeCrock(bks), + ); t.deepEqual(encodeCrock(mySig), sig); - const v = rsaVerify(decodeCrock(messageHash), decodeCrock(sig), decodeCrock(rsaPublicKey)); + const v = rsaVerify( + decodeCrock(messageHash), + decodeCrock(sig), + decodeCrock(rsaPublicKey), + ); t.true(v); }); - test("incremental hashing #1", (t) => { const n = 1024; const d = nacl.randomBytes(n); @@ -198,4 +209,4 @@ test("incremental hashing #2", (t) => { t.deepEqual(encodeCrock(h1), encodeCrock(h3)); t.deepEqual(encodeCrock(h1), encodeCrock(h2)); -});
\ No newline at end of file +}); diff --git a/src/crypto/workers/cryptoApi.ts b/src/crypto/workers/cryptoApi.ts index 0b7c2e233..ab97e1274 100644 --- a/src/crypto/workers/cryptoApi.ts +++ b/src/crypto/workers/cryptoApi.ts @@ -281,8 +281,9 @@ export class CryptoApi { CryptoApi.enableTracing && console.log( - `rpc ${currentWorkItem.operation} took ${timer.performanceNow() - - currentWorkItem.startTime}ms`, + `rpc ${currentWorkItem.operation} took ${ + timer.performanceNow() - currentWorkItem.startTime + }ms`, ); currentWorkItem.resolve(msg.data.result); } diff --git a/src/crypto/workers/cryptoImplementation.ts b/src/crypto/workers/cryptoImplementation.ts index 55caecb43..156c72ba0 100644 --- a/src/crypto/workers/cryptoImplementation.ts +++ b/src/crypto/workers/cryptoImplementation.ts @@ -313,9 +313,7 @@ export class CryptoImplementation { stringToBytes(paytoUri + "\0"), new Uint8Array(0), ); - const p = buildSigPS(SignaturePurpose.MASTER_WIRE_DETAILS) - .put(h) - .build(); + const p = buildSigPS(SignaturePurpose.MASTER_WIRE_DETAILS).put(h).build(); return eddsaVerify(p, decodeCrock(sig), decodeCrock(masterPub)); } @@ -467,8 +465,8 @@ export class CryptoImplementation { exchangeBaseUrl, hash: encodeCrock(sessionHash), meltCoinPub: meltCoin.coinPub, - newDenomHashes: newCoinDenoms.map(d => d.denomPubHash), - newDenoms: newCoinDenoms.map(d => d.denomPub), + newDenomHashes: newCoinDenoms.map((d) => d.denomPubHash), + newDenoms: newCoinDenoms.map((d) => d.denomPub), norevealIndex: undefined, planchetsForGammas: planchetsForGammas, transferPrivs, diff --git a/src/crypto/workers/cryptoWorker.ts b/src/crypto/workers/cryptoWorker.ts index d4449f4a2..9f3ee6f50 100644 --- a/src/crypto/workers/cryptoWorker.ts +++ b/src/crypto/workers/cryptoWorker.ts @@ -5,4 +5,4 @@ export interface CryptoWorker { onmessage: ((m: any) => void) | undefined; onerror: ((m: any) => void) | undefined; -}
\ No newline at end of file +} diff --git a/src/crypto/workers/nodeThreadWorker.ts b/src/crypto/workers/nodeThreadWorker.ts index e40f3c950..1247900f9 100644 --- a/src/crypto/workers/nodeThreadWorker.ts +++ b/src/crypto/workers/nodeThreadWorker.ts @@ -96,7 +96,7 @@ export function handleWorkerMessage(msg: any) { } }; - handleRequest().catch(e => { + handleRequest().catch((e) => { console.error("error in node worker", e); }); } diff --git a/src/crypto/workers/synchronousWorker.ts b/src/crypto/workers/synchronousWorker.ts index 12eecde9a..b453468d5 100644 --- a/src/crypto/workers/synchronousWorker.ts +++ b/src/crypto/workers/synchronousWorker.ts @@ -37,12 +37,10 @@ export class SynchronousCryptoWorkerFactory implements CryptoWorkerFactory { } } - /** * Worker implementation that uses node subprocesses. */ export class SynchronousCryptoWorker { - /** * Function to be called when we receive a message from the worker thread. */ @@ -121,7 +119,7 @@ export class SynchronousCryptoWorker { return; } - this.handleRequest(operation, id, args).catch(e => { + this.handleRequest(operation, id, args).catch((e) => { console.error("Error while handling crypto request:", e); }); } diff --git a/src/headless/NodeHttpLib.ts b/src/headless/NodeHttpLib.ts index 5cbb40ccf..735d6b3cf 100644 --- a/src/headless/NodeHttpLib.ts +++ b/src/headless/NodeHttpLib.ts @@ -16,7 +16,12 @@ SPDX-License-Identifier: AGPL3.0-or-later */ -import { Headers, HttpRequestLibrary, HttpRequestOptions, HttpResponse } from "../util/http"; +import { + Headers, + HttpRequestLibrary, + HttpRequestOptions, + HttpResponse, +} from "../util/http"; import { RequestThrottler } from "../util/RequestThrottler"; import Axios, { AxiosResponse } from "axios"; @@ -85,10 +90,7 @@ export class NodeHttpLib implements HttpRequestLibrary { }; } - async get( - url: string, - opt?: HttpRequestOptions, - ): Promise<HttpResponse> { + async get(url: string, opt?: HttpRequestOptions): Promise<HttpResponse> { return this.req("get", url, undefined, opt); } @@ -99,4 +101,4 @@ export class NodeHttpLib implements HttpRequestLibrary { ): Promise<HttpResponse> { return this.req("post", url, body, opt); } -}
\ No newline at end of file +} diff --git a/src/headless/clk.ts b/src/headless/clk.ts index ab6526f9c..7d7417ea9 100644 --- a/src/headless/clk.ts +++ b/src/headless/clk.ts @@ -340,7 +340,9 @@ export class CommandGroup<GN extends keyof any, TG> { const r = splitOpt(opt); const d = this.longOptions[r.key]; if (!d) { - console.error(`error: unknown option '--${r.key}' for ${currentName}`); + console.error( + `error: unknown option '--${r.key}' for ${currentName}`, + ); process.exit(-1); throw Error("not reached"); } @@ -359,7 +361,7 @@ export class CommandGroup<GN extends keyof any, TG> { process.exit(-1); throw Error("not reached"); } - myArgs[d.name] = unparsedArgs[i+1]; + myArgs[d.name] = unparsedArgs[i + 1]; i++; } else { myArgs[d.name] = r.value; @@ -427,14 +429,15 @@ export class CommandGroup<GN extends keyof any, TG> { throw Error("not reached"); } - for (let i = posArgIndex; i < this.arguments.length; i++) { const d = this.arguments[i]; if (d.required) { if (d.args.default !== undefined) { myArgs[d.name] = d.args.default; } else { - console.error(`error: missing positional argument '${d.name}' for ${currentName}`); + console.error( + `error: missing positional argument '${d.name}' for ${currentName}`, + ); process.exit(-1); throw Error("not reached"); } @@ -447,7 +450,7 @@ export class CommandGroup<GN extends keyof any, TG> { if (option.args.default !== undefined) { myArgs[option.name] = option.args.default; } else { - const name = option.flagspec.join(",") + const name = option.flagspec.join(","); console.error(`error: missing option '${name}'`); process.exit(-1); throw Error("not reached"); @@ -584,10 +587,11 @@ export class Program<PN extends keyof any, T> { } } -export type GetArgType<T> = - T extends Program<any, infer AT> ? AT : - T extends CommandGroup<any, infer AT> ? AT : - any; +export type GetArgType<T> = T extends Program<any, infer AT> + ? AT + : T extends CommandGroup<any, infer AT> + ? AT + : any; export function program<PN extends keyof any>( argKey: PN, @@ -596,15 +600,13 @@ export function program<PN extends keyof any>( return new Program(argKey as string, args); } - - export function prompt(question: string): Promise<string> { const stdinReadline = readline.createInterface({ input: process.stdin, output: process.stdout, }); return new Promise<string>((resolve, reject) => { - stdinReadline.question(question, res => { + stdinReadline.question(question, (res) => { resolve(res); stdinReadline.close(); }); diff --git a/src/headless/helpers.ts b/src/headless/helpers.ts index dc56a9876..fb3d800d4 100644 --- a/src/headless/helpers.ts +++ b/src/headless/helpers.ts @@ -120,7 +120,9 @@ export async function getDefaultNodeWallet( require("worker_threads"); workerFactory = new NodeThreadCryptoWorkerFactory(); } catch (e) { - console.log("worker threads not available, falling back to synchronous workers"); + console.log( + "worker threads not available, falling back to synchronous workers", + ); workerFactory = new SynchronousCryptoWorkerFactory(); } @@ -161,7 +163,7 @@ export async function withdrawTestBalance( myWallet.runRetryLoop().catch((x) => { reject(x); }); - myWallet.addNotificationListener(n => { + myWallet.addNotificationListener((n) => { if ( n.type === NotificationType.ReserveDepleted && n.reservePub === reservePub diff --git a/src/headless/integrationtest.ts b/src/headless/integrationtest.ts index 0c015207e..191e48ff6 100644 --- a/src/headless/integrationtest.ts +++ b/src/headless/integrationtest.ts @@ -99,7 +99,7 @@ export async function runIntegrationTest(args: IntegrationTestArgs) { const myWallet = await getDefaultNodeWallet({ httpLib: myHttpLib }); - myWallet.runRetryLoop().catch(e => { + myWallet.runRetryLoop().catch((e) => { console.error("exception during retry loop:", e); }); @@ -233,7 +233,7 @@ export async function runIntegrationTestBasic(cfg: Configuration) { persistentStoragePath: walletDbPath, }); - myWallet.runRetryLoop().catch(e => { + myWallet.runRetryLoop().catch((e) => { console.error("exception during retry loop:", e); }); @@ -255,7 +255,12 @@ export async function runIntegrationTestBasic(cfg: Configuration) { merchantApiKey, ); - await makePayment(myWallet, myMerchant, Amounts.toString(parsedSpendAmount), "hello world"); + await makePayment( + myWallet, + myMerchant, + Amounts.toString(parsedSpendAmount), + "hello world", + ); // Wait until the refresh is done await myWallet.runUntilDone(); diff --git a/src/headless/merchant.ts b/src/headless/merchant.ts index b30e00d8a..27e7e3f21 100644 --- a/src/headless/merchant.ts +++ b/src/headless/merchant.ts @@ -23,7 +23,10 @@ * Imports. */ import axios from "axios"; -import { CheckPaymentResponse, codecForCheckPaymentResponse } from "../types/talerTypes"; +import { + CheckPaymentResponse, + codecForCheckPaymentResponse, +} from "../types/talerTypes"; /** * Connection to the *internal* merchant backend. @@ -133,7 +136,7 @@ export class MerchantBackendConnection { if (resp.status != 200) { throw Error("failed to check payment"); } - + return codecForCheckPaymentResponse().decode(resp.data); } } diff --git a/src/i18n/strings.ts b/src/i18n/strings.ts index e77fc71a1..289dcbedc 100644 --- a/src/i18n/strings.ts +++ b/src/i18n/strings.ts @@ -14,1144 +14,391 @@ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ -export let strings: {[s: string]: any} = {}; -strings['de'] = { - "domain": "messages", - "locale_data": { - "messages": { +export let strings: { [s: string]: any } = {}; +strings["de"] = { + domain: "messages", + locale_data: { + messages: { "": { - "domain": "messages", - "plural_forms": "nplurals=2; plural=(n != 1);", - "lang": "" + domain: "messages", + plural_forms: "nplurals=2; plural=(n != 1);", + lang: "", }, - "Invalid Wire": [ - null, - "" - ], - "Invalid Test Wire Detail": [ - null, - "" - ], - "Test Wire Acct #%1$s on %2$s": [ - null, - "" - ], - "Unknown Wire Detail": [ - null, - "" - ], - "Operation": [ - null, - "" - ], - "time (ms/op)": [ - null, - "" - ], + "Invalid Wire": [null, ""], + "Invalid Test Wire Detail": [null, ""], + "Test Wire Acct #%1$s on %2$s": [null, ""], + "Unknown Wire Detail": [null, ""], + Operation: [null, ""], + "time (ms/op)": [null, ""], "The merchant %1$s offers you to purchase:": [ null, - "Der Händler %1$s möchte einen Vertrag über %2$s mit Ihnen abschließen." - ], - "The total price is %1$s (plus %2$s fees).": [ - null, - "" - ], - "The total price is %1$s.": [ - null, - "" - ], - "Retry": [ - null, - "" - ], - "Confirm payment": [ - null, - "Bezahlung bestätigen" - ], - "Balance": [ - null, - "Saldo" - ], - "History": [ - null, - "Verlauf" - ], - "Debug": [ - null, - "Debug" + "Der Händler %1$s möchte einen Vertrag über %2$s mit Ihnen abschließen.", ], + "The total price is %1$s (plus %2$s fees).": [null, ""], + "The total price is %1$s.": [null, ""], + Retry: [null, ""], + "Confirm payment": [null, "Bezahlung bestätigen"], + Balance: [null, "Saldo"], + History: [null, "Verlauf"], + Debug: [null, "Debug"], "You have no balance to show. Need some %1$s getting started?": [ null, - "Sie haben kein Digitalgeld. Wollen Sie %1$s? abheben?" - ], - "%1$s incoming": [ - null, - "" - ], - "%1$s being spent": [ - null, - "" - ], - "Error: could not retrieve balance information.": [ - null, - "" - ], - "Invalid ": [ - null, - "" - ], - "Fees ": [ - null, - "" - ], - "Refresh sessions has completed": [ - null, - "" - ], - "Order Refused": [ - null, - "" - ], - "Order redirected": [ - null, - "" - ], - "Payment aborted": [ - null, - "" - ], - "Payment Sent": [ - null, - "" - ], - "Order accepted": [ - null, - "" - ], - "Reserve balance updated": [ - null, - "" - ], - "Payment refund": [ - null, - "" - ], - "Withdrawn": [ - null, - "Abheben bei %1$s" - ], - "Tip Accepted": [ - null, - "" - ], - "Tip Declined": [ - null, - "" - ], - "%1$s": [ - null, - "" - ], - "Error: could not retrieve event history": [ - null, - "" - ], + "Sie haben kein Digitalgeld. Wollen Sie %1$s? abheben?", + ], + "%1$s incoming": [null, ""], + "%1$s being spent": [null, ""], + "Error: could not retrieve balance information.": [null, ""], + "Invalid ": [null, ""], + "Fees ": [null, ""], + "Refresh sessions has completed": [null, ""], + "Order Refused": [null, ""], + "Order redirected": [null, ""], + "Payment aborted": [null, ""], + "Payment Sent": [null, ""], + "Order accepted": [null, ""], + "Reserve balance updated": [null, ""], + "Payment refund": [null, ""], + Withdrawn: [null, "Abheben bei %1$s"], + "Tip Accepted": [null, ""], + "Tip Declined": [null, ""], + "%1$s": [null, ""], + "Error: could not retrieve event history": [null, ""], "Your wallet has no events recorded.": [ null, - "Ihre Geldbörse verzeichnet keine Vorkommnisse." - ], - "Wire to bank account": [ - null, - "" - ], - "Confirm": [ - null, - "Bezahlung bestätigen" - ], - "Cancel": [ - null, - "Saldo" - ], - "Fatal error: \"%1$s\".": [ - null, - "" - ], - "Could not get details for withdraw operation:": [ - null, - "" - ], - "Chose different exchange provider": [ - null, - "" + "Ihre Geldbörse verzeichnet keine Vorkommnisse.", ], + "Wire to bank account": [null, ""], + Confirm: [null, "Bezahlung bestätigen"], + Cancel: [null, "Saldo"], + 'Fatal error: "%1$s".': [null, ""], + "Could not get details for withdraw operation:": [null, ""], + "Chose different exchange provider": [null, ""], "Please select an exchange. You can review the details before after your selection.": [ null, - "" - ], - "Select %1$s": [ - null, - "" - ], - "Select custom exchange": [ - null, - "" + "", ], + "Select %1$s": [null, ""], + "Select custom exchange": [null, ""], "You are about to withdraw %1$s from your bank account into your wallet.": [ null, - "" - ], - "Accept fees and withdraw": [ - null, - "" - ], - "Cancel withdraw operation": [ - null, - "" - ], - "Withdrawal fees:": [ - null, - "Abheben bei" - ], - "Rounding loss:": [ - null, - "" - ], - "Earliest expiration (for deposit): %1$s": [ - null, - "" - ], - "# Coins": [ - null, - "" - ], - "Value": [ - null, - "" - ], - "Withdraw Fee": [ - null, - "Abheben bei %1$s" - ], - "Refresh Fee": [ - null, - "" - ], - "Deposit Fee": [ - null, - "" - ] - } - } + "", + ], + "Accept fees and withdraw": [null, ""], + "Cancel withdraw operation": [null, ""], + "Withdrawal fees:": [null, "Abheben bei"], + "Rounding loss:": [null, ""], + "Earliest expiration (for deposit): %1$s": [null, ""], + "# Coins": [null, ""], + Value: [null, ""], + "Withdraw Fee": [null, "Abheben bei %1$s"], + "Refresh Fee": [null, ""], + "Deposit Fee": [null, ""], + }, + }, }; -strings['en-US'] = { - "domain": "messages", - "locale_data": { - "messages": { +strings["en-US"] = { + domain: "messages", + locale_data: { + messages: { "": { - "domain": "messages", - "plural_forms": "nplurals=2; plural=(n != 1);", - "lang": "" + domain: "messages", + plural_forms: "nplurals=2; plural=(n != 1);", + lang: "", }, - "Invalid Wire": [ - null, - "" - ], - "Invalid Test Wire Detail": [ - null, - "" - ], - "Test Wire Acct #%1$s on %2$s": [ - null, - "" - ], - "Unknown Wire Detail": [ - null, - "" - ], - "Operation": [ - null, - "" - ], - "time (ms/op)": [ - null, - "" - ], - "The merchant %1$s offers you to purchase:": [ - null, - "" - ], - "The total price is %1$s (plus %2$s fees).": [ - null, - "" - ], - "The total price is %1$s.": [ - null, - "" - ], - "Retry": [ - null, - "" - ], - "Confirm payment": [ - null, - "" - ], - "Balance": [ - null, - "" - ], - "History": [ - null, - "" - ], - "Debug": [ - null, - "" - ], + "Invalid Wire": [null, ""], + "Invalid Test Wire Detail": [null, ""], + "Test Wire Acct #%1$s on %2$s": [null, ""], + "Unknown Wire Detail": [null, ""], + Operation: [null, ""], + "time (ms/op)": [null, ""], + "The merchant %1$s offers you to purchase:": [null, ""], + "The total price is %1$s (plus %2$s fees).": [null, ""], + "The total price is %1$s.": [null, ""], + Retry: [null, ""], + "Confirm payment": [null, ""], + Balance: [null, ""], + History: [null, ""], + Debug: [null, ""], "You have no balance to show. Need some %1$s getting started?": [ null, - "" - ], - "%1$s incoming": [ - null, - "" - ], - "%1$s being spent": [ - null, - "" - ], - "Error: could not retrieve balance information.": [ - null, - "" - ], - "Invalid ": [ - null, - "" - ], - "Fees ": [ - null, - "" - ], - "Refresh sessions has completed": [ - null, - "" - ], - "Order Refused": [ - null, - "" - ], - "Order redirected": [ - null, - "" - ], - "Payment aborted": [ - null, - "" - ], - "Payment Sent": [ - null, - "" - ], - "Order accepted": [ - null, - "" - ], - "Reserve balance updated": [ - null, - "" - ], - "Payment refund": [ - null, - "" - ], - "Withdrawn": [ - null, - "" - ], - "Tip Accepted": [ - null, - "" - ], - "Tip Declined": [ - null, - "" - ], - "%1$s": [ - null, - "" - ], - "Error: could not retrieve event history": [ - null, - "" - ], - "Your wallet has no events recorded.": [ - null, - "" - ], - "Wire to bank account": [ - null, - "" - ], - "Confirm": [ - null, - "" - ], - "Cancel": [ - null, - "" - ], - "Fatal error: \"%1$s\".": [ - null, - "" - ], - "Could not get details for withdraw operation:": [ - null, - "" - ], - "Chose different exchange provider": [ - null, - "" - ], + "", + ], + "%1$s incoming": [null, ""], + "%1$s being spent": [null, ""], + "Error: could not retrieve balance information.": [null, ""], + "Invalid ": [null, ""], + "Fees ": [null, ""], + "Refresh sessions has completed": [null, ""], + "Order Refused": [null, ""], + "Order redirected": [null, ""], + "Payment aborted": [null, ""], + "Payment Sent": [null, ""], + "Order accepted": [null, ""], + "Reserve balance updated": [null, ""], + "Payment refund": [null, ""], + Withdrawn: [null, ""], + "Tip Accepted": [null, ""], + "Tip Declined": [null, ""], + "%1$s": [null, ""], + "Error: could not retrieve event history": [null, ""], + "Your wallet has no events recorded.": [null, ""], + "Wire to bank account": [null, ""], + Confirm: [null, ""], + Cancel: [null, ""], + 'Fatal error: "%1$s".': [null, ""], + "Could not get details for withdraw operation:": [null, ""], + "Chose different exchange provider": [null, ""], "Please select an exchange. You can review the details before after your selection.": [ null, - "" - ], - "Select %1$s": [ - null, - "" - ], - "Select custom exchange": [ - null, - "" + "", ], + "Select %1$s": [null, ""], + "Select custom exchange": [null, ""], "You are about to withdraw %1$s from your bank account into your wallet.": [ null, - "" - ], - "Accept fees and withdraw": [ - null, - "" - ], - "Cancel withdraw operation": [ - null, - "" - ], - "Withdrawal fees:": [ - null, - "" - ], - "Rounding loss:": [ - null, - "" - ], - "Earliest expiration (for deposit): %1$s": [ - null, - "" - ], - "# Coins": [ - null, - "" - ], - "Value": [ - null, - "" - ], - "Withdraw Fee": [ - null, - "" - ], - "Refresh Fee": [ - null, - "" - ], - "Deposit Fee": [ - null, - "" - ] - } - } + "", + ], + "Accept fees and withdraw": [null, ""], + "Cancel withdraw operation": [null, ""], + "Withdrawal fees:": [null, ""], + "Rounding loss:": [null, ""], + "Earliest expiration (for deposit): %1$s": [null, ""], + "# Coins": [null, ""], + Value: [null, ""], + "Withdraw Fee": [null, ""], + "Refresh Fee": [null, ""], + "Deposit Fee": [null, ""], + }, + }, }; -strings['fr'] = { - "domain": "messages", - "locale_data": { - "messages": { +strings["fr"] = { + domain: "messages", + locale_data: { + messages: { "": { - "domain": "messages", - "plural_forms": "nplurals=2; plural=(n != 1);", - "lang": "" + domain: "messages", + plural_forms: "nplurals=2; plural=(n != 1);", + lang: "", }, - "Invalid Wire": [ - null, - "" - ], - "Invalid Test Wire Detail": [ - null, - "" - ], - "Test Wire Acct #%1$s on %2$s": [ - null, - "" - ], - "Unknown Wire Detail": [ - null, - "" - ], - "Operation": [ - null, - "" - ], - "time (ms/op)": [ - null, - "" - ], - "The merchant %1$s offers you to purchase:": [ - null, - "" - ], - "The total price is %1$s (plus %2$s fees).": [ - null, - "" - ], - "The total price is %1$s.": [ - null, - "" - ], - "Retry": [ - null, - "" - ], - "Confirm payment": [ - null, - "" - ], - "Balance": [ - null, - "" - ], - "History": [ - null, - "" - ], - "Debug": [ - null, - "" - ], + "Invalid Wire": [null, ""], + "Invalid Test Wire Detail": [null, ""], + "Test Wire Acct #%1$s on %2$s": [null, ""], + "Unknown Wire Detail": [null, ""], + Operation: [null, ""], + "time (ms/op)": [null, ""], + "The merchant %1$s offers you to purchase:": [null, ""], + "The total price is %1$s (plus %2$s fees).": [null, ""], + "The total price is %1$s.": [null, ""], + Retry: [null, ""], + "Confirm payment": [null, ""], + Balance: [null, ""], + History: [null, ""], + Debug: [null, ""], "You have no balance to show. Need some %1$s getting started?": [ null, - "" - ], - "%1$s incoming": [ - null, - "" - ], - "%1$s being spent": [ - null, - "" - ], - "Error: could not retrieve balance information.": [ - null, - "" - ], - "Invalid ": [ - null, - "" - ], - "Fees ": [ - null, - "" - ], - "Refresh sessions has completed": [ - null, - "" - ], - "Order Refused": [ - null, - "" - ], - "Order redirected": [ - null, - "" - ], - "Payment aborted": [ - null, - "" - ], - "Payment Sent": [ - null, - "" - ], - "Order accepted": [ - null, - "" - ], - "Reserve balance updated": [ - null, - "" - ], - "Payment refund": [ - null, - "" - ], - "Withdrawn": [ - null, - "" - ], - "Tip Accepted": [ - null, - "" - ], - "Tip Declined": [ - null, - "" - ], - "%1$s": [ - null, - "" - ], - "Error: could not retrieve event history": [ - null, - "" - ], - "Your wallet has no events recorded.": [ - null, - "" - ], - "Wire to bank account": [ - null, - "" - ], - "Confirm": [ - null, - "" - ], - "Cancel": [ - null, - "" - ], - "Fatal error: \"%1$s\".": [ - null, - "" - ], - "Could not get details for withdraw operation:": [ - null, - "" - ], - "Chose different exchange provider": [ - null, - "" - ], + "", + ], + "%1$s incoming": [null, ""], + "%1$s being spent": [null, ""], + "Error: could not retrieve balance information.": [null, ""], + "Invalid ": [null, ""], + "Fees ": [null, ""], + "Refresh sessions has completed": [null, ""], + "Order Refused": [null, ""], + "Order redirected": [null, ""], + "Payment aborted": [null, ""], + "Payment Sent": [null, ""], + "Order accepted": [null, ""], + "Reserve balance updated": [null, ""], + "Payment refund": [null, ""], + Withdrawn: [null, ""], + "Tip Accepted": [null, ""], + "Tip Declined": [null, ""], + "%1$s": [null, ""], + "Error: could not retrieve event history": [null, ""], + "Your wallet has no events recorded.": [null, ""], + "Wire to bank account": [null, ""], + Confirm: [null, ""], + Cancel: [null, ""], + 'Fatal error: "%1$s".': [null, ""], + "Could not get details for withdraw operation:": [null, ""], + "Chose different exchange provider": [null, ""], "Please select an exchange. You can review the details before after your selection.": [ null, - "" - ], - "Select %1$s": [ - null, - "" - ], - "Select custom exchange": [ - null, - "" + "", ], + "Select %1$s": [null, ""], + "Select custom exchange": [null, ""], "You are about to withdraw %1$s from your bank account into your wallet.": [ null, - "" - ], - "Accept fees and withdraw": [ - null, - "" - ], - "Cancel withdraw operation": [ - null, - "" - ], - "Withdrawal fees:": [ - null, - "" - ], - "Rounding loss:": [ - null, - "" - ], - "Earliest expiration (for deposit): %1$s": [ - null, - "" - ], - "# Coins": [ - null, - "" - ], - "Value": [ - null, - "" - ], - "Withdraw Fee": [ - null, - "" - ], - "Refresh Fee": [ - null, - "" - ], - "Deposit Fee": [ - null, - "" - ] - } - } + "", + ], + "Accept fees and withdraw": [null, ""], + "Cancel withdraw operation": [null, ""], + "Withdrawal fees:": [null, ""], + "Rounding loss:": [null, ""], + "Earliest expiration (for deposit): %1$s": [null, ""], + "# Coins": [null, ""], + Value: [null, ""], + "Withdraw Fee": [null, ""], + "Refresh Fee": [null, ""], + "Deposit Fee": [null, ""], + }, + }, }; -strings['it'] = { - "domain": "messages", - "locale_data": { - "messages": { +strings["it"] = { + domain: "messages", + locale_data: { + messages: { "": { - "domain": "messages", - "plural_forms": "nplurals=2; plural=(n != 1);", - "lang": "" + domain: "messages", + plural_forms: "nplurals=2; plural=(n != 1);", + lang: "", }, - "Invalid Wire": [ - null, - "" - ], - "Invalid Test Wire Detail": [ - null, - "" - ], - "Test Wire Acct #%1$s on %2$s": [ - null, - "" - ], - "Unknown Wire Detail": [ - null, - "" - ], - "Operation": [ - null, - "" - ], - "time (ms/op)": [ - null, - "" - ], - "The merchant %1$s offers you to purchase:": [ - null, - "" - ], - "The total price is %1$s (plus %2$s fees).": [ - null, - "" - ], - "The total price is %1$s.": [ - null, - "" - ], - "Retry": [ - null, - "" - ], - "Confirm payment": [ - null, - "" - ], - "Balance": [ - null, - "" - ], - "History": [ - null, - "" - ], - "Debug": [ - null, - "" - ], + "Invalid Wire": [null, ""], + "Invalid Test Wire Detail": [null, ""], + "Test Wire Acct #%1$s on %2$s": [null, ""], + "Unknown Wire Detail": [null, ""], + Operation: [null, ""], + "time (ms/op)": [null, ""], + "The merchant %1$s offers you to purchase:": [null, ""], + "The total price is %1$s (plus %2$s fees).": [null, ""], + "The total price is %1$s.": [null, ""], + Retry: [null, ""], + "Confirm payment": [null, ""], + Balance: [null, ""], + History: [null, ""], + Debug: [null, ""], "You have no balance to show. Need some %1$s getting started?": [ null, - "" - ], - "%1$s incoming": [ - null, - "" - ], - "%1$s being spent": [ - null, - "" - ], - "Error: could not retrieve balance information.": [ - null, - "" - ], - "Invalid ": [ - null, - "" - ], - "Fees ": [ - null, - "" - ], - "Refresh sessions has completed": [ - null, - "" - ], - "Order Refused": [ - null, - "" - ], - "Order redirected": [ - null, - "" - ], - "Payment aborted": [ - null, - "" - ], - "Payment Sent": [ - null, - "" - ], - "Order accepted": [ - null, - "" - ], - "Reserve balance updated": [ - null, - "" - ], - "Payment refund": [ - null, - "" - ], - "Withdrawn": [ - null, - "" - ], - "Tip Accepted": [ - null, - "" - ], - "Tip Declined": [ - null, - "" - ], - "%1$s": [ - null, - "" - ], - "Error: could not retrieve event history": [ - null, - "" - ], - "Your wallet has no events recorded.": [ - null, - "" - ], - "Wire to bank account": [ - null, - "" - ], - "Confirm": [ - null, - "" - ], - "Cancel": [ - null, - "" - ], - "Fatal error: \"%1$s\".": [ - null, - "" - ], - "Could not get details for withdraw operation:": [ - null, - "" - ], - "Chose different exchange provider": [ - null, - "" - ], + "", + ], + "%1$s incoming": [null, ""], + "%1$s being spent": [null, ""], + "Error: could not retrieve balance information.": [null, ""], + "Invalid ": [null, ""], + "Fees ": [null, ""], + "Refresh sessions has completed": [null, ""], + "Order Refused": [null, ""], + "Order redirected": [null, ""], + "Payment aborted": [null, ""], + "Payment Sent": [null, ""], + "Order accepted": [null, ""], + "Reserve balance updated": [null, ""], + "Payment refund": [null, ""], + Withdrawn: [null, ""], + "Tip Accepted": [null, ""], + "Tip Declined": [null, ""], + "%1$s": [null, ""], + "Error: could not retrieve event history": [null, ""], + "Your wallet has no events recorded.": [null, ""], + "Wire to bank account": [null, ""], + Confirm: [null, ""], + Cancel: [null, ""], + 'Fatal error: "%1$s".': [null, ""], + "Could not get details for withdraw operation:": [null, ""], + "Chose different exchange provider": [null, ""], "Please select an exchange. You can review the details before after your selection.": [ null, - "" - ], - "Select %1$s": [ - null, - "" - ], - "Select custom exchange": [ - null, - "" + "", ], + "Select %1$s": [null, ""], + "Select custom exchange": [null, ""], "You are about to withdraw %1$s from your bank account into your wallet.": [ null, - "" - ], - "Accept fees and withdraw": [ - null, - "" - ], - "Cancel withdraw operation": [ - null, - "" - ], - "Withdrawal fees:": [ - null, - "" - ], - "Rounding loss:": [ - null, - "" - ], - "Earliest expiration (for deposit): %1$s": [ - null, - "" - ], - "# Coins": [ - null, - "" - ], - "Value": [ - null, - "" - ], - "Withdraw Fee": [ - null, - "" - ], - "Refresh Fee": [ - null, - "" - ], - "Deposit Fee": [ - null, - "" - ] - } - } + "", + ], + "Accept fees and withdraw": [null, ""], + "Cancel withdraw operation": [null, ""], + "Withdrawal fees:": [null, ""], + "Rounding loss:": [null, ""], + "Earliest expiration (for deposit): %1$s": [null, ""], + "# Coins": [null, ""], + Value: [null, ""], + "Withdraw Fee": [null, ""], + "Refresh Fee": [null, ""], + "Deposit Fee": [null, ""], + }, + }, }; -strings['sv'] = { - "domain": "messages", - "locale_data": { - "messages": { +strings["sv"] = { + domain: "messages", + locale_data: { + messages: { "": { - "domain": "messages", - "plural_forms": "nplurals=2; plural=(n != 1);", - "lang": "" + domain: "messages", + plural_forms: "nplurals=2; plural=(n != 1);", + lang: "", }, - "Invalid Wire": [ - null, - "" - ], - "Invalid Test Wire Detail": [ - null, - "" - ], - "Test Wire Acct #%1$s on %2$s": [ - null, - "" - ], - "Unknown Wire Detail": [ - null, - "visa mer" - ], - "Operation": [ - null, - "" - ], - "time (ms/op)": [ - null, - "" - ], + "Invalid Wire": [null, ""], + "Invalid Test Wire Detail": [null, ""], + "Test Wire Acct #%1$s on %2$s": [null, ""], + "Unknown Wire Detail": [null, "visa mer"], + Operation: [null, ""], + "time (ms/op)": [null, ""], "The merchant %1$s offers you to purchase:": [ null, - "Säljaren %1$s erbjuder följande:" + "Säljaren %1$s erbjuder följande:", ], "The total price is %1$s (plus %2$s fees).": [ null, - "Det totala priset är %1$s (plus %2$s avgifter).\n" - ], - "The total price is %1$s.": [ - null, - "Det totala priset är %1$s." - ], - "Retry": [ - null, - "" - ], - "Confirm payment": [ - null, - "Godkän betalning" - ], - "Balance": [ - null, - "Balans" - ], - "History": [ - null, - "Historia" - ], - "Debug": [ - null, - "" + "Det totala priset är %1$s (plus %2$s avgifter).\n", ], + "The total price is %1$s.": [null, "Det totala priset är %1$s."], + Retry: [null, ""], + "Confirm payment": [null, "Godkän betalning"], + Balance: [null, "Balans"], + History: [null, "Historia"], + Debug: [null, ""], "You have no balance to show. Need some %1$s getting started?": [ null, - "Du har ingen balans att visa. Behöver du\n %1$s att börja?\n" - ], - "%1$s incoming": [ - null, - "%1$s inkommande" - ], - "%1$s being spent": [ - null, - "" - ], - "Error: could not retrieve balance information.": [ - null, - "" - ], - "Invalid ": [ - null, - "" - ], - "Fees ": [ - null, - "" - ], - "Refresh sessions has completed": [ - null, - "" - ], - "Order Refused": [ - null, - "" - ], - "Order redirected": [ - null, - "" - ], - "Payment aborted": [ - null, - "" - ], - "Payment Sent": [ - null, - "" - ], - "Order accepted": [ - null, - "" - ], - "Reserve balance updated": [ - null, - "" - ], - "Payment refund": [ - null, - "" - ], - "Withdrawn": [ - null, - "Utbetalnings avgift" - ], - "Tip Accepted": [ - null, - "" - ], - "Tip Declined": [ - null, - "" - ], - "%1$s": [ - null, - "" - ], - "Error: could not retrieve event history": [ - null, - "" - ], - "Your wallet has no events recorded.": [ - null, - "plånboken" - ], - "Wire to bank account": [ - null, - "Övervisa till bank konto" - ], - "Confirm": [ - null, - "Bekräfta" - ], - "Cancel": [ - null, - "Avbryt" - ], - "Fatal error: \"%1$s\".": [ - null, - "" - ], - "Could not get details for withdraw operation:": [ - null, - "" - ], - "Chose different exchange provider": [ - null, - "Ändra tjänsteleverantörer" - ], + "Du har ingen balans att visa. Behöver du\n %1$s att börja?\n", + ], + "%1$s incoming": [null, "%1$s inkommande"], + "%1$s being spent": [null, ""], + "Error: could not retrieve balance information.": [null, ""], + "Invalid ": [null, ""], + "Fees ": [null, ""], + "Refresh sessions has completed": [null, ""], + "Order Refused": [null, ""], + "Order redirected": [null, ""], + "Payment aborted": [null, ""], + "Payment Sent": [null, ""], + "Order accepted": [null, ""], + "Reserve balance updated": [null, ""], + "Payment refund": [null, ""], + Withdrawn: [null, "Utbetalnings avgift"], + "Tip Accepted": [null, ""], + "Tip Declined": [null, ""], + "%1$s": [null, ""], + "Error: could not retrieve event history": [null, ""], + "Your wallet has no events recorded.": [null, "plånboken"], + "Wire to bank account": [null, "Övervisa till bank konto"], + Confirm: [null, "Bekräfta"], + Cancel: [null, "Avbryt"], + 'Fatal error: "%1$s".': [null, ""], + "Could not get details for withdraw operation:": [null, ""], + "Chose different exchange provider": [null, "Ändra tjänsteleverantörer"], "Please select an exchange. You can review the details before after your selection.": [ null, - "" - ], - "Select %1$s": [ - null, - "Välj %1$s" - ], - "Select custom exchange": [ - null, - "" + "", ], + "Select %1$s": [null, "Välj %1$s"], + "Select custom exchange": [null, ""], "You are about to withdraw %1$s from your bank account into your wallet.": [ null, - "Du är på väg att ta ut\n %1$s från ditt bankkonto till din plånbok.\n" - ], - "Accept fees and withdraw": [ - null, - "Acceptera avgifter och utbetala" - ], - "Cancel withdraw operation": [ - null, - "" - ], - "Withdrawal fees:": [ - null, - "Utbetalnings avgifter:" - ], - "Rounding loss:": [ - null, - "" - ], - "Earliest expiration (for deposit): %1$s": [ - null, - "" - ], - "# Coins": [ - null, - "# Mynt" - ], - "Value": [ - null, - "Värde" - ], - "Withdraw Fee": [ - null, - "Utbetalnings avgift" - ], - "Refresh Fee": [ - null, - "Återhämtnings avgift" - ], - "Deposit Fee": [ - null, - "Depostitions avgift" - ] - } - } + "Du är på väg att ta ut\n %1$s från ditt bankkonto till din plånbok.\n", + ], + "Accept fees and withdraw": [null, "Acceptera avgifter och utbetala"], + "Cancel withdraw operation": [null, ""], + "Withdrawal fees:": [null, "Utbetalnings avgifter:"], + "Rounding loss:": [null, ""], + "Earliest expiration (for deposit): %1$s": [null, ""], + "# Coins": [null, "# Mynt"], + Value: [null, "Värde"], + "Withdraw Fee": [null, "Utbetalnings avgift"], + "Refresh Fee": [null, "Återhämtnings avgift"], + "Deposit Fee": [null, "Depostitions avgift"], + }, + }, }; diff --git a/src/operations/balance.ts b/src/operations/balance.ts index 03d1b2a9f..8858e8b43 100644 --- a/src/operations/balance.ts +++ b/src/operations/balance.ts @@ -34,8 +34,7 @@ export async function getBalancesInsideTransaction( ws: InternalWalletState, tx: TransactionHandle, ): Promise<WalletBalance> { - - /** + /** * Add amount to a balance field, both for * the slicing by exchange and currency. */ @@ -74,7 +73,7 @@ export async function getBalancesInsideTransaction( byExchange: {}, }; - await tx.iter(Stores.coins).forEach(c => { + await tx.iter(Stores.coins).forEach((c) => { if (c.suspended) { return; } @@ -82,7 +81,7 @@ export async function getBalancesInsideTransaction( addTo(balanceStore, "available", c.currentAmount, c.exchangeBaseUrl); } }); - await tx.iter(Stores.refreshGroups).forEach(r => { + await tx.iter(Stores.refreshGroups).forEach((r) => { // Don't count finished refreshes, since the refresh already resulted // in coins being added to the wallet. if (r.timestampFinished) { @@ -107,7 +106,7 @@ export async function getBalancesInsideTransaction( } }); - await tx.iter(Stores.withdrawalSession).forEach(wds => { + await tx.iter(Stores.withdrawalSession).forEach((wds) => { let w = wds.totalCoinValue; for (let i = 0; i < wds.planchets.length; i++) { if (wds.withdrawn[i]) { @@ -120,7 +119,7 @@ export async function getBalancesInsideTransaction( addTo(balanceStore, "pendingIncoming", w, wds.exchangeBaseUrl); }); - await tx.iter(Stores.purchases).forEach(t => { + await tx.iter(Stores.purchases).forEach((t) => { if (t.timestampFirstSuccessfulPay) { return; } @@ -145,14 +144,16 @@ export async function getBalances( ): Promise<WalletBalance> { logger.trace("starting to compute balance"); - return await ws.db.runWithReadTransaction([ - Stores.coins, - Stores.refreshGroups, - Stores.reserves, - Stores.purchases, - Stores.withdrawalSession, - ], - async tx => { - return getBalancesInsideTransaction(ws, tx); - }); + return await ws.db.runWithReadTransaction( + [ + Stores.coins, + Stores.refreshGroups, + Stores.reserves, + Stores.purchases, + Stores.withdrawalSession, + ], + async (tx) => { + return getBalancesInsideTransaction(ws, tx); + }, + ); } diff --git a/src/operations/errors.ts b/src/operations/errors.ts index 751a57111..50e68993b 100644 --- a/src/operations/errors.ts +++ b/src/operations/errors.ts @@ -64,7 +64,6 @@ export async function scrutinizeTalerJsonResponse<T>( resp: HttpResponse, codec: Codec<T>, ): Promise<T> { - // FIXME: We should distinguish between different types of error status // to react differently (throttle, report permanent failure) @@ -82,7 +81,7 @@ export async function scrutinizeTalerJsonResponse<T>( details: { httpStatusCode: resp.status, errorResponse: errorJson, - } + }, }); } catch (e) { const m = "could not parse response JSON"; @@ -91,7 +90,7 @@ export async function scrutinizeTalerJsonResponse<T>( message: m, details: { status: resp.status, - } + }, }); } throw exc; @@ -101,13 +100,13 @@ export async function scrutinizeTalerJsonResponse<T>( json = await resp.json(); } catch (e) { const m = "could not parse response JSON"; - throw new OperationFailedError({ - type: "network", - message: m, - details: { - status: resp.status, - } - }); + throw new OperationFailedError({ + type: "network", + message: m, + details: { + status: resp.status, + }, + }); } return codec.decode(json); } @@ -138,7 +137,7 @@ export async function guardOperationException<T>( type: "exception", message: e.message, details: {}, - } + }; await onOpError(opErr); throw new OperationFailedAndReportedError(opErr); } diff --git a/src/operations/exchanges.ts b/src/operations/exchanges.ts index f920a5a59..3aaf77468 100644 --- a/src/operations/exchanges.ts +++ b/src/operations/exchanges.ts @@ -193,7 +193,7 @@ async function updateExchangeWithKeys( .currency; const newDenominations = await Promise.all( - exchangeKeysJson.denoms.map(d => + exchangeKeysJson.denoms.map((d) => denominationRecordFromKeys(ws, baseUrl, d), ), ); @@ -202,7 +202,7 @@ async function updateExchangeWithKeys( await ws.db.runWithWriteTransaction( [Stores.exchanges, Stores.denominations, Stores.recoupGroups, Stores.coins], - async tx => { + async (tx) => { const r = await tx.get(Stores.exchanges, baseUrl); if (!r) { console.warn(`exchange ${baseUrl} no longer present`); @@ -275,7 +275,7 @@ async function updateExchangeWithKeys( if (recoupGroupId) { // Asynchronously start recoup. This doesn't need to finish // for the exchange update to be considered finished. - processRecoupGroup(ws, recoupGroupId).catch(e => { + processRecoupGroup(ws, recoupGroupId).catch((e) => { console.log("error while recouping coins:", e); }); } @@ -294,7 +294,7 @@ async function updateExchangeFinalize( } await ws.db.runWithWriteTransaction( [Stores.exchanges, Stores.exchangeUpdatedEvents], - async tx => { + async (tx) => { const r = await tx.get(Stores.exchanges, exchangeBaseUrl); if (!r) { return; @@ -338,7 +338,7 @@ async function updateExchangeWithTermsOfService( const tosText = await resp.text(); const tosEtag = resp.headers.get("etag") || undefined; - await ws.db.runWithWriteTransaction([Stores.exchanges], async tx => { + await ws.db.runWithWriteTransaction([Stores.exchanges], async (tx) => { const r = await tx.get(Stores.exchanges, exchangeBaseUrl); if (!r) { return; @@ -358,7 +358,7 @@ export async function acceptExchangeTermsOfService( exchangeBaseUrl: string, etag: string | undefined, ) { - await ws.db.runWithWriteTransaction([Stores.exchanges], async tx => { + await ws.db.runWithWriteTransaction([Stores.exchanges], async (tx) => { const r = await tx.get(Stores.exchanges, exchangeBaseUrl); if (!r) { return; @@ -438,7 +438,7 @@ async function updateExchangeWithWireInfo( feesForType[wireMethod] = feeList; } - await ws.db.runWithWriteTransaction([Stores.exchanges], async tx => { + await ws.db.runWithWriteTransaction([Stores.exchanges], async (tx) => { const r = await tx.get(Stores.exchanges, exchangeBaseUrl); if (!r) { return; @@ -500,7 +500,7 @@ async function updateExchangeFromUrlImpl( }; await ws.db.put(Stores.exchanges, newExchangeRecord); } else { - await ws.db.runWithWriteTransaction([Stores.exchanges], async t => { + await ws.db.runWithWriteTransaction([Stores.exchanges], async (t) => { const rec = await t.get(Stores.exchanges, baseUrl); if (!rec) { return; diff --git a/src/operations/history.ts b/src/operations/history.ts index 65907de8d..1b4172526 100644 --- a/src/operations/history.ts +++ b/src/operations/history.ts @@ -47,7 +47,7 @@ import { timestampCmp } from "../util/time"; * Create an event ID from the type and the primary key for the event. */ function makeEventId(type: HistoryEventType, ...args: string[]) { - return type + ";" + args.map(x => encodeURIComponent(x)).join(";"); + return type + ";" + args.map((x) => encodeURIComponent(x)).join(";"); } function getOrderShortInfo( @@ -72,7 +72,7 @@ async function collectProposalHistory( history: HistoryEvent[], historyQuery?: HistoryQuery, ) { - tx.iter(Stores.proposals).forEachAsync(async proposal => { + tx.iter(Stores.proposals).forEachAsync(async (proposal) => { const status = proposal.proposalStatus; switch (status) { case ProposalStatus.ACCEPTED: @@ -182,8 +182,8 @@ export async function getHistory( Stores.reserveUpdatedEvents, Stores.recoupGroups, ], - async tx => { - tx.iter(Stores.exchanges).forEach(exchange => { + async (tx) => { + tx.iter(Stores.exchanges).forEach((exchange) => { history.push({ type: HistoryEventType.ExchangeAdded, builtIn: false, @@ -196,7 +196,7 @@ export async function getHistory( }); }); - tx.iter(Stores.exchangeUpdatedEvents).forEach(eu => { + tx.iter(Stores.exchangeUpdatedEvents).forEach((eu) => { history.push({ type: HistoryEventType.ExchangeUpdated, eventId: makeEventId( @@ -208,7 +208,7 @@ export async function getHistory( }); }); - tx.iter(Stores.withdrawalSession).forEach(wsr => { + tx.iter(Stores.withdrawalSession).forEach((wsr) => { if (wsr.timestampFinish) { const cs: PlanchetRecord[] = []; wsr.planchets.forEach((x) => { @@ -226,7 +226,7 @@ export async function getHistory( })), }; } - + history.push({ type: HistoryEventType.Withdrawn, withdrawSessionId: wsr.withdrawSessionId, @@ -246,7 +246,7 @@ export async function getHistory( await collectProposalHistory(tx, history, historyQuery); - await tx.iter(Stores.payEvents).forEachAsync(async pe => { + await tx.iter(Stores.payEvents).forEachAsync(async (pe) => { const proposal = await tx.get(Stores.proposals, pe.proposalId); if (!proposal) { return; @@ -262,7 +262,7 @@ export async function getHistory( let verboseDetails: VerbosePayCoinDetails | undefined = undefined; if (historyQuery?.extraDebug) { const coins: { - value: string, + value: string; contribution: string; denomPub: string; }[] = []; @@ -272,7 +272,10 @@ export async function getHistory( // FIXME: what to do here?? continue; } - const d = await tx.get(Stores.denominations, [c.exchangeBaseUrl, c.denomPub]); + const d = await tx.get(Stores.denominations, [ + c.exchangeBaseUrl, + c.denomPub, + ]); if (!d) { // FIXME: what to do here?? continue; @@ -283,10 +286,12 @@ export async function getHistory( value: Amounts.toString(d.value), }); } - verboseDetails = { coins }; + verboseDetails = { coins }; } const amountPaidWithFees = Amounts.sum( - purchase.payReq.coins.map(x => Amounts.parseOrThrow(x.contribution)), + purchase.payReq.coins.map((x) => + Amounts.parseOrThrow(x.contribution), + ), ).amount; history.push({ type: HistoryEventType.PaymentSent, @@ -301,7 +306,7 @@ export async function getHistory( }); }); - await tx.iter(Stores.refreshGroups).forEachAsync(async rg => { + await tx.iter(Stores.refreshGroups).forEachAsync(async (rg) => { if (!rg.timestampFinished) { return; } @@ -340,7 +345,7 @@ export async function getHistory( if (historyQuery?.extraDebug) { const outputCoins: { value: string; - denomPub: string, + denomPub: string; }[] = []; for (const rs of rg.refreshSessionPerCoin) { if (!rs) { @@ -350,7 +355,10 @@ export async function getHistory( if (!nd) { continue; } - const d = await tx.get(Stores.denominations, [rs.exchangeBaseUrl, nd]); + const d = await tx.get(Stores.denominations, [ + rs.exchangeBaseUrl, + nd, + ]); if (!d) { continue; } @@ -362,7 +370,7 @@ export async function getHistory( } verboseDetails = { outputCoins: outputCoins, - } + }; } history.push({ type: HistoryEventType.Refreshed, @@ -379,7 +387,7 @@ export async function getHistory( }); }); - tx.iter(Stores.reserveUpdatedEvents).forEachAsync(async ru => { + tx.iter(Stores.reserveUpdatedEvents).forEachAsync(async (ru) => { const reserve = await tx.get(Stores.reserves, ru.reservePub); if (!reserve) { return; @@ -413,7 +421,7 @@ export async function getHistory( }); }); - tx.iter(Stores.tips).forEach(tip => { + tx.iter(Stores.tips).forEach((tip) => { if (tip.acceptedTimestamp) { history.push({ type: HistoryEventType.TipAccepted, @@ -425,7 +433,7 @@ export async function getHistory( } }); - tx.iter(Stores.refundEvents).forEachAsync(async re => { + tx.iter(Stores.refundEvents).forEachAsync(async (re) => { const proposal = await tx.get(Stores.proposals, re.proposalId); if (!proposal) { return; @@ -486,7 +494,7 @@ export async function getHistory( }); }); - tx.iter(Stores.recoupGroups).forEach(rg => { + tx.iter(Stores.recoupGroups).forEach((rg) => { if (rg.timestampFinished) { let verboseDetails: any = undefined; if (historyQuery?.extraDebug) { @@ -498,7 +506,10 @@ export async function getHistory( history.push({ type: HistoryEventType.FundsRecouped, timestamp: rg.timestampFinished, - eventId: makeEventId(HistoryEventType.FundsRecouped, rg.recoupGroupId), + eventId: makeEventId( + HistoryEventType.FundsRecouped, + rg.recoupGroupId, + ), numCoinsRecouped: rg.coinPubs.length, verboseDetails, }); diff --git a/src/operations/pay.ts b/src/operations/pay.ts index f3468ae46..9b9d2fa9f 100644 --- a/src/operations/pay.ts +++ b/src/operations/pay.ts @@ -127,7 +127,7 @@ export interface AvailableCoinInfo { /** * Compute the total cost of a payment to the customer. - * + * * This includes the amount taken by the merchant, fees (wire/deposit) contributed * by the customer, refreshing fees, fees for withdraw-after-refresh and "trimmings" * of coins that are too small to spend. @@ -461,7 +461,7 @@ async function recordConfirmPay( await ws.db.runWithWriteTransaction( [Stores.coins, Stores.purchases, Stores.proposals, Stores.refreshGroups], - async tx => { + async (tx) => { const p = await tx.get(Stores.proposals, proposal.proposalId); if (p) { p.proposalStatus = ProposalStatus.ACCEPTED; @@ -486,7 +486,9 @@ async function recordConfirmPay( coin.currentAmount = remaining.amount; await tx.put(Stores.coins, coin); } - const refreshCoinPubs = coinSelection.coinPubs.map(x => ({ coinPub: x })); + const refreshCoinPubs = coinSelection.coinPubs.map((x) => ({ + coinPub: x, + })); await createRefreshGroup(tx, refreshCoinPubs, RefreshReason.Pay); }, ); @@ -560,7 +562,7 @@ export async function abortFailedPayment( RefundReason.AbortRefund, ); - await ws.db.runWithWriteTransaction([Stores.purchases], async tx => { + await ws.db.runWithWriteTransaction([Stores.purchases], async (tx) => { const p = await tx.get(Stores.purchases, proposalId); if (!p) { return; @@ -575,7 +577,7 @@ async function incrementProposalRetry( proposalId: string, err: OperationError | undefined, ): Promise<void> { - await ws.db.runWithWriteTransaction([Stores.proposals], async tx => { + await ws.db.runWithWriteTransaction([Stores.proposals], async (tx) => { const pr = await tx.get(Stores.proposals, proposalId); if (!pr) { return; @@ -597,7 +599,7 @@ async function incrementPurchasePayRetry( err: OperationError | undefined, ): Promise<void> { console.log("incrementing purchase pay retry with error", err); - await ws.db.runWithWriteTransaction([Stores.purchases], async tx => { + await ws.db.runWithWriteTransaction([Stores.purchases], async (tx) => { const pr = await tx.get(Stores.purchases, proposalId); if (!pr) { return; @@ -630,7 +632,7 @@ async function resetDownloadProposalRetry( ws: InternalWalletState, proposalId: string, ) { - await ws.db.mutate(Stores.proposals, proposalId, x => { + await ws.db.mutate(Stores.proposals, proposalId, (x) => { if (x.retryInfo.active) { x.retryInfo = initRetryInfo(); } @@ -685,7 +687,7 @@ async function processDownloadProposalImpl( await ws.db.runWithWriteTransaction( [Stores.proposals, Stores.purchases], - async tx => { + async (tx) => { const p = await tx.get(Stores.proposals, proposalId); if (!p) { return; @@ -715,11 +717,11 @@ async function processDownloadProposalImpl( payDeadline: parsedContractTerms.pay_deadline, refundDeadline: parsedContractTerms.refund_deadline, wireFeeAmortization: parsedContractTerms.wire_fee_amortization || 1, - allowedAuditors: parsedContractTerms.auditors.map(x => ({ + allowedAuditors: parsedContractTerms.auditors.map((x) => ({ auditorBaseUrl: x.url, auditorPub: x.master_pub, })), - allowedExchanges: parsedContractTerms.exchanges.map(x => ({ + allowedExchanges: parsedContractTerms.exchanges.map((x) => ({ exchangeBaseUrl: x.url, exchangePub: x.master_pub, })), @@ -797,7 +799,7 @@ async function startDownloadProposal( downloadSessionId: sessionId, }; - await ws.db.runWithWriteTransaction([Stores.proposals], async tx => { + await ws.db.runWithWriteTransaction([Stores.proposals], async (tx) => { const existingRecord = await tx.getIndexed( Stores.proposals.urlAndOrderIdIndex, [merchantBaseUrl, orderId], @@ -878,7 +880,7 @@ export async function submitPay( await ws.db.runWithWriteTransaction( [Stores.purchases, Stores.payEvents], - async tx => { + async (tx) => { await tx.put(Stores.purchases, purchase); const payEvent: PayEventRecord = { proposalId, @@ -984,7 +986,7 @@ export async function preparePayForUri( console.log( "automatically re-submitting payment with different session ID", ); - await ws.db.runWithWriteTransaction([Stores.purchases], async tx => { + await ws.db.runWithWriteTransaction([Stores.purchases], async (tx) => { const p = await tx.get(Stores.purchases, proposalId); if (!p) { return; @@ -1035,7 +1037,7 @@ export async function confirmPay( sessionIdOverride != purchase.lastSessionId ) { logger.trace(`changing session ID to ${sessionIdOverride}`); - await ws.db.mutate(Stores.purchases, purchase.proposalId, x => { + await ws.db.mutate(Stores.purchases, purchase.proposalId, (x) => { x.lastSessionId = sessionIdOverride; x.paymentSubmitPending = true; return x; @@ -1118,7 +1120,7 @@ async function resetPurchasePayRetry( ws: InternalWalletState, proposalId: string, ) { - await ws.db.mutate(Stores.purchases, proposalId, x => { + await ws.db.mutate(Stores.purchases, proposalId, (x) => { if (x.payRetryInfo.active) { x.payRetryInfo = initRetryInfo(); } @@ -1151,7 +1153,7 @@ export async function refuseProposal( ) { const success = await ws.db.runWithWriteTransaction( [Stores.proposals], - async tx => { + async (tx) => { const proposal = await tx.get(Stores.proposals, proposalId); if (!proposal) { logger.trace(`proposal ${proposalId} not found, won't refuse proposal`); diff --git a/src/operations/pending.ts b/src/operations/pending.ts index a628d6130..adf47b151 100644 --- a/src/operations/pending.ts +++ b/src/operations/pending.ts @@ -59,7 +59,7 @@ async function gatherExchangePending( // FIXME: exchanges should also be updated regularly return; } - await tx.iter(Stores.exchanges).forEach(e => { + await tx.iter(Stores.exchanges).forEach((e) => { switch (e.updateStatus) { case ExchangeUpdateStatus.Finished: if (e.lastError) { @@ -148,7 +148,7 @@ async function gatherReservePending( onlyDue: boolean = false, ): Promise<void> { // FIXME: this should be optimized by using an index for "onlyDue==true". - await tx.iter(Stores.reserves).forEach(reserve => { + await tx.iter(Stores.reserves).forEach((reserve) => { const reserveType = reserve.bankWithdrawStatusUrl ? "taler-bank" : "manual"; if (!reserve.retryInfo.active) { return; @@ -214,7 +214,7 @@ async function gatherRefreshPending( resp: PendingOperationsResponse, onlyDue: boolean = false, ): Promise<void> { - await tx.iter(Stores.refreshGroups).forEach(r => { + await tx.iter(Stores.refreshGroups).forEach((r) => { if (r.timestampFinished) { return; } @@ -243,7 +243,7 @@ async function gatherWithdrawalPending( resp: PendingOperationsResponse, onlyDue: boolean = false, ): Promise<void> { - await tx.iter(Stores.withdrawalSession).forEach(wsr => { + await tx.iter(Stores.withdrawalSession).forEach((wsr) => { if (wsr.timestampFinish) { return; } @@ -277,7 +277,7 @@ async function gatherProposalPending( resp: PendingOperationsResponse, onlyDue: boolean = false, ): Promise<void> { - await tx.iter(Stores.proposals).forEach(proposal => { + await tx.iter(Stores.proposals).forEach((proposal) => { if (proposal.proposalStatus == ProposalStatus.PROPOSED) { if (onlyDue) { return; @@ -318,7 +318,7 @@ async function gatherTipPending( resp: PendingOperationsResponse, onlyDue: boolean = false, ): Promise<void> { - await tx.iter(Stores.tips).forEach(tip => { + await tx.iter(Stores.tips).forEach((tip) => { if (tip.pickedUp) { return; } @@ -348,7 +348,7 @@ async function gatherPurchasePending( resp: PendingOperationsResponse, onlyDue: boolean = false, ): Promise<void> { - await tx.iter(Stores.purchases).forEach(pr => { + await tx.iter(Stores.purchases).forEach((pr) => { if (pr.paymentSubmitPending) { resp.nextRetryDelay = updateRetryDelay( resp.nextRetryDelay, @@ -411,7 +411,7 @@ async function gatherRecoupPending( resp: PendingOperationsResponse, onlyDue: boolean = false, ): Promise<void> { - await tx.iter(Stores.recoupGroups).forEach(rg => { + await tx.iter(Stores.recoupGroups).forEach((rg) => { if (rg.timestampFinished) { return; } @@ -450,7 +450,7 @@ export async function getPendingOperations( Stores.purchases, Stores.recoupGroups, ], - async tx => { + async (tx) => { const walletBalance = await getBalancesInsideTransaction(ws, tx); const resp: PendingOperationsResponse = { nextRetryDelay: { d_ms: Number.MAX_SAFE_INTEGER }, diff --git a/src/operations/refresh.ts b/src/operations/refresh.ts index f196fc5e1..5628263ec 100644 --- a/src/operations/refresh.ts +++ b/src/operations/refresh.ts @@ -68,7 +68,7 @@ export function getTotalRefreshCost( const withdrawDenoms = getWithdrawDenomList(withdrawAmount, denoms); const resultingAmount = Amounts.add( Amounts.getZero(withdrawAmount.currency), - ...withdrawDenoms.map(d => d.value), + ...withdrawDenoms.map((d) => d.value), ).amount; const totalCost = Amounts.sub(amountLeft, resultingAmount).amount; logger.trace( @@ -139,7 +139,7 @@ async function refreshCreateSession( ); await ws.db.runWithWriteTransaction( [Stores.coins, Stores.refreshGroups], - async tx => { + async (tx) => { const rg = await tx.get(Stores.refreshGroups, refreshGroupId); if (!rg) { return; @@ -175,7 +175,7 @@ async function refreshCreateSession( // coin in the same transaction. await ws.db.runWithWriteTransaction( [Stores.refreshGroups, Stores.coins], - async tx => { + async (tx) => { const c = await tx.get(Stores.coins, coin.coinPub); if (!c) { throw Error("coin not found, but marked for refresh"); @@ -274,7 +274,7 @@ async function refreshMelt( refreshSession.norevealIndex = norevealIndex; - await ws.db.mutate(Stores.refreshGroups, refreshGroupId, rg => { + await ws.db.mutate(Stores.refreshGroups, refreshGroupId, (rg) => { const rs = rg.refreshSessionPerCoin[coinIndex]; if (!rs) { return; @@ -420,7 +420,7 @@ async function refreshReveal( await ws.db.runWithWriteTransaction( [Stores.coins, Stores.refreshGroups], - async tx => { + async (tx) => { const rg = await tx.get(Stores.refreshGroups, refreshGroupId); if (!rg) { console.log("no refresh session found"); @@ -464,7 +464,7 @@ async function incrementRefreshRetry( refreshGroupId: string, err: OperationError | undefined, ): Promise<void> { - await ws.db.runWithWriteTransaction([Stores.refreshGroups], async tx => { + await ws.db.runWithWriteTransaction([Stores.refreshGroups], async (tx) => { const r = await tx.get(Stores.refreshGroups, refreshGroupId); if (!r) { return; @@ -499,7 +499,7 @@ async function resetRefreshGroupRetry( ws: InternalWalletState, refreshSessionId: string, ) { - await ws.db.mutate(Stores.refreshGroups, refreshSessionId, x => { + await ws.db.mutate(Stores.refreshGroups, refreshSessionId, (x) => { if (x.retryInfo.active) { x.retryInfo = initRetryInfo(); } @@ -578,13 +578,13 @@ export async function createRefreshGroup( const refreshGroup: RefreshGroupRecord = { timestampFinished: undefined, - finishedPerCoin: oldCoinPubs.map(x => false), + finishedPerCoin: oldCoinPubs.map((x) => false), lastError: undefined, lastErrorPerCoin: {}, - oldCoinPubs: oldCoinPubs.map(x => x.coinPub), + oldCoinPubs: oldCoinPubs.map((x) => x.coinPub), reason, refreshGroupId, - refreshSessionPerCoin: oldCoinPubs.map(x => undefined), + refreshSessionPerCoin: oldCoinPubs.map((x) => undefined), retryInfo: initRetryInfo(), }; diff --git a/src/operations/reserves.ts b/src/operations/reserves.ts index c0e22b3c6..5cf189d3b 100644 --- a/src/operations/reserves.ts +++ b/src/operations/reserves.ts @@ -65,7 +65,7 @@ import { getTimestampNow } from "../util/time"; const logger = new Logger("reserves.ts"); async function resetReserveRetry(ws: InternalWalletState, reservePub: string) { - await ws.db.mutate(Stores.reserves, reservePub, x => { + await ws.db.mutate(Stores.reserves, reservePub, (x) => { if (x.retryInfo.active) { x.retryInfo = initRetryInfo(); } @@ -156,7 +156,7 @@ export async function createReserve( const resp = await ws.db.runWithWriteTransaction( [Stores.currencies, Stores.reserves, Stores.bankWithdrawUris], - async tx => { + async (tx) => { // Check if we have already created a reserve for that bankWithdrawStatusUrl if (reserveRecord.bankWithdrawStatusUrl) { const bwi = await tx.get( @@ -194,7 +194,7 @@ export async function createReserve( // Asynchronously process the reserve, but return // to the caller already. - processReserve(ws, resp.reservePub, true).catch(e => { + processReserve(ws, resp.reservePub, true).catch((e) => { console.error("Processing reserve (after createReserve) failed:", e); }); @@ -208,7 +208,7 @@ export async function forceQueryReserve( ws: InternalWalletState, reservePub: string, ): Promise<void> { - await ws.db.runWithWriteTransaction([Stores.reserves], async tx => { + await ws.db.runWithWriteTransaction([Stores.reserves], async (tx) => { const reserve = await tx.get(Stores.reserves, reservePub); if (!reserve) { return; @@ -275,7 +275,7 @@ async function registerReserveWithBank( reserve_pub: reservePub, selected_exchange: reserve.exchangeWire, }); - await ws.db.mutate(Stores.reserves, reservePub, r => { + await ws.db.mutate(Stores.reserves, reservePub, (r) => { switch (r.reserveStatus) { case ReserveRecordStatus.REGISTERING_BANK: case ReserveRecordStatus.WAIT_CONFIRM_BANK: @@ -349,7 +349,7 @@ async function processReserveBankStatusImpl( } if (status.transfer_done) { - await ws.db.mutate(Stores.reserves, reservePub, r => { + await ws.db.mutate(Stores.reserves, reservePub, (r) => { switch (r.reserveStatus) { case ReserveRecordStatus.REGISTERING_BANK: case ReserveRecordStatus.WAIT_CONFIRM_BANK: @@ -365,7 +365,7 @@ async function processReserveBankStatusImpl( }); await processReserveImpl(ws, reservePub, true); } else { - await ws.db.mutate(Stores.reserves, reservePub, r => { + await ws.db.mutate(Stores.reserves, reservePub, (r) => { switch (r.reserveStatus) { case ReserveRecordStatus.WAIT_CONFIRM_BANK: break; @@ -385,7 +385,7 @@ async function incrementReserveRetry( reservePub: string, err: OperationError | undefined, ): Promise<void> { - await ws.db.runWithWriteTransaction([Stores.reserves], async tx => { + await ws.db.runWithWriteTransaction([Stores.reserves], async (tx) => { const r = await tx.get(Stores.reserves, reservePub); if (!r) { return; @@ -462,7 +462,7 @@ async function updateReserve( const balance = Amounts.parseOrThrow(reserveInfo.balance); await ws.db.runWithWriteTransaction( [Stores.reserves, Stores.reserveUpdatedEvents], - async tx => { + async (tx) => { const r = await tx.get(Stores.reserves, reservePub); if (!r) { return; @@ -501,8 +501,7 @@ async function updateReserve( if (cmp == 0) { // Nothing changed, go back to sleep! r.reserveStatus = ReserveRecordStatus.DORMANT; - } - else if (cmp > 0) { + } else if (cmp > 0) { const extra = Amounts.sub(balance, expectedBalance.amount).amount; r.amountWithdrawRemaining = Amounts.add( r.amountWithdrawRemaining, @@ -591,7 +590,7 @@ export async function confirmReserve( req: ConfirmReserveRequest, ): Promise<void> { const now = getTimestampNow(); - await ws.db.mutate(Stores.reserves, req.reservePub, reserve => { + await ws.db.mutate(Stores.reserves, req.reservePub, (reserve) => { if (reserve.reserveStatus !== ReserveRecordStatus.UNCONFIRMED) { return; } @@ -603,7 +602,7 @@ export async function confirmReserve( ws.notify({ type: NotificationType.ReserveUpdated }); - processReserve(ws, req.reservePub, true).catch(e => { + processReserve(ws, req.reservePub, true).catch((e) => { console.log("processing reserve (after confirmReserve) failed:", e); }); } @@ -653,7 +652,7 @@ async function depleteReserve( const withdrawalSessionId = encodeCrock(randomBytes(32)); - const totalCoinValue = Amounts.sum(denomsForWithdraw.map(x => x.value)) + const totalCoinValue = Amounts.sum(denomsForWithdraw.map((x) => x.value)) .amount; const withdrawalRecord: WithdrawalSessionRecord = { @@ -665,9 +664,9 @@ async function depleteReserve( }, rawWithdrawalAmount: withdrawAmount, timestampStart: getTimestampNow(), - denoms: denomsForWithdraw.map(x => x.denomPub), - withdrawn: denomsForWithdraw.map(x => false), - planchets: denomsForWithdraw.map(x => undefined), + denoms: denomsForWithdraw.map((x) => x.denomPub), + withdrawn: denomsForWithdraw.map((x) => false), + planchets: denomsForWithdraw.map((x) => undefined), totalCoinValue, retryInfo: initRetryInfo(), lastErrorPerCoin: {}, @@ -675,7 +674,7 @@ async function depleteReserve( }; const totalCoinWithdrawFee = Amounts.sum( - denomsForWithdraw.map(x => x.feeWithdraw), + denomsForWithdraw.map((x) => x.feeWithdraw), ).amount; const totalWithdrawAmount = Amounts.add(totalCoinValue, totalCoinWithdrawFee) .amount; @@ -706,7 +705,7 @@ async function depleteReserve( const success = await ws.db.runWithWriteTransaction( [Stores.withdrawalSession, Stores.reserves], - async tx => { + async (tx) => { const myReserve = await tx.get(Stores.reserves, reservePub); if (!myReserve) { return false; diff --git a/src/operations/state.ts b/src/operations/state.ts index ae32db2b3..f571fe93a 100644 --- a/src/operations/state.ts +++ b/src/operations/state.ts @@ -15,10 +15,7 @@ */ import { HttpRequestLibrary } from "../util/http"; -import { - NextUrlResult, - WalletBalance, -} from "../types/walletTypes"; +import { NextUrlResult, WalletBalance } from "../types/walletTypes"; import { CryptoApi, CryptoWorkerFactory } from "../crypto/workers/cryptoApi"; import { AsyncOpMemoMap, AsyncOpMemoSingle } from "../util/asyncMemo"; import { Logger } from "../util/logging"; diff --git a/src/operations/tip.ts b/src/operations/tip.ts index fcdda0763..3636dd247 100644 --- a/src/operations/tip.ts +++ b/src/operations/tip.ts @@ -16,10 +16,7 @@ import { InternalWalletState } from "./state"; import { parseTipUri } from "../util/taleruri"; -import { - TipStatus, - OperationError, -} from "../types/walletTypes"; +import { TipStatus, OperationError } from "../types/walletTypes"; import { TipPickupGetResponse, TipPlanchetDetail, @@ -130,7 +127,7 @@ async function incrementTipRetry( refreshSessionId: string, err: OperationError | undefined, ): Promise<void> { - await ws.db.runWithWriteTransaction([Stores.tips], async tx => { + await ws.db.runWithWriteTransaction([Stores.tips], async (tx) => { const t = await tx.get(Stores.tips, refreshSessionId); if (!t) { return; @@ -162,7 +159,7 @@ async function resetTipRetry( ws: InternalWalletState, tipId: string, ): Promise<void> { - await ws.db.mutate(Stores.tips, tipId, x => { + await ws.db.mutate(Stores.tips, tipId, (x) => { if (x.retryInfo.active) { x.retryInfo = initRetryInfo(); } @@ -197,10 +194,10 @@ async function processTipImpl( ); const planchets = await Promise.all( - denomsForWithdraw.map(d => ws.cryptoApi.createTipPlanchet(d)), + denomsForWithdraw.map((d) => ws.cryptoApi.createTipPlanchet(d)), ); - await ws.db.mutate(Stores.tips, tipId, r => { + await ws.db.mutate(Stores.tips, tipId, (r) => { if (!r.planchets) { r.planchets = planchets; } @@ -220,7 +217,7 @@ async function processTipImpl( console.log("got planchets for tip!"); // Planchets in the form that the merchant expects - const planchetsDetail: TipPlanchetDetail[] = tipRecord.planchets.map(p => ({ + const planchetsDetail: TipPlanchetDetail[] = tipRecord.planchets.map((p) => ({ coin_ev: p.coinEv, denom_pub_hash: p.denomPubHash, })); @@ -269,7 +266,7 @@ async function processTipImpl( const withdrawalSessionId = encodeCrock(getRandomBytes(32)); const withdrawalSession: WithdrawalSessionRecord = { - denoms: planchets.map(x => x.denomPub), + denoms: planchets.map((x) => x.denomPub), exchangeBaseUrl: tipRecord.exchangeUrl, planchets: planchets, source: { @@ -279,8 +276,8 @@ async function processTipImpl( timestampStart: getTimestampNow(), withdrawSessionId: withdrawalSessionId, rawWithdrawalAmount: tipRecord.amount, - withdrawn: planchets.map(x => false), - totalCoinValue: Amounts.sum(planchets.map(p => p.coinValue)).amount, + withdrawn: planchets.map((x) => false), + totalCoinValue: Amounts.sum(planchets.map((p) => p.coinValue)).amount, lastErrorPerCoin: {}, retryInfo: initRetryInfo(), timestampFinish: undefined, @@ -289,7 +286,7 @@ async function processTipImpl( await ws.db.runWithWriteTransaction( [Stores.tips, Stores.withdrawalSession], - async tx => { + async (tx) => { const tr = await tx.get(Stores.tips, tipId); if (!tr) { return; diff --git a/src/operations/versions.ts b/src/operations/versions.ts index 6ac78f013..8b55bd4d5 100644 --- a/src/operations/versions.ts +++ b/src/operations/versions.ts @@ -26,7 +26,7 @@ export const WALLET_EXCHANGE_PROTOCOL_VERSION = "7:0:0"; * Cache breaker that is appended to queries such as /keys and /wire * to break through caching, if it has been accidentally/badly configured * by the exchange. - * - * This is only a temporary measure. + * + * This is only a temporary measure. */ -export const WALLET_CACHE_BREAKER_CLIENT_VERSION = "3";
\ No newline at end of file +export const WALLET_CACHE_BREAKER_CLIENT_VERSION = "3"; diff --git a/src/operations/withdraw.ts b/src/operations/withdraw.ts index 37993023e..4d8af9fc0 100644 --- a/src/operations/withdraw.ts +++ b/src/operations/withdraw.ts @@ -144,7 +144,7 @@ async function getPossibleDenoms( ): Promise<DenominationRecord[]> { return await ws.db .iterIndex(Stores.denominations.exchangeBaseUrlIndex, exchangeBaseUrl) - .filter(d => { + .filter((d) => { return ( (d.status === DenominationStatus.Unverified || d.status === DenominationStatus.VerifiedGood) && @@ -248,7 +248,7 @@ async function processPlanchet( const success = await ws.db.runWithWriteTransaction( [Stores.coins, Stores.withdrawalSession, Stores.reserves], - async tx => { + async (tx) => { const ws = await tx.get(Stores.withdrawalSession, withdrawalSessionId); if (!ws) { return false; @@ -429,17 +429,20 @@ async function makePlanchet( reservePub: r.reservePub, withdrawSig: r.withdrawSig, }; - await ws.db.runWithWriteTransaction([Stores.withdrawalSession], async tx => { - const myWs = await tx.get(Stores.withdrawalSession, withdrawalSessionId); - if (!myWs) { - return; - } - if (myWs.planchets[coinIndex]) { - return; - } - myWs.planchets[coinIndex] = newPlanchet; - await tx.put(Stores.withdrawalSession, myWs); - }); + await ws.db.runWithWriteTransaction( + [Stores.withdrawalSession], + async (tx) => { + const myWs = await tx.get(Stores.withdrawalSession, withdrawalSessionId); + if (!myWs) { + return; + } + if (myWs.planchets[coinIndex]) { + return; + } + myWs.planchets[coinIndex] = newPlanchet; + await tx.put(Stores.withdrawalSession, myWs); + }, + ); } async function processWithdrawCoin( @@ -483,19 +486,22 @@ async function incrementWithdrawalRetry( withdrawalSessionId: string, err: OperationError | undefined, ): Promise<void> { - await ws.db.runWithWriteTransaction([Stores.withdrawalSession], async tx => { - const wsr = await tx.get(Stores.withdrawalSession, withdrawalSessionId); - if (!wsr) { - return; - } - if (!wsr.retryInfo) { - return; - } - wsr.retryInfo.retryCounter++; - updateRetryInfoTimeout(wsr.retryInfo); - wsr.lastError = err; - await tx.put(Stores.withdrawalSession, wsr); - }); + await ws.db.runWithWriteTransaction( + [Stores.withdrawalSession], + async (tx) => { + const wsr = await tx.get(Stores.withdrawalSession, withdrawalSessionId); + if (!wsr) { + return; + } + if (!wsr.retryInfo) { + return; + } + wsr.retryInfo.retryCounter++; + updateRetryInfoTimeout(wsr.retryInfo); + wsr.lastError = err; + await tx.put(Stores.withdrawalSession, wsr); + }, + ); ws.notify({ type: NotificationType.WithdrawOperationError }); } @@ -516,7 +522,7 @@ async function resetWithdrawSessionRetry( ws: InternalWalletState, withdrawalSessionId: string, ) { - await ws.db.mutate(Stores.withdrawalSession, withdrawalSessionId, x => { + await ws.db.mutate(Stores.withdrawalSession, withdrawalSessionId, (x) => { if (x.retryInfo.active) { x.retryInfo = initRetryInfo(); } @@ -594,12 +600,14 @@ export async function getExchangeWithdrawalInfo( const possibleDenoms = await ws.db .iterIndex(Stores.denominations.exchangeBaseUrlIndex, baseUrl) - .filter(d => d.isOffered); + .filter((d) => d.isOffered); const trustedAuditorPubs = []; const currencyRecord = await ws.db.get(Stores.currencies, amount.currency); if (currencyRecord) { - trustedAuditorPubs.push(...currencyRecord.auditors.map(a => a.auditorPub)); + trustedAuditorPubs.push( + ...currencyRecord.auditors.map((a) => a.auditorPub), + ); } let versionMatch; diff --git a/src/types/dbTypes.ts b/src/types/dbTypes.ts index 5a0a653ee..db71db710 100644 --- a/src/types/dbTypes.ts +++ b/src/types/dbTypes.ts @@ -1370,7 +1370,7 @@ export interface BankWithdrawUriRecord { /** * Status of recoup operations that were grouped together. - * + * * The remaining amount of involved coins should be set to zero * in the same transaction that inserts the RecoupGroupRecord. */ @@ -1387,7 +1387,7 @@ export interface RecoupGroupRecord { /** * Public keys that identify the coins being recouped * as part of this session. - * + * * (Structured like this to enable multiEntry indexing in IndexedDB.) */ coinPubs: string[]; diff --git a/src/types/history.ts b/src/types/history.ts index 976788fc3..f4f3872ca 100644 --- a/src/types/history.ts +++ b/src/types/history.ts @@ -18,9 +18,9 @@ * Type and schema definitions for the wallet's history. */ - /** - * Imports. - */ +/** + * Imports. + */ import { RefreshReason } from "./walletTypes"; import { ReserveTransaction } from "./ReserveTransaction"; import { WithdrawalSource } from "./dbTypes"; diff --git a/src/types/schemacore.ts b/src/types/schemacore.ts index c709e3d7a..820f68d18 100644 --- a/src/types/schemacore.ts +++ b/src/types/schemacore.ts @@ -17,7 +17,7 @@ /** * Core of the wallet's schema, used for painless export, import * and schema migration. - * + * * If this schema is extended, it must be extended in a completely * backwards-compatible way. */ @@ -55,4 +55,4 @@ interface SchemaCore { * Schema version of the database that has been exported to the core schema */ versionSourceDatabase: number; -}
\ No newline at end of file +} diff --git a/src/types/types-test.ts b/src/types/types-test.ts index 67d379f7b..885371a1a 100644 --- a/src/types/types-test.ts +++ b/src/types/types-test.ts @@ -24,7 +24,7 @@ const amt = ( currency: string, ): Amounts.AmountJson => ({ value, fraction, currency }); -test("amount addition (simple)", t => { +test("amount addition (simple)", (t) => { const a1 = amt(1, 0, "EUR"); const a2 = amt(1, 0, "EUR"); const a3 = amt(2, 0, "EUR"); @@ -32,14 +32,14 @@ test("amount addition (simple)", t => { t.pass(); }); -test("amount addition (saturation)", t => { +test("amount addition (saturation)", (t) => { const a1 = amt(1, 0, "EUR"); const res = Amounts.add(amt(Amounts.maxAmountValue, 0, "EUR"), a1); t.true(res.saturated); t.pass(); }); -test("amount subtraction (simple)", t => { +test("amount subtraction (simple)", (t) => { const a1 = amt(2, 5, "EUR"); const a2 = amt(1, 0, "EUR"); const a3 = amt(1, 5, "EUR"); @@ -47,7 +47,7 @@ test("amount subtraction (simple)", t => { t.pass(); }); -test("amount subtraction (saturation)", t => { +test("amount subtraction (saturation)", (t) => { const a1 = amt(0, 0, "EUR"); const a2 = amt(1, 0, "EUR"); let res = Amounts.sub(a1, a2); @@ -57,7 +57,7 @@ test("amount subtraction (saturation)", t => { t.pass(); }); -test("amount comparison", t => { +test("amount comparison", (t) => { t.is(Amounts.cmp(amt(1, 0, "EUR"), amt(1, 0, "EUR")), 0); t.is(Amounts.cmp(amt(1, 1, "EUR"), amt(1, 0, "EUR")), 1); t.is(Amounts.cmp(amt(1, 1, "EUR"), amt(1, 2, "EUR")), -1); @@ -68,7 +68,7 @@ test("amount comparison", t => { t.pass(); }); -test("amount parsing", t => { +test("amount parsing", (t) => { t.is( Amounts.cmp(Amounts.parseOrThrow("TESTKUDOS:0"), amt(0, 0, "TESTKUDOS")), 0, @@ -117,7 +117,7 @@ test("amount parsing", t => { t.pass(); }); -test("amount stringification", t => { +test("amount stringification", (t) => { t.is(Amounts.toString(amt(0, 0, "TESTKUDOS")), "TESTKUDOS:0"); t.is(Amounts.toString(amt(4, 94000000, "TESTKUDOS")), "TESTKUDOS:4.94"); t.is(Amounts.toString(amt(0, 10000000, "TESTKUDOS")), "TESTKUDOS:0.1"); @@ -128,7 +128,7 @@ test("amount stringification", t => { t.pass(); }); -test("contract terms validation", t => { +test("contract terms validation", (t) => { const c = { nonce: "123123123", h_wire: "123", diff --git a/src/types/walletTypes.ts b/src/types/walletTypes.ts index c6473a9b7..7b58ba500 100644 --- a/src/types/walletTypes.ts +++ b/src/types/walletTypes.ts @@ -20,7 +20,7 @@ * These types are defined in a separate file make tree shaking easier, since * some components use these types (via RPC) but do not depend on the wallet * code directly. - * + * * @author Florian Dold <dold@taler.net> */ @@ -317,7 +317,6 @@ export class ReturnCoinsRequest { static checked: (obj: any) => ReturnCoinsRequest; } - /** * Status of processing a tip. */ diff --git a/src/util/RequestThrottler.ts b/src/util/RequestThrottler.ts index 0566306de..c99c7e949 100644 --- a/src/util/RequestThrottler.ts +++ b/src/util/RequestThrottler.ts @@ -21,7 +21,12 @@ /** * Imports. */ -import { getTimestampNow, Timestamp, timestampSubtractDuraction, timestampDifference } from "../util/time"; +import { + getTimestampNow, + Timestamp, + timestampSubtractDuraction, + timestampDifference, +} from "../util/time"; /** * Maximum request per second, per origin. @@ -38,7 +43,6 @@ const MAX_PER_MINUTE = 100; */ const MAX_PER_HOUR = 1000; - /** * Throttling state for one origin. */ @@ -52,12 +56,21 @@ class OriginState { const now = getTimestampNow(); const d = timestampDifference(now, this.lastUpdate); if (d.d_ms === "forever") { - throw Error("assertion failed") + throw Error("assertion failed"); } const d_s = d.d_ms / 1000; - this.tokensSecond = Math.min(MAX_PER_SECOND, this.tokensSecond + (d_s / 1000)); - this.tokensMinute = Math.min(MAX_PER_MINUTE, this.tokensMinute + (d_s / 1000 * 60)); - this.tokensHour = Math.min(MAX_PER_HOUR, this.tokensHour + (d_s / 1000 * 60 * 60)); + this.tokensSecond = Math.min( + MAX_PER_SECOND, + this.tokensSecond + d_s / 1000, + ); + this.tokensMinute = Math.min( + MAX_PER_MINUTE, + this.tokensMinute + (d_s / 1000) * 60, + ); + this.tokensHour = Math.min( + MAX_PER_HOUR, + this.tokensHour + (d_s / 1000) * 60 * 60, + ); this.lastUpdate = now; } @@ -104,13 +117,13 @@ export class RequestThrottler { if (s) { return s; } - const ns = this.perOriginInfo[origin] = new OriginState(); + const ns = (this.perOriginInfo[origin] = new OriginState()); return ns; } /** * Apply throttling to a request. - * + * * @returns whether the request should be throttled. */ applyThrottle(requestUrl: string): boolean { diff --git a/src/util/assertUnreachable.ts b/src/util/assertUnreachable.ts index 90f2476b4..ffdf88f04 100644 --- a/src/util/assertUnreachable.ts +++ b/src/util/assertUnreachable.ts @@ -16,4 +16,4 @@ export function assertUnreachable(x: never): never { throw new Error("Didn't expect to get here"); -}
\ No newline at end of file +} diff --git a/src/util/asyncMemo.ts b/src/util/asyncMemo.ts index 17204a88e..84fe6b802 100644 --- a/src/util/asyncMemo.ts +++ b/src/util/asyncMemo.ts @@ -40,9 +40,9 @@ export class AsyncOpMemoMap<T> { // Wrap the operation in case it immediately throws const p = Promise.resolve().then(() => pg()); this.memoMap[key] = { - p, - n, - t: new Date().getTime(), + p, + n, + t: new Date().getTime(), }; return p.finally(() => { this.cleanUp(key, n); @@ -53,7 +53,6 @@ export class AsyncOpMemoMap<T> { } } - export class AsyncOpMemoSingle<T> { private n = 0; private memoEntry: MemoEntry<T> | undefined; diff --git a/src/util/codec-test.ts b/src/util/codec-test.ts index 7c7c93c7b..e25a9d3cd 100644 --- a/src/util/codec-test.ts +++ b/src/util/codec-test.ts @@ -19,7 +19,13 @@ */ import test from "ava"; -import { Codec, makeCodecForObject, makeCodecForConstString, codecForString, makeCodecForUnion } from "./codec"; +import { + Codec, + makeCodecForObject, + makeCodecForConstString, + codecForString, + makeCodecForUnion, +} from "./codec"; interface MyObj { foo: string; @@ -37,7 +43,7 @@ interface AltTwo { type MyUnion = AltOne | AltTwo; -test("basic codec", t => { +test("basic codec", (t) => { const myObjCodec = makeCodecForObject<MyObj>() .property("foo", codecForString) .build("MyObj"); @@ -49,7 +55,7 @@ test("basic codec", t => { }); }); -test("union", t => { +test("union", (t) => { const altOneCodec: Codec<AltOne> = makeCodecForObject<AltOne>() .property("type", makeCodecForConstString("one")) .property("foo", codecForString) diff --git a/src/util/codec.ts b/src/util/codec.ts index 09fa9f953..a8f495238 100644 --- a/src/util/codec.ts +++ b/src/util/codec.ts @@ -110,7 +110,8 @@ class ObjectCodecBuilder<OutputType, PartialOutputType> { throw new DecodingError( `expected object for ${objectDisplayName} at ${renderContext( c, - )} but got ${typeof x}`) + )} but got ${typeof x}`, + ); } const obj: any = {}; for (const prop of propList) { @@ -273,7 +274,9 @@ export const codecForNumber: Codec<number> = { if (typeof x === "number") { return x; } - throw new DecodingError(`expected number at ${renderContext(c)} but got ${typeof x}`); + throw new DecodingError( + `expected number at ${renderContext(c)} but got ${typeof x}`, + ); }, }; @@ -285,7 +288,9 @@ export const codecForBoolean: Codec<boolean> = { if (typeof x === "boolean") { return x; } - throw new DecodingError(`expected boolean at ${renderContext(c)} but got ${typeof x}`); + throw new DecodingError( + `expected boolean at ${renderContext(c)} but got ${typeof x}`, + ); }, }; @@ -297,7 +302,9 @@ export const codecForString: Codec<string> = { if (typeof x === "string") { return x; } - throw new DecodingError(`expected string at ${renderContext(c)} but got ${typeof x}`); + throw new DecodingError( + `expected string at ${renderContext(c)} but got ${typeof x}`, + ); }, }; @@ -320,21 +327,25 @@ export function makeCodecForConstString<V extends string>(s: V): Codec<V> { return x; } throw new DecodingError( - `expected string constant "${s}" at ${renderContext(c)} but got ${typeof x}`, + `expected string constant "${s}" at ${renderContext( + c, + )} but got ${typeof x}`, ); }, }; } -export function makeCodecOptional<V>(innerCodec: Codec<V>): Codec<V | undefined> { +export function makeCodecOptional<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); - } - } + }, + }; } export function typecheckedCodec<T = undefined>(c: Codec<T>): Codec<T> { diff --git a/src/util/helpers-test.ts b/src/util/helpers-test.ts index 74817120a..35f3d87b2 100644 --- a/src/util/helpers-test.ts +++ b/src/util/helpers-test.ts @@ -14,25 +14,26 @@ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ - import test from "ava"; import * as helpers from "./helpers"; - test("URL canonicalization", (t) => { // converts to relative, adds https t.is( "https://alice.example.com/exchange/", - helpers.canonicalizeBaseUrl("alice.example.com/exchange")); + helpers.canonicalizeBaseUrl("alice.example.com/exchange"), + ); // keeps http, adds trailing slash t.is( "http://alice.example.com/exchange/", - helpers.canonicalizeBaseUrl("http://alice.example.com/exchange")); + helpers.canonicalizeBaseUrl("http://alice.example.com/exchange"), + ); // keeps http, adds trailing slash t.is( "http://alice.example.com/exchange/", - helpers.canonicalizeBaseUrl("http://alice.example.com/exchange#foobar")); + helpers.canonicalizeBaseUrl("http://alice.example.com/exchange#foobar"), + ); t.pass(); }); diff --git a/src/util/helpers.ts b/src/util/helpers.ts index 722688d35..130dcdaef 100644 --- a/src/util/helpers.ts +++ b/src/util/helpers.ts @@ -34,7 +34,6 @@ export function amountToPretty(amount: AmountJson): string { return `${x} ${amount.currency}`; } - /** * Canonicalize a base url, typically for the exchange. * @@ -53,7 +52,6 @@ export function canonicalizeBaseUrl(url: string) { return x.href; } - /** * Convert object to JSON with canonical ordering of keys * and whitespace omitted. @@ -84,7 +82,6 @@ export function canonicalJson(obj: any): string { return s + "}"; } - /** * Check for deep equality of two objects. * Only arrays, objects and primitives are supported. @@ -99,11 +96,12 @@ export function deepEquals(x: any, y: any): boolean { } const p = Object.keys(x); - return Object.keys(y).every((i) => p.indexOf(i) !== -1) && - p.every((i) => deepEquals(x[i], y[i])); + return ( + Object.keys(y).every((i) => p.indexOf(i) !== -1) && + p.every((i) => deepEquals(x[i], y[i])) + ); } - /** * Map from a collection to a list or results and then * concatenate the results. @@ -125,12 +123,11 @@ export function hash(val: any): number { } /* JavaScript does bitwise operations (like XOR, above) on 32-bit signed - * integers. Since we want the results to be always positive, convert the - * signed int to an unsigned by doing an unsigned bitshift. */ + * integers. Since we want the results to be always positive, convert the + * signed int to an unsigned by doing an unsigned bitshift. */ return h >>> 0; } - /** * Lexically compare two strings. */ @@ -146,10 +143,10 @@ export function strcmp(s1: string, s2: string): number { /** * Run a function and return its result. - * + * * Used as a nicer-looking way to do immediately invoked function * expressions (IFFEs). */ export function runBlock<T>(f: () => T) { return f(); -}
\ No newline at end of file +} diff --git a/src/util/http.ts b/src/util/http.ts index 93c748d79..1a5cb85fa 100644 --- a/src/util/http.ts +++ b/src/util/http.ts @@ -101,12 +101,12 @@ export class BrowserHttpLib implements HttpRequestLibrary { myRequest.send(); } - myRequest.onerror = e => { + myRequest.onerror = (e) => { console.error("http request error"); reject(Error("could not make XMLHttpRequest")); }; - myRequest.addEventListener("readystatechange", e => { + myRequest.addEventListener("readystatechange", (e) => { if (myRequest.readyState === XMLHttpRequest.DONE) { if (myRequest.status === 0) { reject( @@ -134,7 +134,7 @@ export class BrowserHttpLib implements HttpRequestLibrary { // Create a map of header names to values const headerMap = new Headers(); - arr.forEach(function(line) { + arr.forEach(function (line) { const parts = line.split(": "); const header = parts.shift(); const value = parts.join(": "); diff --git a/src/util/libtoolVersion-test.ts b/src/util/libtoolVersion-test.ts index 0a610e455..e58e94759 100644 --- a/src/util/libtoolVersion-test.ts +++ b/src/util/libtoolVersion-test.ts @@ -19,12 +19,30 @@ 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", "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}); + 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/src/util/libtoolVersion.ts b/src/util/libtoolVersion.ts index cc2435b94..5e9d0b74e 100644 --- a/src/util/libtoolVersion.ts +++ b/src/util/libtoolVersion.ts @@ -19,7 +19,6 @@ * See https://www.gnu.org/software/libtool/manual/html_node/Libtool-versioning.html */ - /** * Result of comparing two libtool versions. */ @@ -44,7 +43,10 @@ interface Version { /** * Compare two libtool-style version strings. */ -export function compare(me: string, other: string): VersionMatchResult|undefined { +export function compare( + me: string, + other: string, +): VersionMatchResult | undefined { const meVer = parseVersion(me); const otherVer = parseVersion(other); @@ -52,16 +54,16 @@ export function compare(me: string, other: string): VersionMatchResult|undefined return undefined; } - const compatible = (meVer.current - meVer.age <= otherVer.current && - meVer.current >= (otherVer.current - otherVer.age)); + 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}; + return { compatible, currentCmp }; } - -function parseVersion(v: string): Version|undefined { +function parseVersion(v: string): Version | undefined { const [currentStr, revisionStr, ageStr, ...rest] = v.split(":"); if (rest.length !== 0) { return undefined; @@ -82,5 +84,5 @@ function parseVersion(v: string): Version|undefined { return undefined; } - return {current, revision, age}; + return { current, revision, age }; } diff --git a/src/util/payto-test.ts b/src/util/payto-test.ts index 82daff164..01280b650 100644 --- a/src/util/payto-test.ts +++ b/src/util/payto-test.ts @@ -28,4 +28,4 @@ test("basic payto parsing", (t) => { const r3 = parsePaytoUri("payto://x-taler-bank/123"); t.is(r3?.targetType, "x-taler-bank"); t.is(r3?.targetPath, "123"); -});
\ No newline at end of file +}); diff --git a/src/util/payto.ts b/src/util/payto.ts index 0926fdeed..ac5bc0c7f 100644 --- a/src/util/payto.ts +++ b/src/util/payto.ts @@ -20,9 +20,8 @@ interface PaytoUri { params: { [name: string]: string }; } - export function parsePaytoUri(s: string): PaytoUri | undefined { - const pfx = "payto://" + const pfx = "payto://"; if (!s.startsWith(pfx)) { return undefined; } @@ -50,5 +49,5 @@ export function parsePaytoUri(s: string): PaytoUri | undefined { targetPath, targetType, params, - } -}
\ No newline at end of file + }; +} diff --git a/src/util/promiseUtils.ts b/src/util/promiseUtils.ts index 9add2c407..d409686d9 100644 --- a/src/util/promiseUtils.ts +++ b/src/util/promiseUtils.ts @@ -14,11 +14,11 @@ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ - export interface OpenedPromise<T> { +export interface OpenedPromise<T> { promise: Promise<T>; resolve: (val: T) => void; reject: (err: any) => void; - } +} /** * Get an unresolved promise together with its extracted resolve / reject @@ -57,4 +57,4 @@ export class AsyncCondition { this._waitPromise = op.promise; this._resolveWaitPromise = op.resolve; } -}
\ No newline at end of file +} diff --git a/src/util/query.ts b/src/util/query.ts index 3303907fe..ce704b4fc 100644 --- a/src/util/query.ts +++ b/src/util/query.ts @@ -271,11 +271,14 @@ export class TransactionHandle { return new ResultStream<T>(req); } - iterIndexed<S extends IDBValidKey,T>( + iterIndexed<S extends IDBValidKey, T>( index: Index<S, T>, key?: any, ): ResultStream<T> { - const req = this.tx.objectStore(index.storeName).index(index.indexName).openCursor(key); + const req = this.tx + .objectStore(index.storeName) + .index(index.indexName) + .openCursor(key); return new ResultStream<T>(req); } @@ -298,7 +301,7 @@ function runWithTransaction<T>( ): Promise<T> { const stack = Error("Failed transaction was started here."); return new Promise((resolve, reject) => { - const storeName = stores.map(x => x.name); + const storeName = stores.map((x) => x.name); const tx = db.transaction(storeName, mode); let funResult: any = undefined; let gotFunResult: boolean = false; @@ -332,11 +335,11 @@ function runWithTransaction<T>( const th = new TransactionHandle(tx); const resP = Promise.resolve().then(() => f(th)); resP - .then(result => { + .then((result) => { gotFunResult = true; funResult = result; }) - .catch(e => { + .catch((e) => { if (e == TransactionAbort) { console.info("aborting transaction"); } else { @@ -344,7 +347,8 @@ function runWithTransaction<T>( console.error(stack); tx.abort(); } - }).catch((e) => { + }) + .catch((e) => { console.error("fatal: aborting transaction failed", e); }); }); @@ -394,15 +398,19 @@ export function openDatabase( databaseName: string, databaseVersion: number, onVersionChange: () => void, - onUpgradeNeeded: (db: IDBDatabase, oldVersion: number, newVersion: number) => void, + onUpgradeNeeded: ( + db: IDBDatabase, + oldVersion: number, + newVersion: number, + ) => void, ): Promise<IDBDatabase> { return new Promise<IDBDatabase>((resolve, reject) => { const req = idbFactory.open(databaseName, databaseVersion); - req.onerror = e => { + req.onerror = (e) => { console.log("taler database error", e); reject(new Error("database error")); }; - req.onsuccess = e => { + req.onsuccess = (e) => { req.result.onversionchange = (evt: IDBVersionChangeEvent) => { console.log( `handling live db version change from ${evt.oldVersion} to ${evt.newVersion}`, @@ -412,7 +420,7 @@ export function openDatabase( }; resolve(req.result); }; - req.onupgradeneeded = e => { + req.onupgradeneeded = (e) => { const db = req.result; onUpgradeNeeded(db, e.oldVersion, e.newVersion!); console.log( @@ -441,7 +449,7 @@ export class Database { stores: {} as { [s: string]: any }, version: db.version, }; - + return new Promise((resolve, reject) => { const tx = db.transaction(Array.from(db.objectStoreNames)); tx.addEventListener("complete", () => { @@ -489,7 +497,7 @@ export class Database { }); }); } - + async get<T>(store: Store<T>, key: any): Promise<T | undefined> { const tx = this.db.transaction([store.name], "readonly"); const req = tx.objectStore(store.name).get(key); @@ -503,10 +511,7 @@ export class Database { key: any, ): Promise<T | undefined> { const tx = this.db.transaction([index.storeName], "readonly"); - const req = tx - .objectStore(index.storeName) - .index(index.indexName) - .get(key); + const req = tx.objectStore(index.storeName).index(index.indexName).get(key); const v = await requestToPromise(req); await transactionToPromise(tx); return v; diff --git a/src/util/talerconfig.ts b/src/util/talerconfig.ts index 333bcd1bb..61c75574f 100644 --- a/src/util/talerconfig.ts +++ b/src/util/talerconfig.ts @@ -110,11 +110,13 @@ export class Configuration { getString(section: string, option: string): ConfigValue<string> { const val = (this.sectionMap[section] ?? {})[option]; - return new ConfigValue(section, option, val, x => x); + return new ConfigValue(section, option, val, (x) => x); } getAmount(section: string, option: string): ConfigValue<AmountJson> { const val = (this.sectionMap[section] ?? {})[option]; - return new ConfigValue(section, option, val, x => Amounts.parseOrThrow(x)); + return new ConfigValue(section, option, val, (x) => + Amounts.parseOrThrow(x), + ); } } diff --git a/src/util/taleruri-test.ts b/src/util/taleruri-test.ts index 052581a91..9efc1846d 100644 --- a/src/util/taleruri-test.ts +++ b/src/util/taleruri-test.ts @@ -22,7 +22,7 @@ import { parseTipUri, } from "./taleruri"; -test("taler pay url parsing: wrong scheme", t => { +test("taler pay url parsing: wrong scheme", (t) => { const url1 = "talerfoo://"; const r1 = parsePayUri(url1); t.is(r1, undefined); @@ -32,7 +32,7 @@ test("taler pay url parsing: wrong scheme", t => { t.is(r2, undefined); }); -test("taler pay url parsing: defaults", t => { +test("taler pay url parsing: defaults", (t) => { const url1 = "taler://pay/example.com/-/-/myorder"; const r1 = parsePayUri(url1); if (!r1) { @@ -52,7 +52,7 @@ test("taler pay url parsing: defaults", t => { t.is(r2.sessionId, "mysession"); }); -test("taler pay url parsing: trailing parts", t => { +test("taler pay url parsing: trailing parts", (t) => { const url1 = "taler://pay/example.com/-/-/myorder/mysession/spam/eggs"; const r1 = parsePayUri(url1); if (!r1) { @@ -63,7 +63,7 @@ test("taler pay url parsing: trailing parts", t => { t.is(r1.sessionId, "mysession"); }); -test("taler pay url parsing: instance", t => { +test("taler pay url parsing: instance", (t) => { const url1 = "taler://pay/example.com/-/myinst/myorder"; const r1 = parsePayUri(url1); if (!r1) { @@ -74,7 +74,7 @@ test("taler pay url parsing: instance", t => { t.is(r1.orderId, "myorder"); }); -test("taler pay url parsing: path prefix and instance", t => { +test("taler pay url parsing: path prefix and instance", (t) => { const url1 = "taler://pay/example.com/mypfx/myinst/myorder"; const r1 = parsePayUri(url1); if (!r1) { @@ -84,7 +84,7 @@ test("taler pay url parsing: path prefix and instance", t => { t.is(r1.merchantBaseUrl, "https://example.com/mypfx/instances/myinst/"); }); -test("taler pay url parsing: complex path prefix", t => { +test("taler pay url parsing: complex path prefix", (t) => { const url1 = "taler://pay/example.com/mypfx%2Fpublic/-/myorder"; const r1 = parsePayUri(url1); if (!r1) { @@ -96,7 +96,7 @@ test("taler pay url parsing: complex path prefix", t => { t.is(r1.sessionId, undefined); }); -test("taler pay uri parsing: complex path prefix and instance", t => { +test("taler pay uri parsing: complex path prefix and instance", (t) => { const url1 = "taler://pay/example.com/mypfx%2Fpublic/foo/myorder"; const r1 = parsePayUri(url1); if (!r1) { @@ -107,29 +107,29 @@ test("taler pay uri parsing: complex path prefix and instance", t => { t.is(r1.orderId, "myorder"); }); -test("taler refund uri parsing: non-https #1", t => { +test("taler refund uri parsing: non-https #1", (t) => { const url1 = "taler://refund/example.com/-/-/myorder?insecure=1"; const r1 = parseRefundUri(url1); if (!r1) { t.fail(); return; - } + } t.is(r1.merchantBaseUrl, "http://example.com/public/"); - t.is(r1.orderId, "myorder") + t.is(r1.orderId, "myorder"); }); -test("taler pay uri parsing: non-https #1", t => { +test("taler pay uri parsing: non-https #1", (t) => { const url1 = "taler://pay/example.com/-/-/myorder?insecure=1"; const r1 = parsePayUri(url1); if (!r1) { t.fail(); return; - } + } t.is(r1.merchantBaseUrl, "http://example.com/public/"); - t.is(r1.orderId, "myorder") + t.is(r1.orderId, "myorder"); }); -test("taler pay url parsing: non-https #2", t => { +test("taler pay url parsing: non-https #2", (t) => { const url1 = "taler://pay/example.com/-/-/myorder?insecure=2"; const r1 = parsePayUri(url1); if (!r1) { @@ -140,7 +140,7 @@ test("taler pay url parsing: non-https #2", t => { t.is(r1.orderId, "myorder"); }); -test("taler withdraw uri parsing", t => { +test("taler withdraw uri parsing", (t) => { const url1 = "taler://withdraw/bank.example.com/-/12345"; const r1 = parseWithdrawUri(url1); if (!r1) { @@ -150,7 +150,7 @@ test("taler withdraw uri parsing", t => { t.is(r1.statusUrl, "https://bank.example.com/api/withdraw-operation/12345"); }); -test("taler refund uri parsing", t => { +test("taler refund uri parsing", (t) => { const url1 = "taler://refund/merchant.example.com/-/-/1234"; const r1 = parseRefundUri(url1); if (!r1) { @@ -161,7 +161,7 @@ test("taler refund uri parsing", t => { t.is(r1.orderId, "1234"); }); -test("taler refund uri parsing with instance", t => { +test("taler refund uri parsing with instance", (t) => { const url1 = "taler://refund/merchant.example.com/-/myinst/1234"; const r1 = parseRefundUri(url1); if (!r1) { @@ -169,23 +169,23 @@ test("taler refund uri parsing with instance", t => { return; } t.is(r1.orderId, "1234"); - t.is(r1.merchantBaseUrl, "https://merchant.example.com/public/instances/myinst/"); + t.is( + r1.merchantBaseUrl, + "https://merchant.example.com/public/instances/myinst/", + ); }); -test("taler tip pickup uri", t => { +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/public/", - ); + t.is(r1.merchantBaseUrl, "https://merchant.example.com/public/"); }); -test("taler tip pickup uri with instance", t => { +test("taler tip pickup uri with instance", (t) => { const url1 = "taler://tip/merchant.example.com/-/tipm/tipid"; const r1 = parseTipUri(url1); if (!r1) { @@ -199,7 +199,7 @@ test("taler tip pickup uri with instance", t => { t.is(r1.merchantTipId, "tipid"); }); -test("taler tip pickup uri with instance and prefix", t => { +test("taler tip pickup uri with instance and prefix", (t) => { const url1 = "taler://tip/merchant.example.com/my%2fpfx/tipm/tipid"; const r1 = parseTipUri(url1); if (!r1) { diff --git a/src/util/time.ts b/src/util/time.ts index 2740c361f..138ecb876 100644 --- a/src/util/time.ts +++ b/src/util/time.ts @@ -138,7 +138,11 @@ export function timestampDifference(t1: Timestamp, t2: Timestamp): Duration { return { d_ms: Math.abs(t1.t_ms - t2.t_ms) }; } -export function timestampIsBetween(t: Timestamp, start: Timestamp, end: Timestamp) { +export function timestampIsBetween( + t: Timestamp, + start: Timestamp, + end: Timestamp, +) { if (timestampCmp(t, start) < 0) { return false; } diff --git a/src/util/timer.ts b/src/util/timer.ts index 000f36608..8706c939e 100644 --- a/src/util/timer.ts +++ b/src/util/timer.ts @@ -31,8 +31,7 @@ export interface TimerHandle { } class IntervalHandle { - constructor(public h: any) { - } + constructor(public h: any) {} clear() { clearInterval(this.h); @@ -40,8 +39,7 @@ class IntervalHandle { } class TimeoutHandle { - constructor(public h: any) { - } + constructor(public h: any) {} clear() { clearTimeout(this.h); @@ -78,7 +76,6 @@ export function after(delayMs: number, callback: () => void): TimerHandle { return new TimeoutHandle(setTimeout(callback, delayMs)); } - const nullTimerHandle = { clear() { // do nothing diff --git a/src/util/wire.ts b/src/util/wire.ts index 757ba9266..21ad600fc 100644 --- a/src/util/wire.ts +++ b/src/util/wire.ts @@ -14,7 +14,6 @@ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ - /** * Display and manipulate wire information. * @@ -50,4 +49,3 @@ export function summarizeWire(w: any): string { return i18n.str`Unknown Wire Detail`; } } - diff --git a/src/wallet.ts b/src/wallet.ts index 810b724e7..2560b0dc3 100644 --- a/src/wallet.ts +++ b/src/wallet.ts @@ -640,7 +640,9 @@ export class Wallet { * Accept a refund, return the contract hash for the contract * that was involved in the refund. */ - async applyRefund(talerRefundUri: string): Promise<{ contractTermsHash: string }> { + async applyRefund( + talerRefundUri: string, + ): Promise<{ contractTermsHash: string }> { return applyRefund(this.ws, talerRefundUri); } diff --git a/src/webex/background.html b/src/webex/background.html index 0535dd5f3..12a962c67 100644 --- a/src/webex/background.html +++ b/src/webex/background.html @@ -1,11 +1,11 @@ <!DOCTYPE html> <html lang="en"> -<head> - <meta charset="UTF-8"> - <script src="../../dist/background-bundle.js"></script> - <title>(wallet bg page)</title> -</head> -<body> - <img id="taler-logo" src="/img/icon.png"> -</body> + <head> + <meta charset="UTF-8" /> + <script src="../../dist/background-bundle.js"></script> + <title>(wallet bg page)</title> + </head> + <body> + <img id="taler-logo" src="/img/icon.png" /> + </body> </html> diff --git a/src/webex/chromeBadge.ts b/src/webex/chromeBadge.ts index e6b21ad91..cdd99f8c1 100644 --- a/src/webex/chromeBadge.ts +++ b/src/webex/chromeBadge.ts @@ -14,10 +14,8 @@ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ - import { isFirefox } from "./compat"; - /** * Polyfill for requestAnimationFrame, which * doesn't work from a background page. @@ -28,7 +26,6 @@ function rAF(cb: (ts: number) => void) { }, 100 /* 100 ms delay between frames */); } - /** * Badge for Chrome that renders a Taler logo with a rotating ring if some * background activity is happening. @@ -139,16 +136,27 @@ export class ChromeBadge { if (this.animationRunning) { /* Draw circle around the "T" with an opening of this.gapWidth */ const aMax = ChromeBadge.rotationAngleMax; - const startAngle = this.rotationAngle / aMax * Math.PI * 2; - const stopAngle = ((this.rotationAngle + aMax - this.gapWidth) / aMax) * Math.PI * 2; - this.ctx.arc(0, 0, this.canvas.width / 2 - 2, /* radius */ startAngle, stopAngle, false); + const startAngle = (this.rotationAngle / aMax) * Math.PI * 2; + const stopAngle = + ((this.rotationAngle + aMax - this.gapWidth) / aMax) * Math.PI * 2; + this.ctx.arc( + 0, + 0, + this.canvas.width / 2 - 2, + /* radius */ startAngle, + stopAngle, + false, + ); } else { /* Draw full circle */ - this.ctx.arc(0, 0, - this.canvas.width / 2 - 2, /* radius */ - 0, - Math.PI * 2, - false); + this.ctx.arc( + 0, + 0, + this.canvas.width / 2 - 2 /* radius */, + 0, + Math.PI * 2, + false, + ); } this.ctx.stroke(); // go back to the origin @@ -162,7 +170,14 @@ export class ChromeBadge { const ch = this.canvas.height; this.ctx.beginPath(); this.ctx.arc(cw - r, ch - r, r, 0, 2 * Math.PI, false); - const gradient = this.ctx.createRadialGradient(cw - r, ch - r, r, cw - r, ch - r, 5); + const gradient = this.ctx.createRadialGradient( + cw - r, + ch - r, + r, + cw - r, + ch - r, + 5, + ); gradient.addColorStop(0, "rgba(255, 255, 255, 1)"); gradient.addColorStop(1, "blue"); this.ctx.fillStyle = gradient; @@ -173,11 +188,13 @@ export class ChromeBadge { // tslint:disable-next-line:no-string-literal if (window["chrome"] && window.chrome["browserAction"]) { try { - const imageData = this.ctx.getImageData(0, - 0, - this.canvas.width, - this.canvas.height); - chrome.browserAction.setIcon({imageData}); + const imageData = this.ctx.getImageData( + 0, + 0, + this.canvas.width, + this.canvas.height, + ); + chrome.browserAction.setIcon({ imageData }); } catch (e) { // Might fail if browser has over-eager canvas fingerprinting countermeasures. // There's nothing we can do then ... @@ -194,7 +211,7 @@ export class ChromeBadge { return; } this.animationRunning = true; - let start: number|undefined; + let start: number | undefined; const step = (timestamp: number) => { if (!this.animationRunning) { return; @@ -206,8 +223,10 @@ export class ChromeBadge { // stop if we're close enough to origin this.rotationAngle = 0; } else { - this.rotationAngle = (this.rotationAngle + (timestamp - start) * - ChromeBadge.rotationSpeed) % ChromeBadge.rotationAngleMax; + this.rotationAngle = + (this.rotationAngle + + (timestamp - start) * ChromeBadge.rotationSpeed) % + ChromeBadge.rotationAngleMax; } if (this.isBusy) { if (this.gapWidth < ChromeBadge.openMax) { diff --git a/src/webex/compat.ts b/src/webex/compat.ts index 121c58e7f..f1a68f33e 100644 --- a/src/webex/compat.ts +++ b/src/webex/compat.ts @@ -20,16 +20,16 @@ */ export function isFirefox(): boolean { - const rt = chrome.runtime as any; - if (typeof rt.getBrowserInfo === "function") { - return true; - } - return false; + const rt = chrome.runtime as any; + if (typeof rt.getBrowserInfo === "function") { + return true; + } + return false; } /** * Check if we are running under nodejs. */ export function isNode() { - return (typeof process !== 'undefined') && (process.release.name === 'node') -}
\ No newline at end of file + return typeof process !== "undefined" && process.release.name === "node"; +} diff --git a/src/webex/i18n.tsx b/src/webex/i18n.tsx index 3923654e7..2e753e441 100644 --- a/src/webex/i18n.tsx +++ b/src/webex/i18n.tsx @@ -21,19 +21,17 @@ /** * Imports. */ -import {strings} from "../i18n/strings"; +import { strings } from "../i18n/strings"; // @ts-ignore: no type decl for this library import * as jedLib from "jed"; import * as React from "react"; - const jed = setupJed(); let enableTracing = false; - /** * Set up jed library for internationalization, * based on browser language settings. @@ -56,7 +54,6 @@ function setupJed(): any { return new jedLib.Jed(strings[lang]); } - /** * Convert template strings to a msgid */ @@ -71,22 +68,22 @@ function toI18nString(stringSeq: ReadonlyArray<string>) { return s; } - /** * Internationalize a string template with arbitrary serialized values. */ export function str(stringSeq: TemplateStringsArray, ...values: any[]) { const s = toI18nString(stringSeq); - const tr = jed.translate(s).ifPlural(1, s).fetch(...values); + const tr = jed + .translate(s) + .ifPlural(1, s) + .fetch(...values); return tr; } - interface TranslateSwitchProps { target: number; } - function stringifyChildren(children: any): string { let n = 1; const ss = React.Children.map(children, (c) => { @@ -100,7 +97,6 @@ function stringifyChildren(children: any): string { return s; } - interface TranslateProps { /** * Component that the translated element should be wrapped in. @@ -114,7 +110,6 @@ interface TranslateProps { wrapProps?: any; } - /** * Translate text node children of this component. * If a child component might produce a text node, it must be wrapped @@ -130,11 +125,19 @@ interface TranslateProps { export class Translate extends React.Component<TranslateProps, {}> { render(): JSX.Element { const s = stringifyChildren(this.props.children); - const tr = jed.ngettext(s, s, 1).split(/%(\d+)\$s/).filter((e: any, i: number) => i % 2 === 0); + const tr = jed + .ngettext(s, s, 1) + .split(/%(\d+)\$s/) + .filter((e: any, i: number) => i % 2 === 0); const childArray = React.Children.toArray(this.props.children!); for (let i = 0; i < childArray.length - 1; ++i) { - if ((typeof childArray[i]) === "string" && (typeof childArray[i + 1]) === "string") { - childArray[i + 1] = (childArray[i] as string).concat(childArray[i + 1] as string); + if ( + typeof childArray[i] === "string" && + typeof childArray[i + 1] === "string" + ) { + childArray[i + 1] = (childArray[i] as string).concat( + childArray[i + 1] as string, + ); childArray.splice(i, 1); } } @@ -158,7 +161,6 @@ export class Translate extends React.Component<TranslateProps, {}> { } } - /** * Switch translation based on singular or plural based on the target prop. * Should only contain TranslateSingular and TransplatePlural as children. @@ -171,7 +173,10 @@ export class Translate extends React.Component<TranslateProps, {}> { * </TranslateSwitch> * ``` */ -export class TranslateSwitch extends React.Component<TranslateSwitchProps, void> { +export class TranslateSwitch extends React.Component< + TranslateSwitchProps, + void +> { render(): JSX.Element { let singular: React.ReactElement<TranslationPluralProps> | undefined; let plural: React.ReactElement<TranslationPluralProps> | undefined; @@ -186,7 +191,7 @@ export class TranslateSwitch extends React.Component<TranslateSwitchProps, void> } }); } - if ((!singular) || (!plural)) { + if (!singular || !plural) { console.error("translation not found"); return React.createElement("span", {}, ["translation not found"]); } @@ -198,7 +203,6 @@ export class TranslateSwitch extends React.Component<TranslateSwitchProps, void> } } - interface TranslationPluralProps { target: number; } @@ -206,14 +210,24 @@ interface TranslationPluralProps { /** * See [[TranslateSwitch]]. */ -export class TranslatePlural extends React.Component<TranslationPluralProps, void> { +export class TranslatePlural extends React.Component< + TranslationPluralProps, + void +> { render(): JSX.Element { const s = stringifyChildren(this.props.children); - const tr = jed.ngettext(s, s, 1).split(/%(\d+)\$s/).filter((e: any, i: number) => i % 2 === 0); + const tr = jed + .ngettext(s, s, 1) + .split(/%(\d+)\$s/) + .filter((e: any, i: number) => i % 2 === 0); const childArray = React.Children.toArray(this.props.children!); for (let i = 0; i < childArray.length - 1; ++i) { - if ((typeof childArray[i]) === "string" && (typeof childArray[i + 1]) === "string") { - childArray[i + i] = childArray[i] as string + childArray[i + 1] as string; + if ( + typeof childArray[i] === "string" && + typeof childArray[i + 1] === "string" + ) { + childArray[i + i] = ((childArray[i] as string) + + childArray[i + 1]) as string; childArray.splice(i, 1); } } @@ -234,18 +248,27 @@ export class TranslatePlural extends React.Component<TranslationPluralProps, voi } } - /** * See [[TranslateSwitch]]. */ -export class TranslateSingular extends React.Component<TranslationPluralProps, void> { +export class TranslateSingular extends React.Component< + TranslationPluralProps, + void +> { render(): JSX.Element { const s = stringifyChildren(this.props.children); - const tr = jed.ngettext(s, s, 1).split(/%(\d+)\$s/).filter((e: any, i: number) => i % 2 === 0); + const tr = jed + .ngettext(s, s, 1) + .split(/%(\d+)\$s/) + .filter((e: any, i: number) => i % 2 === 0); const childArray = React.Children.toArray(this.props.children!); for (let i = 0; i < childArray.length - 1; ++i) { - if ((typeof childArray[i]) === "string" && (typeof childArray[i + 1]) === "string") { - childArray[i + i] = childArray[i] as string + childArray[i + 1] as string; + if ( + typeof childArray[i] === "string" && + typeof childArray[i + 1] === "string" + ) { + childArray[i + i] = ((childArray[i] as string) + + childArray[i + 1]) as string; childArray.splice(i, 1); } } diff --git a/src/webex/messages.ts b/src/webex/messages.ts index 7672fcb4b..b695b4ab6 100644 --- a/src/webex/messages.ts +++ b/src/webex/messages.ts @@ -147,7 +147,10 @@ export interface MessageMap { response: walletTypes.BenchmarkResult; }; "get-withdraw-details": { - request: { talerWithdrawUri: string; maybeSelectedExchange: string | undefined }; + request: { + talerWithdrawUri: string; + maybeSelectedExchange: string | undefined; + }; response: walletTypes.WithdrawDetails; }; "accept-withdrawal": { @@ -159,12 +162,11 @@ export interface MessageMap { response: walletTypes.PreparePayResult; }; "get-diagnostics": { - request: { }; + request: {}; response: walletTypes.WalletDiagnostics; }; } - /** * String literal types for messages. */ diff --git a/src/webex/notify.ts b/src/webex/notify.ts index 61a96cb1b..910a20999 100644 --- a/src/webex/notify.ts +++ b/src/webex/notify.ts @@ -41,18 +41,17 @@ if (document.documentElement.getAttribute("data-taler-nojs")) { interface Handler { type: string; - listener: (e: Event) => void|Promise<void>; + listener: (e: Event) => void | Promise<void>; } const handlers: Handler[] = []; - -let sheet: CSSStyleSheet|null; +let sheet: CSSStyleSheet | null; function initStyle() { logVerbose && console.log("taking over styles"); const name = "taler-presence-stylesheet"; const content = "/* Taler stylesheet controlled by JS */"; - let style = document.getElementById(name) as HTMLStyleElement|null; + let style = document.getElementById(name) as HTMLStyleElement | null; if (!style) { style = document.createElement("style"); // Needed by WebKit @@ -68,7 +67,9 @@ function initStyle() { style.innerText = content; } if (!style.sheet) { - throw Error("taler-presence-stylesheet should be a style sheet (<link> or <style>)"); + throw Error( + "taler-presence-stylesheet should be a style sheet (<link> or <style>)", + ); } sheet = style.sheet as CSSStyleSheet; while (sheet.cssRules.length > 0) { @@ -77,7 +78,6 @@ function initStyle() { } } - function setStyles(installed: boolean) { if (!sheet || !sheet.cssRules) { return; @@ -93,7 +93,6 @@ function setStyles(installed: boolean) { } } - function onceOnComplete(cb: () => void) { if (document.readyState === "complete") { cb(); @@ -106,7 +105,6 @@ function onceOnComplete(cb: () => void) { } } - function init() { onceOnComplete(() => { if (document.documentElement.getAttribute("data-taler-nojs")) { @@ -131,7 +129,6 @@ function init() { type HandlerFn = (detail: any, sendResponse: (msg: any) => void) => void; - function registerHandlers() { /** * Add a handler for a DOM event, which automatically @@ -149,12 +146,16 @@ function registerHandlers() { } let callId: number | undefined; let detail; - if ((e instanceof CustomEvent) && e.detail && e.detail.callId !== undefined) { + if ( + e instanceof CustomEvent && + e.detail && + e.detail.callId !== undefined + ) { callId = e.detail.callId; detail = e.detail; } const responder = (msg?: any) => { - const fullMsg = Object.assign({}, msg, {callId}); + const fullMsg = Object.assign({}, msg, { callId }); let opts = { detail: fullMsg }; if ("function" === typeof cloneInto) { opts = cloneInto(opts, document.defaultView); @@ -165,7 +166,7 @@ function registerHandlers() { handler(detail, responder); }; document.addEventListener(type, handlerWrap); - handlers.push({type, listener: handlerWrap}); + handlers.push({ type, listener: handlerWrap }); } addHandler("taler-query-id", (msg: any, sendResponse: any) => { @@ -178,25 +179,34 @@ function registerHandlers() { }); addHandler("taler-create-reserve", (msg: any) => { - const uri = new URL(chrome.extension.getURL("/src/webex/pages/confirm-create-reserve.html")); + const uri = new URL( + chrome.extension.getURL("/src/webex/pages/confirm-create-reserve.html"), + ); uri.searchParams.set("amount", JSON.stringify(msg.amount)); uri.searchParams.set("bank_url", document.location.href); - uri.searchParams.set("callback_url", new URL(msg.callback_url, document.location.href).href); + uri.searchParams.set( + "callback_url", + new URL(msg.callback_url, document.location.href).href, + ); uri.searchParams.set("suggested_exchange_url", msg.suggested_exchange_url); uri.searchParams.set("wt_types", JSON.stringify(msg.wt_types)); window.location.href = uri.href; }); addHandler("taler-add-auditor", (msg: any) => { - const uri = new URL(chrome.extension.getURL("/src/webex/pages/add-auditor.html")); - uri.searchParams.set("req", JSON.stringify(msg)) + const uri = new URL( + chrome.extension.getURL("/src/webex/pages/add-auditor.html"), + ); + uri.searchParams.set("req", JSON.stringify(msg)); window.location.href = uri.href; }); addHandler("taler-confirm-reserve", async (msg: any, sendResponse: any) => { const reservePub = msg.reserve_pub; if (typeof reservePub !== "string") { - console.error("taler-confirm-reserve expects parameter reserve_pub of type 'string'"); + console.error( + "taler-confirm-reserve expects parameter reserve_pub of type 'string'", + ); return; } await wxApi.confirmReserve(msg.reserve_pub); diff --git a/src/webex/pages/add-auditor.html b/src/webex/pages/add-auditor.html index b7a9d041d..7f30b5fb6 100644 --- a/src/webex/pages/add-auditor.html +++ b/src/webex/pages/add-auditor.html @@ -1,32 +1,32 @@ <!DOCTYPE html> <html> + <head> + <meta charset="UTF-8" /> -<head> - <meta charset="UTF-8"> + <title>Taler Wallet: Add Auditor</title> - <title>Taler Wallet: Add Auditor</title> + <link rel="stylesheet" type="text/css" href="../style/wallet.css" /> - <link rel="stylesheet" type="text/css" href="../style/wallet.css"> + <link rel="icon" href="/img/icon.png" /> - <link rel="icon" href="/img/icon.png"> + <script src="/dist/page-common-bundle.js"></script> + <script src="/dist/add-auditor-bundle.js"></script> - <script src="/dist/page-common-bundle.js"></script> - <script src="/dist/add-auditor-bundle.js"></script> - - <style> - .tree-item { - margin: 2em; - border-radius: 5px; - border: 1px solid gray; - padding: 1em; - } - .button-linky { - background: none; - color: black; - text-decoration: underline; - border: none; - } - </style> + <style> + .tree-item { + margin: 2em; + border-radius: 5px; + border: 1px solid gray; + padding: 1em; + } + .button-linky { + background: none; + color: black; + text-decoration: underline; + border: none; + } + </style> + </head> <body> <div id="container"></div> diff --git a/src/webex/pages/add-auditor.tsx b/src/webex/pages/add-auditor.tsx index 0f681aae4..5840f4d63 100644 --- a/src/webex/pages/add-auditor.tsx +++ b/src/webex/pages/add-auditor.tsx @@ -35,8 +35,7 @@ interface ConfirmAuditorProps { function ConfirmAuditor(props: ConfirmAuditorProps) { const [addDone, setAddDone] = useState(false); - - const add = async() => { + const add = async () => { const currencies = await getCurrencies(); let currency: CurrencyRecord | undefined; @@ -78,7 +77,7 @@ function ConfirmAuditor(props: ConfirmAuditorProps) { await updateCurrency(currency); setAddDone(true); - } + }; const back = () => { window.history.back(); @@ -115,7 +114,6 @@ function ConfirmAuditor(props: ConfirmAuditorProps) { ); } - registerMountPage(() => { const walletPageUrl = new URL(document.location.href); const url = walletPageUrl.searchParams.get("url"); @@ -136,5 +134,5 @@ registerMountPage(() => { } const expirationStamp = Number.parseInt(auditorStampStr); const args = { url, currency, auditorPub, expirationStamp }; - return <ConfirmAuditor {...args}/>; + return <ConfirmAuditor {...args} />; }); diff --git a/src/webex/pages/auditors.html b/src/webex/pages/auditors.html index cbfc3b4b5..7c207f750 100644 --- a/src/webex/pages/auditors.html +++ b/src/webex/pages/auditors.html @@ -1,34 +1,34 @@ <!DOCTYPE html> <html> + <head> + <meta charset="UTF-8" /> + <title>Taler Wallet: Auditors</title> -<head> - <meta charset="UTF-8"> - <title>Taler Wallet: Auditors</title> + <link rel="stylesheet" type="text/css" href="../style/wallet.css" /> - <link rel="stylesheet" type="text/css" href="../style/wallet.css"> + <link rel="icon" href="/img/icon.png" /> - <link rel="icon" href="/img/icon.png"> + <script src="/dist/page-common-bundle.js"></script> + <script src="/dist/auditors-bundle.js"></script> - <script src="/dist/page-common-bundle.js"></script> - <script src="/dist/auditors-bundle.js"></script> - - <style> - body { - font-size: 100%; - } - .tree-item { - margin: 2em; - border-radius: 5px; - border: 1px solid gray; - padding: 1em; - } - .button-linky { - background: none; - color: black; - text-decoration: underline; - border: none; - } - </style> + <style> + body { + font-size: 100%; + } + .tree-item { + margin: 2em; + border-radius: 5px; + border: 1px solid gray; + padding: 1em; + } + .button-linky { + background: none; + color: black; + text-decoration: underline; + border: none; + } + </style> + </head> <body> <div id="container"></div> diff --git a/src/webex/pages/auditors.tsx b/src/webex/pages/auditors.tsx index 876cf326b..e2bb29af1 100644 --- a/src/webex/pages/auditors.tsx +++ b/src/webex/pages/auditors.tsx @@ -20,17 +20,13 @@ * @author Florian Dold */ - import { AuditorRecord, CurrencyRecord, ExchangeForCurrencyRecord, } from "../../types/dbTypes"; -import { - getCurrencies, - updateCurrency, -} from "../wxApi"; +import { getCurrencies, updateCurrency } from "../wxApi"; import * as React from "react"; import * as ReactDOM from "react-dom"; @@ -60,14 +56,22 @@ class CurrencyList extends React.Component<{}, CurrencyListState> { } async confirmRemoveAuditor(c: CurrencyRecord, a: AuditorRecord) { - if (window.confirm(`Do you really want to remove auditor ${a.baseUrl} for currency ${c.name}?`)) { + if ( + window.confirm( + `Do you really want to remove auditor ${a.baseUrl} for currency ${c.name}?`, + ) + ) { c.auditors = c.auditors.filter((x) => x.auditorPub !== a.auditorPub); await updateCurrency(c); } } async confirmRemoveExchange(c: CurrencyRecord, e: ExchangeForCurrencyRecord) { - if (window.confirm(`Do you really want to remove exchange ${e.baseUrl} for currency ${c.name}?`)) { + if ( + window.confirm( + `Do you really want to remove exchange ${e.baseUrl} for currency ${c.name}?`, + ) + ) { c.exchanges = c.exchanges.filter((x) => x.baseUrl !== e.baseUrl); await updateCurrency(c); } @@ -81,18 +85,21 @@ class CurrencyList extends React.Component<{}, CurrencyListState> { <div> <p>Trusted Auditors:</p> <ul> - {c.auditors.map((a) => ( - <li> - {a.baseUrl}{" "} - <button className="pure-button button-destructive" onClick={() => this.confirmRemoveAuditor(c, a)}> - Remove - </button> - <ul> - <li>valid until {new Date(a.expirationStamp).toString()}</li> - <li>public key {a.auditorPub}</li> - </ul> - </li> - ))} + {c.auditors.map((a) => ( + <li> + {a.baseUrl}{" "} + <button + className="pure-button button-destructive" + onClick={() => this.confirmRemoveAuditor(c, a)} + > + Remove + </button> + <ul> + <li>valid until {new Date(a.expirationStamp).toString()}</li> + <li>public key {a.auditorPub}</li> + </ul> + </li> + ))} </ul> </div> ); @@ -106,14 +113,17 @@ class CurrencyList extends React.Component<{}, CurrencyListState> { <div> <p>Trusted Exchanges:</p> <ul> - {c.exchanges.map((e) => ( - <li> - {e.baseUrl}{" "} - <button className="pure-button button-destructive" onClick={() => this.confirmRemoveExchange(c, e)}> - Remove - </button> - </li> - ))} + {c.exchanges.map((e) => ( + <li> + {e.baseUrl}{" "} + <button + className="pure-button button-destructive" + onClick={() => this.confirmRemoveExchange(c, e)} + > + Remove + </button> + </li> + ))} </ul> </div> ); @@ -126,16 +136,16 @@ class CurrencyList extends React.Component<{}, CurrencyListState> { } return ( <div id="main"> - {currencies.map((c) => ( - <div> - <h1>Currency {c.name}</h1> - <p>Displayed with {c.fractionalDigits} fractional digits.</p> - <h2>Auditors</h2> - <div>{this.renderAuditors(c)}</div> - <h2>Exchanges</h2> - <div>{this.renderExchanges(c)}</div> - </div> - ))} + {currencies.map((c) => ( + <div> + <h1>Currency {c.name}</h1> + <p>Displayed with {c.fractionalDigits} fractional digits.</p> + <h2>Auditors</h2> + <div>{this.renderAuditors(c)}</div> + <h2>Exchanges</h2> + <div>{this.renderExchanges(c)}</div> + </div> + ))} </div> ); } diff --git a/src/webex/pages/benchmark.html b/src/webex/pages/benchmark.html index a593d1e37..d4216ecad 100644 --- a/src/webex/pages/benchmark.html +++ b/src/webex/pages/benchmark.html @@ -1,17 +1,17 @@ -<!doctype html> +<!DOCTYPE html> <html> <head> - <meta charset="UTF-8"> + <meta charset="UTF-8" /> <title>Taler Wallet: Benchmarks</title> - <link rel="stylesheet" type="text/css" href="../style/wallet.css"> - <link rel="icon" href="/img/icon.png"> + <link rel="stylesheet" type="text/css" href="../style/wallet.css" /> + <link rel="icon" href="/img/icon.png" /> <script src="/dist/page-common-bundle.js"></script> <script src="/dist/benchmark-bundle.js"></script> </head> <body> - <section id="main"> - <h1>Benchmarks</h1> - <div id="container"></div> - </section> + <section id="main"> + <h1>Benchmarks</h1> + <div id="container"></div> + </section> </body> </html> diff --git a/src/webex/pages/benchmark.tsx b/src/webex/pages/benchmark.tsx index fe874f2b7..7de546bb0 100644 --- a/src/webex/pages/benchmark.tsx +++ b/src/webex/pages/benchmark.tsx @@ -14,7 +14,6 @@ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ - /** * Benchmarks for the wallet. * @@ -31,14 +30,12 @@ import * as React from "react"; import * as ReactDOM from "react-dom"; import { registerMountPage } from "../renderHtml"; - interface BenchmarkRunnerState { repetitions: number; result?: BenchmarkResult; running: boolean; } - function BenchmarkDisplay(props: BenchmarkRunnerState) { const result = props.result; if (!result) { @@ -50,24 +47,23 @@ function BenchmarkDisplay(props: BenchmarkRunnerState) { } return ( <> - <h2>Results for {result.repetitions} repetitions</h2> - <table className="pure-table"> - <thead> - <tr> - <th>{i18n.str`Operation`}</th> - <th>{i18n.str`time (ms/op)`}</th> - </tr> - { - Object.keys(result.time).sort().map( - k => - <tr> - <td>{k}</td> - <td>{result.time[k] / result.repetitions}</td> - </tr> - ) - } - </thead> - </table> + <h2>Results for {result.repetitions} repetitions</h2> + <table className="pure-table"> + <thead> + <tr> + <th>{i18n.str`Operation`}</th> + <th>{i18n.str`time (ms/op)`}</th> + </tr> + {Object.keys(result.time) + .sort() + .map((k) => ( + <tr> + <td>{k}</td> + <td>{result.time[k] / result.repetitions}</td> + </tr> + ))} + </thead> + </table> </> ); } @@ -91,10 +87,13 @@ class BenchmarkRunner extends React.Component<any, BenchmarkRunnerState> { return ( <div> <label>Repetitions:</label> - <input type="number" - value={this.state.repetitions} - onChange={(evt) => this.setState({ repetitions: Number.parseInt(evt.target.value) })} /> - {" "} + <input + type="number" + value={this.state.repetitions} + onChange={(evt) => + this.setState({ repetitions: Number.parseInt(evt.target.value) }) + } + />{" "} <button onClick={() => this.run()}>Run</button> <BenchmarkDisplay {...this.state} /> </div> diff --git a/src/webex/pages/pay.html b/src/webex/pages/pay.html index 20605ac49..6afc95615 100644 --- a/src/webex/pages/pay.html +++ b/src/webex/pages/pay.html @@ -1,79 +1,76 @@ <!DOCTYPE html> <html> + <head> + <meta charset="UTF-8" /> + <title>Taler Wallet: Confirm Contract</title> -<head> - <meta charset="UTF-8"> - <title>Taler Wallet: Confirm Contract</title> + <link rel="stylesheet" type="text/css" href="../style/pure.css" /> + <link rel="stylesheet" type="text/css" href="../style/wallet.css" /> - <link rel="stylesheet" type="text/css" href="../style/pure.css"> - <link rel="stylesheet" type="text/css" href="../style/wallet.css"> + <link rel="icon" href="/img/icon.png" /> - <link rel="icon" href="/img/icon.png"> + <script src="/dist/page-common-bundle.js"></script> + <script src="/dist/pay-bundle.js"></script> - <script src="/dist/page-common-bundle.js"></script> - <script src="/dist/pay-bundle.js"></script> + <style> + button.accept { + background-color: #5757d2; + border: 1px solid black; + border-radius: 5px; + margin: 1em 0; + padding: 0.5em; + font-weight: bold; + color: white; + } + button.linky { + background: none !important; + border: none; + padding: 0 !important; - <style> - button.accept { - background-color: #5757D2; - border: 1px solid black; - border-radius: 5px; - margin: 1em 0; - padding: 0.5em; - font-weight: bold; - color: white; - } - button.linky { - background:none!important; - border:none; - padding:0!important; + font-family: arial, sans-serif; + color: #069; + text-decoration: underline; + cursor: pointer; + } - font-family:arial,sans-serif; - color:#069; - text-decoration:underline; - cursor:pointer; - } + input.url { + width: 25em; + } - input.url { - width: 25em; - } + button.accept:disabled { + background-color: #dedbe8; + border: 1px solid white; + border-radius: 5px; + margin: 1em 0; + padding: 0.5em; + font-weight: bold; + color: #2c2c2c; + } + .errorbox { + border: 1px solid; + display: inline-block; + margin: 1em; + padding: 1em; + font-weight: bold; + background: #ff8a8a; + } - button.accept:disabled { - background-color: #dedbe8; - border: 1px solid white; - border-radius: 5px; - margin: 1em 0; - padding: 0.5em; - font-weight: bold; - color: #2C2C2C; - } - - .errorbox { - border: 1px solid; - display: inline-block; - margin: 1em; - padding: 1em; - font-weight: bold; - background: #FF8A8A; - } - - .okaybox { - border: 1px solid; - display: inline-block; - margin: 1em; - padding: 1em; - font-weight: bold; - background: #00FA9A; - } - </style> -</head> - -<body> - <section id="main"> - <h1>GNU Taler Wallet</h1> - <article id="container" class="fade"></article> - </section> -</body> + .okaybox { + border: 1px solid; + display: inline-block; + margin: 1em; + padding: 1em; + font-weight: bold; + background: #00fa9a; + } + </style> + </head> + <body> + <section id="main"> + <h1>GNU Taler Wallet</h1> + <article id="container" class="fade"></article> + </section> + </body> </html> diff --git a/src/webex/pages/pay.tsx b/src/webex/pages/pay.tsx index 7f36cb66e..714e3b0a3 100644 --- a/src/webex/pages/pay.tsx +++ b/src/webex/pages/pay.tsx @@ -78,17 +78,15 @@ function TalerPayDialog({ talerPayUri }: { talerPayUri: string }) { let contractTerms: ContractTerms; try { - contractTerms = codecForContractTerms().decode(JSON.parse(payStatus.contractTermsRaw)); + contractTerms = codecForContractTerms().decode( + JSON.parse(payStatus.contractTermsRaw), + ); } catch (e) { // This should never happen, as the wallet is supposed to check the contract terms // before storing them. console.error(e); console.log("raw contract terms were", payStatus.contractTermsRaw); - return ( - <span> - Invalid contract terms. - </span> - ); + return <span>Invalid contract terms.</span>; } if (!contractTerms) { @@ -149,7 +147,9 @@ function TalerPayDialog({ talerPayUri }: { talerPayUri: string }) { {insufficientBalance ? ( <div> - <p style={{color: "red", fontWeight: "bold"}}>Unable to pay: Your balance is insufficient.</p> + <p style={{ color: "red", fontWeight: "bold" }}> + Unable to pay: Your balance is insufficient. + </p> </div> ) : null} @@ -168,7 +168,8 @@ function TalerPayDialog({ talerPayUri }: { talerPayUri: string }) { <ProgressButton loading={loading} disabled={insufficientBalance} - onClick={() => doPayment()}> + onClick={() => doPayment()} + > {i18n.str`Confirm payment`} </ProgressButton> </div> diff --git a/src/webex/pages/payback.html b/src/webex/pages/payback.html index d6fe334c8..706949544 100644 --- a/src/webex/pages/payback.html +++ b/src/webex/pages/payback.html @@ -1,34 +1,34 @@ <!DOCTYPE html> <html> + <head> + <meta charset="UTF-8" /> + <title>Taler Wallet: Payback</title> -<head> - <meta charset="UTF-8"> - <title>Taler Wallet: Payback</title> + <link rel="stylesheet" type="text/css" href="../style/wallet.css" /> - <link rel="stylesheet" type="text/css" href="../style/wallet.css"> + <link rel="icon" href="/img/icon.png" /> - <link rel="icon" href="/img/icon.png"> + <script src="/dist/page-common-bundle.js"></script> + <script src="/dist/payback-bundle.js"></script> - <script src="/dist/page-common-bundle.js"></script> - <script src="/dist/payback-bundle.js"></script> - - <style> - body { - font-size: 100%; - } - .tree-item { - margin: 2em; - border-radius: 5px; - border: 1px solid gray; - padding: 1em; - } - .button-linky { - background: none; - color: black; - text-decoration: underline; - border: none; - } - </style> + <style> + body { + font-size: 100%; + } + .tree-item { + margin: 2em; + border-radius: 5px; + border: 1px solid gray; + padding: 1em; + } + .button-linky { + background: none; + color: black; + text-decoration: underline; + border: none; + } + </style> + </head> <body> <div id="container"></div> diff --git a/src/webex/pages/popup.css b/src/webex/pages/popup.css index 4cae66177..cca002399 100644 --- a/src/webex/pages/popup.css +++ b/src/webex/pages/popup.css @@ -1,4 +1,3 @@ - /** * @author Gabor X. Toth * @author Marcello Stanisci @@ -6,182 +5,181 @@ */ body { - min-height: 20em; - width: 30em; - margin: 0; - padding: 0; - max-height: 800px; - overflow: hidden; - background-color: #f8faf7; - font-family: Arial, Helvetica, sans-serif; + min-height: 20em; + width: 30em; + margin: 0; + padding: 0; + max-height: 800px; + overflow: hidden; + background-color: #f8faf7; + font-family: Arial, Helvetica, sans-serif; } .nav { - background-color: #033; - padding: 0.5em 0; + background-color: #033; + padding: 0.5em 0; } .nav a { - color: #f8faf7; - padding: 0.7em 1.4em; - text-decoration: none; + color: #f8faf7; + padding: 0.7em 1.4em; + text-decoration: none; } .nav a.active { - background-color: #f8faf7; - color: #000; - font-weight: bold; + background-color: #f8faf7; + color: #000; + font-weight: bold; } - .container { - overflow-y: scroll; - max-height: 400px; + overflow-y: scroll; + max-height: 400px; } .abbrev { - text-decoration-style: dotted; + text-decoration-style: dotted; } #content { - padding: 1em; + padding: 1em; } - #wallet-table .amount { - text-align: right; + text-align: right; } .hidden { - display: none; + display: none; } #transactions-table th, #transactions-table td { - padding: 0.2em 0.5em; + padding: 0.2em 0.5em; } #reserve-create table { - width: 100%; + width: 100%; } #reserve-create table td.label { - width: 5em; + width: 5em; } #reserve-create table .input input[type="text"] { - width: 100%; + width: 100%; } .historyItem { - min-width: 380px; - display: flex; - flex-direction: row; - border-bottom: 1px solid #d9dbd8; - padding: 0.5em; - align-items: center; - } - - .historyItem .amount { - font-size: 110%; - font-weight: bold; - text-align: right; - } - - .historyDate, - .historyTitle, - .historyText, - .historySmall { - margin: 0.3em; - } - - .historyDate { - font-size: 90%; - color: slategray; - text-align: right; - } - - .historyLeft { - display: flex; - flex-direction: column; - text-align: right; - } - - .historyContent { - flex: 1; - } - - .historyTitle { - font-weight: 400; - } - - .historyText { - font-size: 90%; - } - - .historySmall { - font-size: 70%; - text-transform: uppercase; - } - - .historyAmount { - flex-grow: 1; - } - - .historyAmount .primary { - font-size: 100%; - } - - .historyAmount .secondary { - font-size: 80%; - } - - .historyAmount .positive { - color: #088; - } - - .historyAmount .positive:before { - content: "+"; - } - - .historyAmount .negative { - color: #800 - } - - .historyAmount .negative:before { - color: #800; - content: "-"; - } - .icon { - margin: 0 10px; - text-align: center; - width: 35px; - font-size: 20px; - border-radius: 50%; - background: #ccc; - color: #fff; - padding-top: 4px; - height: 30px; - } - - .option { - text-transform: uppercase; - text-align: right; - padding: 0.4em; - font-size: 0.9em; - } - - input[type=checkbox], input[type=radio] { - vertical-align: middle; - position: relative; - bottom: 1px; - } - - input[type=radio] { - bottom: 2px; - } - - .balance { - text-align: center; - padding-top: 2em; - }
\ No newline at end of file + min-width: 380px; + display: flex; + flex-direction: row; + border-bottom: 1px solid #d9dbd8; + padding: 0.5em; + align-items: center; +} + +.historyItem .amount { + font-size: 110%; + font-weight: bold; + text-align: right; +} + +.historyDate, +.historyTitle, +.historyText, +.historySmall { + margin: 0.3em; +} + +.historyDate { + font-size: 90%; + color: slategray; + text-align: right; +} + +.historyLeft { + display: flex; + flex-direction: column; + text-align: right; +} + +.historyContent { + flex: 1; +} + +.historyTitle { + font-weight: 400; +} + +.historyText { + font-size: 90%; +} + +.historySmall { + font-size: 70%; + text-transform: uppercase; +} + +.historyAmount { + flex-grow: 1; +} + +.historyAmount .primary { + font-size: 100%; +} + +.historyAmount .secondary { + font-size: 80%; +} + +.historyAmount .positive { + color: #088; +} + +.historyAmount .positive:before { + content: "+"; +} + +.historyAmount .negative { + color: #800; +} + +.historyAmount .negative:before { + color: #800; + content: "-"; +} +.icon { + margin: 0 10px; + text-align: center; + width: 35px; + font-size: 20px; + border-radius: 50%; + background: #ccc; + color: #fff; + padding-top: 4px; + height: 30px; +} + +.option { + text-transform: uppercase; + text-align: right; + padding: 0.4em; + font-size: 0.9em; +} + +input[type="checkbox"], +input[type="radio"] { + vertical-align: middle; + position: relative; + bottom: 1px; +} + +input[type="radio"] { + bottom: 2px; +} + +.balance { + text-align: center; + padding-top: 2em; +} diff --git a/src/webex/pages/popup.html b/src/webex/pages/popup.html index 7929da765..030641d60 100644 --- a/src/webex/pages/popup.html +++ b/src/webex/pages/popup.html @@ -1,18 +1,16 @@ <!DOCTYPE html> <html> + <head> + <meta charset="utf-8" /> -<head> - <meta charset="utf-8"> + <link rel="stylesheet" type="text/css" href="../style/wallet.css" /> + <link rel="stylesheet" type="text/css" href="popup.css" /> - <link rel="stylesheet" type="text/css" href="../style/wallet.css"> - <link rel="stylesheet" type="text/css" href="popup.css"> - - <script src="/dist/page-common-bundle.js"></script> - <script src="/dist/popup-bundle.js"></script> -</head> - -<body> - <div id="container" style="margin:0;padding:0"></div> -</body> + <script src="/dist/page-common-bundle.js"></script> + <script src="/dist/popup-bundle.js"></script> + </head> + <body> + <div id="container" style="margin: 0; padding: 0;"></div> + </body> </html> diff --git a/src/webex/pages/popup.tsx b/src/webex/pages/popup.tsx index 44f45f9db..7b20f2227 100644 --- a/src/webex/pages/popup.tsx +++ b/src/webex/pages/popup.tsx @@ -29,10 +29,7 @@ import * as i18n from "../i18n"; import { AmountJson } from "../../util/amounts"; import * as Amounts from "../../util/amounts"; -import { - WalletBalance, - WalletBalanceEntry, -} from "../../types/walletTypes"; +import { WalletBalance, WalletBalanceEntry } from "../../types/walletTypes"; import { abbrev, @@ -98,7 +95,7 @@ class Router extends React.Component<any, any> { console.log("rendering route", route); let defaultChild: React.ReactChild | null = null; let foundChild: React.ReactChild | null = null; - React.Children.forEach(this.props.children, child => { + React.Children.forEach(this.props.children, (child) => { const childProps: any = (child as any).props; if (!childProps) { return; @@ -188,7 +185,7 @@ function bigAmount(amount: AmountJson): JSX.Element { const v = amount.value + amount.fraction / Amounts.fractionalBase; return ( <span> - <span style={{ fontSize: "5em", display: 'block'}}>{v}</span>{" "} + <span style={{ fontSize: "5em", display: "block" }}>{v}</span>{" "} <span>{amount.currency}</span> </span> ); @@ -281,7 +278,7 @@ class WalletBalanceView extends React.Component<any, any> { ); } - const l = [incoming, payment].filter(x => x !== undefined); + const l = [incoming, payment].filter((x) => x !== undefined); if (l.length === 0) { return <span />; } @@ -300,7 +297,7 @@ class WalletBalanceView extends React.Component<any, any> { const wallet = this.balance; if (this.gotError) { return ( - <div className='balance'> + <div className="balance"> <p>{i18n.str`Error: could not retrieve balance information.`}</p> <p> Click <PageLink pageName="welcome.html">here</PageLink> for help and @@ -313,7 +310,7 @@ class WalletBalanceView extends React.Component<any, any> { return <span></span>; } console.log(wallet); - const listing = Object.keys(wallet.byCurrency).map(key => { + const listing = Object.keys(wallet.byCurrency).map((key) => { const entry: WalletBalanceEntry = wallet.byCurrency[key]; return ( <p> @@ -321,7 +318,11 @@ class WalletBalanceView extends React.Component<any, any> { </p> ); }); - return listing.length > 0 ? <div className='balance'>{listing}</div> : <EmptyBalanceView />; + return listing.length > 0 ? ( + <div className="balance">{listing}</div> + ) : ( + <EmptyBalanceView /> + ); } } @@ -356,7 +357,7 @@ function HistoryItem({ invalid, timestamp, icon, - negative = false + negative = false, }: HistoryItemProps) { function formatDate(timestamp: number | "never") { if (timestamp !== "never") { @@ -425,7 +426,7 @@ function HistoryItem({ function amountDiff( total: string | Amounts.AmountJson, - partial: string | Amounts.AmountJson + partial: string | Amounts.AmountJson, ): Amounts.AmountJson | string { let a = typeof total === "string" ? Amounts.parse(total) : total; let b = typeof partial === "string" ? Amounts.parse(partial) : partial; @@ -436,12 +437,11 @@ function amountDiff( } } - function parseSummary(summary: string) { let parsed = summary.split(/: (.+)/); return { merchant: parsed[0], - item: parsed[1] + item: parsed[1], }; } @@ -454,7 +454,7 @@ function formatHistoryItem(historyItem: HistoryEvent) { small={i18n.str`Refresh sessions has completed`} fees={amountDiff( historyItem.amountRefreshedRaw, - historyItem.amountRefreshedEffective + historyItem.amountRefreshedEffective, )} /> ); @@ -462,7 +462,7 @@ function formatHistoryItem(historyItem: HistoryEvent) { case "order-refused": { const { merchant, item } = parseSummary( - historyItem.orderShortInfo.summary + historyItem.orderShortInfo.summary, ); return ( <HistoryItem @@ -477,7 +477,7 @@ function formatHistoryItem(historyItem: HistoryEvent) { case "order-redirected": { const { merchant, item } = parseSummary( - historyItem.newOrderShortInfo.summary + historyItem.newOrderShortInfo.summary, ); return ( <HistoryItem @@ -492,7 +492,7 @@ function formatHistoryItem(historyItem: HistoryEvent) { case "payment-aborted": { const { merchant, item } = parseSummary( - historyItem.orderShortInfo.summary + historyItem.orderShortInfo.summary, ); return ( <HistoryItem @@ -510,18 +510,15 @@ function formatHistoryItem(historyItem: HistoryEvent) { case "payment-sent": { const url = historyItem.orderShortInfo.fulfillmentUrl; const { merchant, item } = parseSummary( - historyItem.orderShortInfo.summary + historyItem.orderShortInfo.summary, ); const fees = amountDiff( historyItem.amountPaidWithFees, - historyItem.orderShortInfo.amount + historyItem.orderShortInfo.amount, ); const fulfillmentLinkElem = ( <Fragment> - <a - href={url} - onClick={openTab(url)} - > + <a href={url} onClick={openTab(url)}> {item ? abbrev(item, 30) : null} </a> </Fragment> @@ -542,14 +539,11 @@ function formatHistoryItem(historyItem: HistoryEvent) { case "order-accepted": { const url = historyItem.orderShortInfo.fulfillmentUrl; const { merchant, item } = parseSummary( - historyItem.orderShortInfo.summary + historyItem.orderShortInfo.summary, ); const fulfillmentLinkElem = ( <Fragment> - <a - href={url} - onClick={openTab(url)} - > + <a href={url} onClick={openTab(url)}> {item ? abbrev(item, 40) : null} </a> </Fragment> @@ -573,7 +567,7 @@ function formatHistoryItem(historyItem: HistoryEvent) { small={i18n.str`Reserve balance updated`} fees={amountDiff( historyItem.amountExpected, - historyItem.amountReserveBalance + historyItem.amountReserveBalance, )} /> ); @@ -593,9 +587,9 @@ function formatHistoryItem(historyItem: HistoryEvent) { fees={amountDiff( amountDiff( historyItem.amountRefundedRaw, - historyItem.amountRefundedInvalid + historyItem.amountRefundedInvalid, ), - historyItem.amountRefundedEffective + historyItem.amountRefundedEffective, )} /> ); @@ -604,7 +598,7 @@ function formatHistoryItem(historyItem: HistoryEvent) { const exchange = new URL(historyItem.exchangeBaseUrl).host; const fees = amountDiff( historyItem.amountWithdrawnRaw, - historyItem.amountWithdrawnEffective + historyItem.amountWithdrawnEffective, ); return ( <HistoryItem @@ -663,9 +657,9 @@ class WalletHistory extends React.Component<any, any> { "refreshed", "reserve-balance-updated", "exchange-updated", - "exchange-added" + "exchange-added", ]; - + componentWillMount() { this.update(); this.setState({ filter: true }); @@ -678,7 +672,7 @@ class WalletHistory extends React.Component<any, any> { } update() { - chrome.runtime.sendMessage({ type: "get-history" }, resp => { + chrome.runtime.sendMessage({ type: "get-history" }, (resp) => { if (this.unmounted) { return; } @@ -709,15 +703,13 @@ class WalletHistory extends React.Component<any, any> { } const listing: any[] = []; - const messages = history - .reverse() - .filter(hEvent => { - if (!this.state.filter) return true; - return this.hidenTypes.indexOf(hEvent.type) === -1; - }); + const messages = history.reverse().filter((hEvent) => { + if (!this.state.filter) return true; + return this.hidenTypes.indexOf(hEvent.type) === -1; + }); for (const record of messages) { - const item = (<HistoryComponent key={record.eventId} record={record} />); + const item = <HistoryComponent key={record.eventId} record={record} />; listing.push(item); } @@ -821,5 +813,5 @@ function WalletPopup() { registerMountPage(() => { chrome.runtime.connect({ name: "popup" }); - return <WalletPopup /> + return <WalletPopup />; }); diff --git a/src/webex/pages/redirect.html b/src/webex/pages/redirect.html index 9d07d3d2b..67fddb527 100644 --- a/src/webex/pages/redirect.html +++ b/src/webex/pages/redirect.html @@ -1,14 +1,12 @@ <!DOCTYPE html> <html> + <head> + <meta charset="utf-8" /> -<head> - <meta charset="utf-8"> - - <script src="/src/webex/pages/redirect.js"></script> -</head> - -<body> - Redirecting to extension page ... -</body> + <script src="/src/webex/pages/redirect.js"></script> + </head> + <body> + Redirecting to extension page ... + </body> </html> diff --git a/src/webex/pages/redirect.js b/src/webex/pages/redirect.js index 879f5b530..547b225bd 100644 --- a/src/webex/pages/redirect.js +++ b/src/webex/pages/redirect.js @@ -2,7 +2,7 @@ * This is the entry point for redirects, and should be the only * web-accessible resource declared in the manifest. This prevents * malicious websites from embedding wallet pages in them. - * + * * We still need this redirect page since a webRequest can only directly * redirect to pages inside the extension that are a web-accessible resource. */ diff --git a/src/webex/pages/refund.html b/src/webex/pages/refund.html index 203fda21b..c671bb193 100644 --- a/src/webex/pages/refund.html +++ b/src/webex/pages/refund.html @@ -1,16 +1,16 @@ <!DOCTYPE html> <html> + <head> + <meta charset="UTF-8" /> + <title>Taler Wallet: Refund Status</title> -<head> - <meta charset="UTF-8"> - <title>Taler Wallet: Refund Status</title> + <link rel="stylesheet" type="text/css" href="../style/wallet.css" /> - <link rel="stylesheet" type="text/css" href="../style/wallet.css"> + <link rel="icon" href="/img/icon.png" /> - <link rel="icon" href="/img/icon.png"> - - <script src="/dist/page-common-bundle.js"></script> - <script src="/dist/refund-bundle.js"></script> + <script src="/dist/page-common-bundle.js"></script> + <script src="/dist/refund-bundle.js"></script> + </head> <body> <section id="main"> diff --git a/src/webex/pages/refund.tsx b/src/webex/pages/refund.tsx index 2a3f65d21..389d5e569 100644 --- a/src/webex/pages/refund.tsx +++ b/src/webex/pages/refund.tsx @@ -65,11 +65,10 @@ function RefundStatusView(props: { talerRefundUri: string }) { <h2>Refund Status</h2> <p> The product <em>{purchaseDetails.contractTerms.summary!}</em> has - received a total refund of <AmountView amount={purchaseDetails.totalRefundAmount} />. - </p> - <p> - Note that additional fees from the exchange may apply. + received a total refund of{" "} + <AmountView amount={purchaseDetails.totalRefundAmount} />. </p> + <p>Note that additional fees from the exchange may apply.</p> </> ); } diff --git a/src/webex/pages/reset-required.html b/src/webex/pages/reset-required.html index 72b176b4d..124d5f46f 100644 --- a/src/webex/pages/reset-required.html +++ b/src/webex/pages/reset-required.html @@ -1,30 +1,27 @@ <!DOCTYPE html> <html> + <head> + <meta charset="UTF-8" /> + <title>Taler Wallet: Select Taler Provider</title> -<head> - <meta charset="UTF-8"> - <title>Taler Wallet: Select Taler Provider</title> + <link rel="icon" href="/img/icon.png" /> + <link rel="stylesheet" type="text/css" href="../style/wallet.css" /> + <link rel="stylesheet" type="text/css" href="../style/pure.css" /> - <link rel="icon" href="/img/icon.png"> - <link rel="stylesheet" type="text/css" href="../style/wallet.css"> - <link rel="stylesheet" type="text/css" href="../style/pure.css"> + <script src="/dist/page-common-bundle.js"></script> + <script src="/dist/reset-required-bundle.js"></script> - <script src="/dist/page-common-bundle.js"></script> - <script src="/dist/reset-required-bundle.js"></script> - - <style> - body { - font-size: 100%; - overflow-y: scroll; - } - </style> - -</head> - -<body> - <section id="main"> - <div id="container"></div> - </section> -</body> + <style> + body { + font-size: 100%; + overflow-y: scroll; + } + </style> + </head> + <body> + <section id="main"> + <div id="container"></div> + </section> + </body> </html> diff --git a/src/webex/pages/reset-required.tsx b/src/webex/pages/reset-required.tsx index 6631705af..81f21f459 100644 --- a/src/webex/pages/reset-required.tsx +++ b/src/webex/pages/reset-required.tsx @@ -14,7 +14,6 @@ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ - /** * Page to inform the user when a database reset is required. * @@ -38,16 +37,15 @@ class State { resetRequired: boolean; } - class ResetNotification extends React.Component<any, State> { constructor(props: any) { super(props); - this.state = {checked: false, resetRequired: true}; + this.state = { checked: false, resetRequired: true }; setInterval(() => this.update(), 500); } async update() { const res = await wxApi.checkUpgrade(); - this.setState({resetRequired: res.dbResetRequired}); + this.setState({ resetRequired: res.dbResetRequired }); } render() { if (this.state.resetRequired) { @@ -55,32 +53,42 @@ class ResetNotification extends React.Component<any, State> { <div> <h1>Manual Reset Reqired</h1> <p> - The wallet's database in your browser is incompatible with the {" "} - currently installed wallet. Please reset manually. + The wallet's database in your browser is incompatible with the{" "} + currently installed wallet. Please reset manually. </p> - <p>Once the database format has stabilized, we will provide automatic upgrades.</p> - <input id="check" - type="checkbox" - checked={this.state.checked} - onChange={(e) => this.setState({checked: e.target.checked})} />{" "} + <p> + Once the database format has stabilized, we will provide automatic + upgrades. + </p> + <input + id="check" + type="checkbox" + checked={this.state.checked} + onChange={(e) => this.setState({ checked: e.target.checked })} + />{" "} <label htmlFor="check"> I understand that I will lose all my data </label> <br /> - <button className="pure-button" disabled={!this.state.checked} onClick={() => wxApi.resetDb()}>Reset</button> + <button + className="pure-button" + disabled={!this.state.checked} + onClick={() => wxApi.resetDb()} + > + Reset + </button> </div> ); } return ( <div> - <h1>Everything is fine!</h1> - A reset is not required anymore, you can close this page. + <h1>Everything is fine!</h1>A reset is not required anymore, you can + close this page. </div> ); } } - document.addEventListener("DOMContentLoaded", () => { - ReactDOM.render(<ResetNotification />, document.getElementById( "container")!); + ReactDOM.render(<ResetNotification />, document.getElementById("container")!); }); diff --git a/src/webex/pages/return-coins.html b/src/webex/pages/return-coins.html index c0ab218d2..54106f3e6 100644 --- a/src/webex/pages/return-coins.html +++ b/src/webex/pages/return-coins.html @@ -1,17 +1,17 @@ <!DOCTYPE html> <html> + <head> + <meta charset="UTF-8" /> + <title>Taler Wallet: Return Coins to Bank Account</title> -<head> - <meta charset="UTF-8"> - <title>Taler Wallet: Return Coins to Bank Account</title> + <link rel="stylesheet" type="text/css" href="../style/pure.css" /> + <link rel="stylesheet" type="text/css" href="../style/wallet.css" /> - <link rel="stylesheet" type="text/css" href="../style/pure.css"> - <link rel="stylesheet" type="text/css" href="../style/wallet.css"> + <link rel="icon" href="/img/icon.png" /> - <link rel="icon" href="/img/icon.png"> - - <script src="/dist/page-common-bundle.js"></script> - <script src="/dist/return-coins-bundle.js"></script> + <script src="/dist/page-common-bundle.js"></script> + <script src="/dist/return-coins-bundle.js"></script> + </head> <body> <div id="container"></div> diff --git a/src/webex/pages/return-coins.tsx b/src/webex/pages/return-coins.tsx index 7c835da0a..fd9238ee2 100644 --- a/src/webex/pages/return-coins.tsx +++ b/src/webex/pages/return-coins.tsx @@ -20,7 +20,6 @@ * @author Florian Dold */ - /** * Imports. */ @@ -28,20 +27,13 @@ import { AmountJson } from "../../util/amounts"; import * as Amounts from "../../util/amounts"; -import { - SenderWireInfos, - WalletBalance, -} from "../../types/walletTypes"; +import { SenderWireInfos, WalletBalance } from "../../types/walletTypes"; import * as i18n from "../i18n"; import * as wire from "../../util/wire"; -import { - getBalance, - getSenderWireInfos, - returnCoins, -} from "../wxApi"; +import { getBalance, getSenderWireInfos, returnCoins } from "../wxApi"; import { renderAmount } from "../renderHtml"; @@ -60,17 +52,27 @@ interface ReturnSelectionItemState { currency: string; } -class ReturnSelectionItem extends React.Component<ReturnSelectionItemProps, ReturnSelectionItemState> { +class ReturnSelectionItem extends React.Component< + ReturnSelectionItemProps, + ReturnSelectionItemState +> { constructor(props: ReturnSelectionItemProps) { super(props); const exchange = this.props.exchangeUrl; const wireTypes = this.props.senderWireInfos.exchangeWireTypes; - const supportedWires = this.props.senderWireInfos.senderWires.filter((x) => { - return wireTypes[exchange] && wireTypes[exchange].indexOf((x as any).type) >= 0; - }); + const supportedWires = this.props.senderWireInfos.senderWires.filter( + (x) => { + return ( + wireTypes[exchange] && + wireTypes[exchange].indexOf((x as any).type) >= 0 + ); + }, + ); this.state = { currency: props.balance.byExchange[props.exchangeUrl].available.currency, - selectedValue: Amounts.toString(props.balance.byExchange[props.exchangeUrl].available), + selectedValue: Amounts.toString( + props.balance.byExchange[props.exchangeUrl].available, + ), selectedWire: "", supportedWires, }; @@ -83,28 +85,46 @@ class ReturnSelectionItem extends React.Component<ReturnSelectionItemProps, Retu <div key={exchange}> <h2>Exchange {exchange}</h2> <p>Available amount: {renderAmount(byExchange[exchange].available)}</p> - <p>Supported wire methods: {wireTypes[exchange].length ? wireTypes[exchange].join(", ") : "none"}</p> - <p>Wire {""} - <input - type="text" - size={this.state.selectedValue.length || 1} - value={this.state.selectedValue} - onChange={(evt) => this.setState({selectedValue: evt.target.value})} - style={{textAlign: "center"}} - /> {this.props.balance.byExchange[exchange].available.currency} {""} - to account {""} - <select value={this.state.selectedWire} onChange={(evt) => this.setState({selectedWire: evt.target.value})}> - <option style={{display: "none"}}>Select account</option> - {this.state.supportedWires.map((w, n) => - <option value={n.toString()} key={JSON.stringify(w)}>{n + 1}: {wire.summarizeWire(w)}</option>, - )} - </select>. + <p> + Supported wire methods:{" "} + {wireTypes[exchange].length ? wireTypes[exchange].join(", ") : "none"} + </p> + <p> + Wire {""} + <input + type="text" + size={this.state.selectedValue.length || 1} + value={this.state.selectedValue} + onChange={(evt) => + this.setState({ selectedValue: evt.target.value }) + } + style={{ textAlign: "center" }} + />{" "} + {this.props.balance.byExchange[exchange].available.currency} {""} + to account {""} + <select + value={this.state.selectedWire} + onChange={(evt) => + this.setState({ selectedWire: evt.target.value }) + } + > + <option style={{ display: "none" }}>Select account</option> + {this.state.supportedWires.map((w, n) => ( + <option value={n.toString()} key={JSON.stringify(w)}> + {n + 1}: {wire.summarizeWire(w)} + </option> + ))} + </select> + . </p> - {this.state.selectedWire - ? <button className="pure-button button-success" onClick={() => this.select()}> - {i18n.str`Wire to bank account`} - </button> - : null} + {this.state.selectedWire ? ( + <button + className="pure-button button-success" + onClick={() => this.select()} + > + {i18n.str`Wire to bank account`} + </button> + ) : null} </div> ); } @@ -133,16 +153,23 @@ interface ReturnSelectionListProps { selectDetail(d: SelectedDetail): void; } -class ReturnSelectionList extends React.Component<ReturnSelectionListProps, {}> { +class ReturnSelectionList extends React.Component< + ReturnSelectionListProps, + {} +> { render(): JSX.Element { const byExchange = this.props.balance.byExchange; const exchanges = Object.keys(byExchange); if (!exchanges.length) { - return <p className="errorbox">Currently no funds available to transfer.</p>; + return ( + <p className="errorbox">Currently no funds available to transfer.</p> + ); } return ( <div> - {exchanges.map((e) => <ReturnSelectionItem key={e} exchangeUrl={e} {...this.props} />)} + {exchanges.map((e) => ( + <ReturnSelectionItem key={e} exchangeUrl={e} {...this.props} /> + ))} </div> ); } @@ -154,7 +181,6 @@ interface SelectedDetail { exchange: string; } - interface ReturnConfirmationProps { detail: SelectedDetail; cancel(): void; @@ -165,11 +191,19 @@ class ReturnConfirmation extends React.Component<ReturnConfirmationProps, {}> { render() { return ( <div> - <p>Please confirm if you want to transmit <strong>{renderAmount(this.props.detail.amount)}</strong> at {""} - {this.props.detail.exchange} to account {""} - <strong style={{whiteSpace: "nowrap"}}>{wire.summarizeWire(this.props.detail.senderWire)}</strong>. + <p> + Please confirm if you want to transmit{" "} + <strong>{renderAmount(this.props.detail.amount)}</strong> at {""} + {this.props.detail.exchange} to account {""} + <strong style={{ whiteSpace: "nowrap" }}> + {wire.summarizeWire(this.props.detail.senderWire)} + </strong> + . </p> - <button className="pure-button button-success" onClick={() => this.props.confirm()}> + <button + className="pure-button button-success" + onClick={() => this.props.confirm()} + > {i18n.str`Confirm`} </button> <button className="pure-button" onClick={() => this.props.cancel()}> @@ -213,7 +247,7 @@ class ReturnCoins extends React.Component<{}, ReturnCoinsState> { } selectDetail(d: SelectedDetail) { - this.setState({selectedReturn: d}); + this.setState({ selectedReturn: d }); } async confirm() { @@ -223,11 +257,17 @@ class ReturnCoins extends React.Component<{}, ReturnCoinsState> { } await returnCoins(selectedReturn); await this.update(); - this.setState({selectedReturn: undefined, lastConfirmedDetail: selectedReturn}); + this.setState({ + selectedReturn: undefined, + lastConfirmedDetail: selectedReturn, + }); } async cancel() { - this.setState({selectedReturn: undefined, lastConfirmedDetail: undefined}); + this.setState({ + selectedReturn: undefined, + lastConfirmedDetail: undefined, + }); } render() { @@ -248,25 +288,28 @@ class ReturnCoins extends React.Component<{}, ReturnCoinsState> { ); } return ( - <div id="main"> - <h1>Wire electronic cash back to own bank account</h1> - <p>You can send coins back into your own bank account. Note that - you're acting as a merchant when doing this, and thus the same fees apply.</p> - {this.state.lastConfirmedDetail - ? <p className="okaybox"> - Transfer of {renderAmount(this.state.lastConfirmedDetail.amount)} successfully initiated. - </p> - : null} - <ReturnSelectionList - selectDetail={(d) => this.selectDetail(d)} - balance={balance} - senderWireInfos={senderWireInfos} /> - </div> + <div id="main"> + <h1>Wire electronic cash back to own bank account</h1> + <p> + You can send coins back into your own bank account. Note that you're + acting as a merchant when doing this, and thus the same fees apply. + </p> + {this.state.lastConfirmedDetail ? ( + <p className="okaybox"> + Transfer of {renderAmount(this.state.lastConfirmedDetail.amount)}{" "} + successfully initiated. + </p> + ) : null} + <ReturnSelectionList + selectDetail={(d) => this.selectDetail(d)} + balance={balance} + senderWireInfos={senderWireInfos} + /> + </div> ); } } - function main() { ReactDOM.render(<ReturnCoins />, document.getElementById("container")!); } diff --git a/src/webex/pages/show-db.html b/src/webex/pages/show-db.html index 714089553..ae77e3fb0 100644 --- a/src/webex/pages/show-db.html +++ b/src/webex/pages/show-db.html @@ -1,16 +1,16 @@ -<!doctype html> +<!DOCTYPE html> <html> <head> - <meta charset="UTF-8"> + <meta charset="UTF-8" /> <title>Taler Wallet: Reserve Created</title> - <link rel="stylesheet" type="text/css" href="../style/wallet.css"> - <link rel="icon" href="/img/icon.png"> + <link rel="stylesheet" type="text/css" href="../style/wallet.css" /> + <link rel="icon" href="/img/icon.png" /> <script src="/dist/page-common-bundle.js"></script> <script src="/dist/show-db-bundle.js"></script> </head> <body> <h1>DB Dump</h1> - <input type="file" id="fileInput" style="display:none"> + <input type="file" id="fileInput" style="display: none;" /> <button id="import">Import Dump</button> <button id="download">Download Dump</button> <pre id="dump"></pre> diff --git a/src/webex/pages/show-db.ts b/src/webex/pages/show-db.ts index d95951385..16ea80d2d 100644 --- a/src/webex/pages/show-db.ts +++ b/src/webex/pages/show-db.ts @@ -14,15 +14,19 @@ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ - /** * Wallet database dump for debugging. * * @author Florian Dold */ -function replacer(match: string, pIndent: string, pKey: string, pVal: string, - pEnd: string) { +function replacer( + match: string, + pIndent: string, + pKey: string, + pVal: string, + pEnd: string, +) { const key = "<span class=json-key>"; const val = "<span class=json-value>"; const str = "<span class=json-string>"; @@ -36,18 +40,18 @@ function replacer(match: string, pIndent: string, pKey: string, pVal: string, return r + (pEnd || ""); } - function prettyPrint(obj: any) { - const jsonLine = /^( *)("[\w]+": )?("[^"]*"|[\w.+-]*)?([,[{])?$/mg; + const jsonLine = /^( *)("[\w]+": )?("[^"]*"|[\w.+-]*)?([,[{])?$/gm; return JSON.stringify(obj, null as any, 3) - .replace(/&/g, "&").replace(/\\"/g, """) - .replace(/</g, "<").replace(/>/g, ">") - .replace(jsonLine, replacer); + .replace(/&/g, "&") + .replace(/\\"/g, """) + .replace(/</g, "<") + .replace(/>/g, ">") + .replace(jsonLine, replacer); } - document.addEventListener("DOMContentLoaded", () => { - chrome.runtime.sendMessage({type: "dump-db"}, (resp) => { + chrome.runtime.sendMessage({ type: "dump-db" }, (resp) => { const el = document.getElementById("dump"); if (!el) { throw Error(); @@ -57,16 +61,18 @@ document.addEventListener("DOMContentLoaded", () => { document.getElementById("download")!.addEventListener("click", (evt) => { console.log("creating download"); const element = document.createElement("a"); - element.setAttribute("href", "data:text/plain;charset=utf-8," + encodeURIComponent(JSON.stringify(resp))); + element.setAttribute( + "href", + "data:text/plain;charset=utf-8," + + encodeURIComponent(JSON.stringify(resp)), + ); element.setAttribute("download", "wallet-dump.txt"); element.style.display = "none"; document.body.appendChild(element); element.click(); }); - }); - const fileInput = document.getElementById("fileInput")! as HTMLInputElement; fileInput.onchange = (evt) => { if (!fileInput.files || fileInput.files.length !== 1) { @@ -79,9 +85,12 @@ document.addEventListener("DOMContentLoaded", () => { console.log("got file"); const dump = JSON.parse(e.target.result); console.log("parsed contents", dump); - chrome.runtime.sendMessage({ type: "import-db", detail: { dump } }, (resp) => { - alert("loaded"); - }); + chrome.runtime.sendMessage( + { type: "import-db", detail: { dump } }, + (resp) => { + alert("loaded"); + }, + ); }; console.log("reading file", file); fr.readAsText(file); diff --git a/src/webex/pages/tip.html b/src/webex/pages/tip.html index 72d91a123..0625640ed 100644 --- a/src/webex/pages/tip.html +++ b/src/webex/pages/tip.html @@ -1,24 +1,21 @@ <!DOCTYPE html> <html> + <head> + <meta charset="UTF-8" /> + <title>Taler Wallet: Received Tip</title> -<head> - <meta charset="UTF-8"> - <title>Taler Wallet: Received Tip</title> + <link rel="icon" href="/img/icon.png" /> + <link rel="stylesheet" type="text/css" href="../style/pure.css" /> + <link rel="stylesheet" type="text/css" href="../style/wallet.css" /> - <link rel="icon" href="/img/icon.png"> - <link rel="stylesheet" type="text/css" href="../style/pure.css"> - <link rel="stylesheet" type="text/css" href="../style/wallet.css"> - - <script src="/dist/page-common-bundle.js"></script> - <script src="/dist/tip-bundle.js"></script> - -</head> - -<body> - <section id="main"> - <h1>GNU Taler Wallet</h1> - <div id="container"></div> - </section> -</body> + <script src="/dist/page-common-bundle.js"></script> + <script src="/dist/tip-bundle.js"></script> + </head> + <body> + <section id="main"> + <h1>GNU Taler Wallet</h1> + <div id="container"></div> + </section> + </body> </html> diff --git a/src/webex/pages/tip.tsx b/src/webex/pages/tip.tsx index c44b343a4..35e033c0d 100644 --- a/src/webex/pages/tip.tsx +++ b/src/webex/pages/tip.tsx @@ -28,13 +28,16 @@ import * as i18n from "../i18n"; import { acceptTip, getReserveCreationInfo, getTipStatus } from "../wxApi"; -import { WithdrawDetailView, renderAmount, ProgressButton } from "../renderHtml"; +import { + WithdrawDetailView, + renderAmount, + ProgressButton, +} from "../renderHtml"; import * as Amounts from "../../util/amounts"; import { useState, useEffect } from "react"; import { TipStatus } from "../../types/walletTypes"; - function TipDisplay(props: { talerTipUri: string }) { const [tipStatus, setTipStatus] = useState<TipStatus | undefined>(undefined); const [discarded, setDiscarded] = useState(false); @@ -88,8 +91,7 @@ function TipDisplay(props: { talerTipUri: string }) { <form className="pure-form"> <ProgressButton loading={loading} onClick={() => accept()}> Accept Tip - </ProgressButton> - {" "} + </ProgressButton>{" "} <button className="pure-button" type="button" onClick={() => discard()}> Discard tip </button> diff --git a/src/webex/pages/welcome.html b/src/webex/pages/welcome.html index 9a96d04a7..8f17891e2 100644 --- a/src/webex/pages/welcome.html +++ b/src/webex/pages/welcome.html @@ -1,24 +1,21 @@ <!DOCTYPE html> <html> + <head> + <meta charset="UTF-8" /> + <title>Taler Wallet: Withdraw</title> -<head> - <meta charset="UTF-8"> - <title>Taler Wallet: Withdraw</title> + <link rel="icon" href="/img/icon.png" /> + <link rel="stylesheet" type="text/css" href="../style/pure.css" /> + <link rel="stylesheet" type="text/css" href="../style/wallet.css" /> - <link rel="icon" href="/img/icon.png"> - <link rel="stylesheet" type="text/css" href="../style/pure.css"> - <link rel="stylesheet" type="text/css" href="../style/wallet.css"> - - <script src="/dist/page-common-bundle.js"></script> - <script src="/dist/welcome-bundle.js"></script> - -</head> - -<body> - <section id="main"> - <h1>GNU Taler Wallet Installed!</h1> - <div id="container">Loading...</div> - </section> -</body> + <script src="/dist/page-common-bundle.js"></script> + <script src="/dist/welcome-bundle.js"></script> + </head> + <body> + <section id="main"> + <h1>GNU Taler Wallet Installed!</h1> + <div id="container">Loading...</div> + </section> + </body> </html> diff --git a/src/webex/pages/welcome.tsx b/src/webex/pages/welcome.tsx index e8f7028ed..83f4f01d5 100644 --- a/src/webex/pages/welcome.tsx +++ b/src/webex/pages/welcome.tsx @@ -68,7 +68,7 @@ function Diagnostics() { > <p>Problems detected:</p> <ol> - {diagnostics.errors.map(errMsg => ( + {diagnostics.errors.map((errMsg) => ( <li>{errMsg}</li> ))} </ol> diff --git a/src/webex/pages/withdraw.html b/src/webex/pages/withdraw.html index e5c527275..861b219f5 100644 --- a/src/webex/pages/withdraw.html +++ b/src/webex/pages/withdraw.html @@ -1,24 +1,21 @@ <!DOCTYPE html> <html> + <head> + <meta charset="UTF-8" /> + <title>Taler Wallet: Withdraw</title> -<head> - <meta charset="UTF-8"> - <title>Taler Wallet: Withdraw</title> + <link rel="icon" href="/img/icon.png" /> + <link rel="stylesheet" type="text/css" href="../style/pure.css" /> + <link rel="stylesheet" type="text/css" href="../style/wallet.css" /> - <link rel="icon" href="/img/icon.png"> - <link rel="stylesheet" type="text/css" href="../style/pure.css"> - <link rel="stylesheet" type="text/css" href="../style/wallet.css"> + <script src="/dist/page-common-bundle.js"></script> + <script src="/dist/withdraw-bundle.js"></script> + </head> - <script src="/dist/page-common-bundle.js"></script> - <script src="/dist/withdraw-bundle.js"></script> - -</head> - -<body> - <section id="main"> - <h1>GNU Taler Wallet</h1> + <body> + <section id="main"> + <h1>GNU Taler Wallet</h1> <div class="fade" id="exchange-selection"></div> - </section> -</body> - + </section> + </body> </html> diff --git a/src/webex/pages/withdraw.tsx b/src/webex/pages/withdraw.tsx index c123e2a6f..7a2665314 100644 --- a/src/webex/pages/withdraw.tsx +++ b/src/webex/pages/withdraw.tsx @@ -127,7 +127,7 @@ function NewExchangeSelection(props: { talerWithdrawUri: string }) { <p> <input type="text" - onChange={e => setCustomUrl(e.target.value)} + onChange={(e) => setCustomUrl(e.target.value)} value={customUrl} /> </p> diff --git a/src/webex/renderHtml.tsx b/src/webex/renderHtml.tsx index 3204c410d..08e7de607 100644 --- a/src/webex/renderHtml.tsx +++ b/src/webex/renderHtml.tsx @@ -143,7 +143,7 @@ function AuditorDetailsView(props: { } return ( <div> - {(rci.exchangeInfo.details?.auditors ?? []).map(a => ( + {(rci.exchangeInfo.details?.auditors ?? []).map((a) => ( <div> <h3>Auditor {a.auditor_url}</h3> <p> @@ -214,7 +214,7 @@ function FeeDetailsView(props: { </tr> </thead>, <tbody> - {rci!.wireFees.feesForType[s].map(f => ( + {rci!.wireFees.feesForType[s].map((f) => ( <tr> <td>{stringifyTimestamp(f.endStamp)}</td> <td>{renderAmount(f.wireFee)}</td> @@ -232,7 +232,10 @@ function FeeDetailsView(props: { <div> <h3>Overview</h3> <p> - Public key: <ExpanderText text={rci.exchangeInfo.details?.masterPublicKey ?? "??"} /> + Public key:{" "} + <ExpanderText + text={rci.exchangeInfo.details?.masterPublicKey ?? "??"} + /> </p> <p> {i18n.str`Withdrawal fees:`} {withdrawFee} @@ -240,8 +243,9 @@ function FeeDetailsView(props: { <p> {i18n.str`Rounding loss:`} {overhead} </p> - <p>{i18n.str`Earliest expiration (for deposit): ${ - stringifyTimestamp(rci.earliestDepositExpiration)}`}</p> + <p>{i18n.str`Earliest expiration (for deposit): ${stringifyTimestamp( + rci.earliestDepositExpiration, + )}`}</p> <h3>Coin Fees</h3> <div style={{ overflow: "auto" }}> <table className="pure-table"> diff --git a/src/webex/style/pure.css b/src/webex/style/pure.css index 739113970..88a4bb7d7 100644 --- a/src/webex/style/pure.css +++ b/src/webex/style/pure.css @@ -449,7 +449,7 @@ th { .hidden, [hidden] { - display: none !important; + display: none !important; } /** @@ -457,20 +457,20 @@ th { * aspect ratio. */ .pure-img { - max-width: 100%; - height: auto; - display: block; + max-width: 100%; + height: auto; + display: block; } /*csslint regex-selectors:false, known-properties:false, duplicate-properties:false*/ .pure-g { - letter-spacing: -0.31em; /* Webkit: collapse white-space between units */ - *letter-spacing: normal; /* reset IE < 8 */ - *word-spacing: -0.43em; /* IE < 8: collapse white-space between units */ - text-rendering: optimizespeed; /* Webkit: fixes text-rendering: optimizeLegibility */ + letter-spacing: -0.31em; /* Webkit: collapse white-space between units */ + *letter-spacing: normal; /* reset IE < 8 */ + *word-spacing: -0.43em; /* IE < 8: collapse white-space between units */ + text-rendering: optimizespeed; /* Webkit: fixes text-rendering: optimizeLegibility */ - /* + /* Sets the font stack to fonts known to work properly with the above letter and word spacings. See: https://github.com/yahoo/pure/issues/41/ @@ -486,28 +486,28 @@ th { * Helvetica, Arial, sans-serif: Common font stack on OS X and Windows. */ - font-family: FreeSans, Arimo, "Droid Sans", Helvetica, Arial, sans-serif; + font-family: FreeSans, Arimo, "Droid Sans", Helvetica, Arial, sans-serif; - /* Use flexbox when possible to avoid `letter-spacing` side-effects. */ - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-flex-flow: row wrap; - -ms-flex-flow: row wrap; - flex-flow: row wrap; + /* Use flexbox when possible to avoid `letter-spacing` side-effects. */ + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-flow: row wrap; + -ms-flex-flow: row wrap; + flex-flow: row wrap; - /* Prevents distributing space between rows */ - -webkit-align-content: flex-start; - -ms-flex-line-pack: start; - align-content: flex-start; + /* Prevents distributing space between rows */ + -webkit-align-content: flex-start; + -ms-flex-line-pack: start; + align-content: flex-start; } /* IE10 display: -ms-flexbox (and display: flex in IE 11) does not work inside a table; fall back to block and rely on font hack */ @media all and (-ms-high-contrast: none), (-ms-high-contrast: active) { - table .pure-g { - display: block; - } + table .pure-g { + display: block; + } } /* Opera as of 12 on Windows needs word-spacing. @@ -516,25 +516,25 @@ th { */ .opera-only :-o-prefocus, .pure-g { - word-spacing: -0.43em; + word-spacing: -0.43em; } .pure-u { - display: inline-block; - *display: inline; /* IE < 8: fake inline-block */ - zoom: 1; - letter-spacing: normal; - word-spacing: normal; - vertical-align: top; - text-rendering: auto; + display: inline-block; + *display: inline; /* IE < 8: fake inline-block */ + zoom: 1; + letter-spacing: normal; + word-spacing: normal; + vertical-align: top; + text-rendering: auto; } /* Resets the font family back to the OS/browser's default sans-serif font, this the same font stack that Normalize.css sets for the `body`. */ -.pure-g [class *= "pure-u"] { - font-family: sans-serif; +.pure-g [class*="pure-u"] { + font-family: sans-serif; } .pure-u-1, @@ -583,245 +583,254 @@ this the same font stack that Normalize.css sets for the `body`. .pure-u-22-24, .pure-u-23-24, .pure-u-24-24 { - display: inline-block; - *display: inline; - zoom: 1; - letter-spacing: normal; - word-spacing: normal; - vertical-align: top; - text-rendering: auto; + display: inline-block; + *display: inline; + zoom: 1; + letter-spacing: normal; + word-spacing: normal; + vertical-align: top; + text-rendering: auto; } .pure-u-1-24 { - width: 4.1667%; - *width: 4.1357%; + width: 4.1667%; + *width: 4.1357%; } .pure-u-1-12, .pure-u-2-24 { - width: 8.3333%; - *width: 8.3023%; + width: 8.3333%; + *width: 8.3023%; } .pure-u-1-8, .pure-u-3-24 { - width: 12.5000%; - *width: 12.4690%; + width: 12.5%; + *width: 12.469%; } .pure-u-1-6, .pure-u-4-24 { - width: 16.6667%; - *width: 16.6357%; + width: 16.6667%; + *width: 16.6357%; } .pure-u-1-5 { - width: 20%; - *width: 19.9690%; + width: 20%; + *width: 19.969%; } .pure-u-5-24 { - width: 20.8333%; - *width: 20.8023%; + width: 20.8333%; + *width: 20.8023%; } .pure-u-1-4, .pure-u-6-24 { - width: 25%; - *width: 24.9690%; + width: 25%; + *width: 24.969%; } .pure-u-7-24 { - width: 29.1667%; - *width: 29.1357%; + width: 29.1667%; + *width: 29.1357%; } .pure-u-1-3, .pure-u-8-24 { - width: 33.3333%; - *width: 33.3023%; + width: 33.3333%; + *width: 33.3023%; } .pure-u-3-8, .pure-u-9-24 { - width: 37.5000%; - *width: 37.4690%; + width: 37.5%; + *width: 37.469%; } .pure-u-2-5 { - width: 40%; - *width: 39.9690%; + width: 40%; + *width: 39.969%; } .pure-u-5-12, .pure-u-10-24 { - width: 41.6667%; - *width: 41.6357%; + width: 41.6667%; + *width: 41.6357%; } .pure-u-11-24 { - width: 45.8333%; - *width: 45.8023%; + width: 45.8333%; + *width: 45.8023%; } .pure-u-1-2, .pure-u-12-24 { - width: 50%; - *width: 49.9690%; + width: 50%; + *width: 49.969%; } .pure-u-13-24 { - width: 54.1667%; - *width: 54.1357%; + width: 54.1667%; + *width: 54.1357%; } .pure-u-7-12, .pure-u-14-24 { - width: 58.3333%; - *width: 58.3023%; + width: 58.3333%; + *width: 58.3023%; } .pure-u-3-5 { - width: 60%; - *width: 59.9690%; + width: 60%; + *width: 59.969%; } .pure-u-5-8, .pure-u-15-24 { - width: 62.5000%; - *width: 62.4690%; + width: 62.5%; + *width: 62.469%; } .pure-u-2-3, .pure-u-16-24 { - width: 66.6667%; - *width: 66.6357%; + width: 66.6667%; + *width: 66.6357%; } .pure-u-17-24 { - width: 70.8333%; - *width: 70.8023%; + width: 70.8333%; + *width: 70.8023%; } .pure-u-3-4, .pure-u-18-24 { - width: 75%; - *width: 74.9690%; + width: 75%; + *width: 74.969%; } .pure-u-19-24 { - width: 79.1667%; - *width: 79.1357%; + width: 79.1667%; + *width: 79.1357%; } .pure-u-4-5 { - width: 80%; - *width: 79.9690%; + width: 80%; + *width: 79.969%; } .pure-u-5-6, .pure-u-20-24 { - width: 83.3333%; - *width: 83.3023%; + width: 83.3333%; + *width: 83.3023%; } .pure-u-7-8, .pure-u-21-24 { - width: 87.5000%; - *width: 87.4690%; + width: 87.5%; + *width: 87.469%; } .pure-u-11-12, .pure-u-22-24 { - width: 91.6667%; - *width: 91.6357%; + width: 91.6667%; + *width: 91.6357%; } .pure-u-23-24 { - width: 95.8333%; - *width: 95.8023%; + width: 95.8333%; + *width: 95.8023%; } .pure-u-1, .pure-u-1-1, .pure-u-5-5, .pure-u-24-24 { - width: 100%; + width: 100%; } .pure-button { - /* Structure */ - display: inline-block; - zoom: 1; - line-height: normal; - white-space: nowrap; - vertical-align: middle; - text-align: center; - cursor: pointer; - -webkit-user-drag: none; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - box-sizing: border-box; + /* Structure */ + display: inline-block; + zoom: 1; + line-height: normal; + white-space: nowrap; + vertical-align: middle; + text-align: center; + cursor: pointer; + -webkit-user-drag: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + box-sizing: border-box; } /* Firefox: Get rid of the inner focus border */ .pure-button::-moz-focus-inner { - padding: 0; - border: 0; + padding: 0; + border: 0; } /* Inherit .pure-g styles */ .pure-button-group { - letter-spacing: -0.31em; /* Webkit: collapse white-space between units */ - *letter-spacing: normal; /* reset IE < 8 */ - *word-spacing: -0.43em; /* IE < 8: collapse white-space between units */ - text-rendering: optimizespeed; /* Webkit: fixes text-rendering: optimizeLegibility */ + letter-spacing: -0.31em; /* Webkit: collapse white-space between units */ + *letter-spacing: normal; /* reset IE < 8 */ + *word-spacing: -0.43em; /* IE < 8: collapse white-space between units */ + text-rendering: optimizespeed; /* Webkit: fixes text-rendering: optimizeLegibility */ } .opera-only :-o-prefocus, .pure-button-group { - word-spacing: -0.43em; + word-spacing: -0.43em; } .pure-button-group .pure-button { - letter-spacing: normal; - word-spacing: normal; - vertical-align: top; - text-rendering: auto; + letter-spacing: normal; + word-spacing: normal; + vertical-align: top; + text-rendering: auto; } /*csslint outline-none:false*/ .pure-button { - font-family: inherit; - font-size: 100%; - padding: 0.5em 1em; - color: #444; /* rgba not supported (IE 8) */ - color: rgba(0, 0, 0, 0.80); /* rgba supported */ - border: 1px solid #999; /*IE 6/7/8*/ - border: none rgba(0, 0, 0, 0); /*IE9 + everything else*/ - background-color: #E6E6E6; - text-decoration: none; - border-radius: 2px; + font-family: inherit; + font-size: 100%; + padding: 0.5em 1em; + color: #444; /* rgba not supported (IE 8) */ + color: rgba(0, 0, 0, 0.8); /* rgba supported */ + border: 1px solid #999; /*IE 6/7/8*/ + border: none rgba(0, 0, 0, 0); /*IE9 + everything else*/ + background-color: #e6e6e6; + text-decoration: none; + border-radius: 2px; } .pure-button-hover, .pure-button:hover, .pure-button:focus { - /* csslint ignore:start */ - filter: alpha(opacity=90); - /* csslint ignore:end */ - background-image: -webkit-linear-gradient(transparent, rgba(0,0,0, 0.05) 40%, rgba(0,0,0, 0.10)); - background-image: linear-gradient(transparent, rgba(0,0,0, 0.05) 40%, rgba(0,0,0, 0.10)); + /* csslint ignore:start */ + filter: alpha(opacity=90); + /* csslint ignore:end */ + background-image: -webkit-linear-gradient( + transparent, + rgba(0, 0, 0, 0.05) 40%, + rgba(0, 0, 0, 0.1) + ); + background-image: linear-gradient( + transparent, + rgba(0, 0, 0, 0.05) 40%, + rgba(0, 0, 0, 0.1) + ); } .pure-button:focus { - outline: 0; + outline: 0; } .pure-button-active, .pure-button:active { - box-shadow: 0 0 0 1px rgba(0,0,0, 0.15) inset, 0 0 6px rgba(0,0,0, 0.20) inset; - border-color: #000\9; + box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.15) inset, + 0 0 6px rgba(0, 0, 0, 0.2) inset; + border-color: #000\9; } .pure-button[disabled], @@ -829,46 +838,45 @@ this the same font stack that Normalize.css sets for the `body`. .pure-button-disabled:hover, .pure-button-disabled:focus, .pure-button-disabled:active { - border: none; - background-image: none; - /* csslint ignore:start */ - filter: alpha(opacity=40); - /* csslint ignore:end */ - opacity: 0.40; - cursor: not-allowed; - box-shadow: none; - pointer-events: none; + border: none; + background-image: none; + /* csslint ignore:start */ + filter: alpha(opacity=40); + /* csslint ignore:end */ + opacity: 0.4; + cursor: not-allowed; + box-shadow: none; + pointer-events: none; } .pure-button-hidden { - display: none; + display: none; } .pure-button-primary, .pure-button-selected, a.pure-button-primary, a.pure-button-selected { - background-color: rgb(0, 120, 231); - color: #fff; + background-color: rgb(0, 120, 231); + color: #fff; } /* Button Groups */ .pure-button-group .pure-button { - margin: 0; - border-radius: 0; - border-right: 1px solid #111; /* fallback color for rgba() for IE7/8 */ - border-right: 1px solid rgba(0, 0, 0, 0.2); - + margin: 0; + border-radius: 0; + border-right: 1px solid #111; /* fallback color for rgba() for IE7/8 */ + border-right: 1px solid rgba(0, 0, 0, 0.2); } .pure-button-group .pure-button:first-child { - border-top-left-radius: 2px; - border-bottom-left-radius: 2px; + border-top-left-radius: 2px; + border-bottom-left-radius: 2px; } .pure-button-group .pure-button:last-child { - border-top-right-radius: 2px; - border-bottom-right-radius: 2px; - border-right: none; + border-top-right-radius: 2px; + border-bottom-right-radius: 2px; + border-right: none; } /*csslint box-model:false*/ @@ -895,13 +903,13 @@ so we can ignore the csslint warning. .pure-form input[type="color"], .pure-form select, .pure-form textarea { - padding: 0.5em 0.6em; - display: inline-block; - border: 1px solid #ccc; - box-shadow: inset 0 1px 3px #ddd; - border-radius: 4px; - vertical-align: middle; - box-sizing: border-box; + padding: 0.5em 0.6em; + display: inline-block; + border: 1px solid #ccc; + box-shadow: inset 0 1px 3px #ddd; + border-radius: 4px; + vertical-align: middle; + box-sizing: border-box; } /* @@ -909,22 +917,20 @@ Need to separate out the :not() selector from the rest of the CSS 2.1 selectors since IE8 won't execute CSS that contains a CSS3 selector. */ .pure-form input:not([type]) { - padding: 0.5em 0.6em; - display: inline-block; - border: 1px solid #ccc; - box-shadow: inset 0 1px 3px #ddd; - border-radius: 4px; - box-sizing: border-box; + padding: 0.5em 0.6em; + display: inline-block; + border: 1px solid #ccc; + box-shadow: inset 0 1px 3px #ddd; + border-radius: 4px; + box-sizing: border-box; } - /* Chrome (as of v.32/34 on OS X) needs additional room for color to display. */ /* May be able to remove this tweak as color inputs become more standardized across browsers. */ .pure-form input[type="color"] { - padding: 0.2em 0.5em; + padding: 0.2em 0.5em; } - .pure-form input[type="text"]:focus, .pure-form input[type="password"]:focus, .pure-form input[type="email"]:focus, @@ -941,8 +947,8 @@ since IE8 won't execute CSS that contains a CSS3 selector. .pure-form input[type="color"]:focus, .pure-form select:focus, .pure-form textarea:focus { - outline: 0; - border-color: #129FEA; + outline: 0; + border-color: #129fea; } /* @@ -950,20 +956,20 @@ Need to separate out the :not() selector from the rest of the CSS 2.1 selectors since IE8 won't execute CSS that contains a CSS3 selector. */ .pure-form input:not([type]):focus { - outline: 0; - border-color: #129FEA; + outline: 0; + border-color: #129fea; } .pure-form input[type="file"]:focus, .pure-form input[type="radio"]:focus, .pure-form input[type="checkbox"]:focus { - outline: thin solid #129FEA; - outline: 1px auto #129FEA; + outline: thin solid #129fea; + outline: 1px auto #129fea; } .pure-form .pure-checkbox, .pure-form .pure-radio { - margin: 0.5em 0; - display: block; + margin: 0.5em 0; + display: block; } .pure-form input[type="text"][disabled], @@ -982,9 +988,9 @@ since IE8 won't execute CSS that contains a CSS3 selector. .pure-form input[type="color"][disabled], .pure-form select[disabled], .pure-form textarea[disabled] { - cursor: not-allowed; - background-color: #eaeded; - color: #cad2d3; + cursor: not-allowed; + background-color: #eaeded; + color: #cad2d3; } /* @@ -992,53 +998,53 @@ Need to separate out the :not() selector from the rest of the CSS 2.1 selectors since IE8 won't execute CSS that contains a CSS3 selector. */ .pure-form input:not([type])[disabled] { - cursor: not-allowed; - background-color: #eaeded; - color: #cad2d3; + cursor: not-allowed; + background-color: #eaeded; + color: #cad2d3; } .pure-form input[readonly], .pure-form select[readonly], .pure-form textarea[readonly] { - background-color: #eee; /* menu hover bg color */ - color: #777; /* menu text color */ - border-color: #ccc; + background-color: #eee; /* menu hover bg color */ + color: #777; /* menu text color */ + border-color: #ccc; } .pure-form input:focus:invalid, .pure-form textarea:focus:invalid, .pure-form select:focus:invalid { - color: #b94a48; - border-color: #e9322d; + color: #b94a48; + border-color: #e9322d; } .pure-form input[type="file"]:focus:invalid:focus, .pure-form input[type="radio"]:focus:invalid:focus, .pure-form input[type="checkbox"]:focus:invalid:focus { - outline-color: #e9322d; + outline-color: #e9322d; } .pure-form select { - /* Normalizes the height; padding is not sufficient. */ - height: 2.25em; - border: 1px solid #ccc; - background-color: white; + /* Normalizes the height; padding is not sufficient. */ + height: 2.25em; + border: 1px solid #ccc; + background-color: white; } .pure-form select[multiple] { - height: auto; + height: auto; } .pure-form label { - margin: 0.5em 0 0.2em; + margin: 0.5em 0 0.2em; } .pure-form fieldset { - margin: 0; - padding: 0.35em 0 0.75em; - border: 0; + margin: 0; + padding: 0.35em 0 0.75em; + border: 0; } .pure-form legend { - display: block; - width: 100%; - padding: 0.3em 0; - margin-bottom: 0.3em; - color: #333; - border-bottom: 1px solid #e5e5e5; + display: block; + width: 100%; + padding: 0.3em 0; + margin-bottom: 0.3em; + color: #333; + border-bottom: 1px solid #e5e5e5; } .pure-form-stacked input[type="text"], @@ -1059,8 +1065,8 @@ since IE8 won't execute CSS that contains a CSS3 selector. .pure-form-stacked select, .pure-form-stacked label, .pure-form-stacked textarea { - display: block; - margin: 0.25em 0; + display: block; + margin: 0.25em 0; } /* @@ -1068,8 +1074,8 @@ Need to separate out the :not() selector from the rest of the CSS 2.1 selectors since IE8 won't execute CSS that contains a CSS3 selector. */ .pure-form-stacked input:not([type]) { - display: block; - margin: 0.25em 0; + display: block; + margin: 0.25em 0; } .pure-form-aligned input, .pure-form-aligned textarea, @@ -1077,397 +1083,397 @@ since IE8 won't execute CSS that contains a CSS3 selector. /* NOTE: pure-help-inline is deprecated. Use .pure-form-message-inline instead. */ .pure-form-aligned .pure-help-inline, .pure-form-message-inline { - display: inline-block; - *display: inline; - *zoom: 1; - vertical-align: middle; + display: inline-block; + *display: inline; + *zoom: 1; + vertical-align: middle; } .pure-form-aligned textarea { - vertical-align: top; + vertical-align: top; } /* Aligned Forms */ .pure-form-aligned .pure-control-group { - margin-bottom: 0.5em; + margin-bottom: 0.5em; } .pure-form-aligned .pure-control-group label { - text-align: right; - display: inline-block; - vertical-align: middle; - width: 10em; - margin: 0 1em 0 0; + text-align: right; + display: inline-block; + vertical-align: middle; + width: 10em; + margin: 0 1em 0 0; } .pure-form-aligned .pure-controls { - margin: 1.5em 0 0 11em; + margin: 1.5em 0 0 11em; } /* Rounded Inputs */ .pure-form input.pure-input-rounded, .pure-form .pure-input-rounded { - border-radius: 2em; - padding: 0.5em 1em; + border-radius: 2em; + padding: 0.5em 1em; } /* Grouped Inputs */ .pure-form .pure-group fieldset { - margin-bottom: 10px; + margin-bottom: 10px; } .pure-form .pure-group input, .pure-form .pure-group textarea { - display: block; - padding: 10px; - margin: 0 0 -1px; - border-radius: 0; - position: relative; - top: -1px; + display: block; + padding: 10px; + margin: 0 0 -1px; + border-radius: 0; + position: relative; + top: -1px; } .pure-form .pure-group input:focus, .pure-form .pure-group textarea:focus { - z-index: 3; + z-index: 3; } .pure-form .pure-group input:first-child, .pure-form .pure-group textarea:first-child { - top: 1px; - border-radius: 4px 4px 0 0; - margin: 0; + top: 1px; + border-radius: 4px 4px 0 0; + margin: 0; } .pure-form .pure-group input:first-child:last-child, .pure-form .pure-group textarea:first-child:last-child { - top: 1px; - border-radius: 4px; - margin: 0; + top: 1px; + border-radius: 4px; + margin: 0; } .pure-form .pure-group input:last-child, .pure-form .pure-group textarea:last-child { - top: -2px; - border-radius: 0 0 4px 4px; - margin: 0; + top: -2px; + border-radius: 0 0 4px 4px; + margin: 0; } .pure-form .pure-group button { - margin: 0.35em 0; + margin: 0.35em 0; } .pure-form .pure-input-1 { - width: 100%; + width: 100%; } .pure-form .pure-input-3-4 { - width: 75%; + width: 75%; } .pure-form .pure-input-2-3 { - width: 66%; + width: 66%; } .pure-form .pure-input-1-2 { - width: 50%; + width: 50%; } .pure-form .pure-input-1-3 { - width: 33%; + width: 33%; } .pure-form .pure-input-1-4 { - width: 25%; + width: 25%; } /* Inline help for forms */ /* NOTE: pure-help-inline is deprecated. Use .pure-form-message-inline instead. */ .pure-form .pure-help-inline, .pure-form-message-inline { - display: inline-block; - padding-left: 0.3em; - color: #666; - vertical-align: middle; - font-size: 0.875em; + display: inline-block; + padding-left: 0.3em; + color: #666; + vertical-align: middle; + font-size: 0.875em; } /* Block help for forms */ .pure-form-message { + display: block; + color: #666; + font-size: 0.875em; +} + +@media only screen and (max-width: 480px) { + .pure-form button[type="submit"] { + margin: 0.7em 0 0; + } + + .pure-form input:not([type]), + .pure-form input[type="text"], + .pure-form input[type="password"], + .pure-form input[type="email"], + .pure-form input[type="url"], + .pure-form input[type="date"], + .pure-form input[type="month"], + .pure-form input[type="time"], + .pure-form input[type="datetime"], + .pure-form input[type="datetime-local"], + .pure-form input[type="week"], + .pure-form input[type="number"], + .pure-form input[type="search"], + .pure-form input[type="tel"], + .pure-form input[type="color"], + .pure-form label { + margin-bottom: 0.3em; display: block; - color: #666; - font-size: 0.875em; -} - -@media only screen and (max-width : 480px) { - .pure-form button[type="submit"] { - margin: 0.7em 0 0; - } - - .pure-form input:not([type]), - .pure-form input[type="text"], - .pure-form input[type="password"], - .pure-form input[type="email"], - .pure-form input[type="url"], - .pure-form input[type="date"], - .pure-form input[type="month"], - .pure-form input[type="time"], - .pure-form input[type="datetime"], - .pure-form input[type="datetime-local"], - .pure-form input[type="week"], - .pure-form input[type="number"], - .pure-form input[type="search"], - .pure-form input[type="tel"], - .pure-form input[type="color"], - .pure-form label { - margin-bottom: 0.3em; - display: block; - } - - .pure-group input:not([type]), - .pure-group input[type="text"], - .pure-group input[type="password"], - .pure-group input[type="email"], - .pure-group input[type="url"], - .pure-group input[type="date"], - .pure-group input[type="month"], - .pure-group input[type="time"], - .pure-group input[type="datetime"], - .pure-group input[type="datetime-local"], - .pure-group input[type="week"], - .pure-group input[type="number"], - .pure-group input[type="search"], - .pure-group input[type="tel"], - .pure-group input[type="color"] { - margin-bottom: 0; - } - - .pure-form-aligned .pure-control-group label { - margin-bottom: 0.3em; - text-align: left; - display: block; - width: 100%; - } - - .pure-form-aligned .pure-controls { - margin: 1.5em 0 0 0; - } - - /* NOTE: pure-help-inline is deprecated. Use .pure-form-message-inline instead. */ - .pure-form .pure-help-inline, - .pure-form-message-inline, - .pure-form-message { - display: block; - font-size: 0.75em; - /* Increased bottom padding to make it group with its related input element. */ - padding: 0.2em 0 0.8em; - } + } + + .pure-group input:not([type]), + .pure-group input[type="text"], + .pure-group input[type="password"], + .pure-group input[type="email"], + .pure-group input[type="url"], + .pure-group input[type="date"], + .pure-group input[type="month"], + .pure-group input[type="time"], + .pure-group input[type="datetime"], + .pure-group input[type="datetime-local"], + .pure-group input[type="week"], + .pure-group input[type="number"], + .pure-group input[type="search"], + .pure-group input[type="tel"], + .pure-group input[type="color"] { + margin-bottom: 0; + } + + .pure-form-aligned .pure-control-group label { + margin-bottom: 0.3em; + text-align: left; + display: block; + width: 100%; + } + + .pure-form-aligned .pure-controls { + margin: 1.5em 0 0 0; + } + + /* NOTE: pure-help-inline is deprecated. Use .pure-form-message-inline instead. */ + .pure-form .pure-help-inline, + .pure-form-message-inline, + .pure-form-message { + display: block; + font-size: 0.75em; + /* Increased bottom padding to make it group with its related input element. */ + padding: 0.2em 0 0.8em; + } } /*csslint adjoining-classes: false, box-model:false*/ .pure-menu { - box-sizing: border-box; + box-sizing: border-box; } .pure-menu-fixed { - position: fixed; - left: 0; - top: 0; - z-index: 3; + position: fixed; + left: 0; + top: 0; + z-index: 3; } .pure-menu-list, .pure-menu-item { - position: relative; + position: relative; } .pure-menu-list { - list-style: none; - margin: 0; - padding: 0; + list-style: none; + margin: 0; + padding: 0; } .pure-menu-item { - padding: 0; - margin: 0; - height: 100%; + padding: 0; + margin: 0; + height: 100%; } .pure-menu-link, .pure-menu-heading { - display: block; - text-decoration: none; - white-space: nowrap; + display: block; + text-decoration: none; + white-space: nowrap; } /* HORIZONTAL MENU */ .pure-menu-horizontal { - width: 100%; - white-space: nowrap; + width: 100%; + white-space: nowrap; } .pure-menu-horizontal .pure-menu-list { - display: inline-block; + display: inline-block; } /* Initial menus should be inline-block so that they are horizontal */ .pure-menu-horizontal .pure-menu-item, .pure-menu-horizontal .pure-menu-heading, .pure-menu-horizontal .pure-menu-separator { - display: inline-block; - *display: inline; - zoom: 1; - vertical-align: middle; + display: inline-block; + *display: inline; + zoom: 1; + vertical-align: middle; } /* Submenus should still be display: block; */ .pure-menu-item .pure-menu-item { - display: block; + display: block; } .pure-menu-children { - display: none; - position: absolute; - left: 100%; - top: 0; - margin: 0; - padding: 0; - z-index: 3; + display: none; + position: absolute; + left: 100%; + top: 0; + margin: 0; + padding: 0; + z-index: 3; } .pure-menu-horizontal .pure-menu-children { - left: 0; - top: auto; - width: inherit; + left: 0; + top: auto; + width: inherit; } .pure-menu-allow-hover:hover > .pure-menu-children, .pure-menu-active > .pure-menu-children { - display: block; - position: absolute; + display: block; + position: absolute; } /* Vertical Menus - show the dropdown arrow */ .pure-menu-has-children > .pure-menu-link:after { - padding-left: 0.5em; - content: "\25B8"; - font-size: small; + padding-left: 0.5em; + content: "\25B8"; + font-size: small; } /* Horizontal Menus - show the dropdown arrow */ .pure-menu-horizontal .pure-menu-has-children > .pure-menu-link:after { - content: "\25BE"; + content: "\25BE"; } /* scrollable menus */ .pure-menu-scrollable { - overflow-y: scroll; - overflow-x: hidden; + overflow-y: scroll; + overflow-x: hidden; } .pure-menu-scrollable .pure-menu-list { - display: block; + display: block; } .pure-menu-horizontal.pure-menu-scrollable .pure-menu-list { - display: inline-block; + display: inline-block; } .pure-menu-horizontal.pure-menu-scrollable { - white-space: nowrap; - overflow-y: hidden; - overflow-x: auto; - -ms-overflow-style: none; - -webkit-overflow-scrolling: touch; - /* a little extra padding for this style to allow for scrollbars */ - padding: .5em 0; + white-space: nowrap; + overflow-y: hidden; + overflow-x: auto; + -ms-overflow-style: none; + -webkit-overflow-scrolling: touch; + /* a little extra padding for this style to allow for scrollbars */ + padding: 0.5em 0; } .pure-menu-horizontal.pure-menu-scrollable::-webkit-scrollbar { - display: none; + display: none; } /* misc default styling */ .pure-menu-separator, .pure-menu-horizontal .pure-menu-children .pure-menu-separator { - background-color: #ccc; - height: 1px; - margin: .3em 0; + background-color: #ccc; + height: 1px; + margin: 0.3em 0; } .pure-menu-horizontal .pure-menu-separator { - width: 1px; - height: 1.3em; - margin: 0 .3em ; + width: 1px; + height: 1.3em; + margin: 0 0.3em; } /* Need to reset the separator since submenu is vertical */ .pure-menu-horizontal .pure-menu-children .pure-menu-separator { - display: block; - width: auto; + display: block; + width: auto; } .pure-menu-heading { - text-transform: uppercase; - color: #565d64; + text-transform: uppercase; + color: #565d64; } .pure-menu-link { - color: #777; + color: #777; } .pure-menu-children { - background-color: #fff; + background-color: #fff; } .pure-menu-link, .pure-menu-disabled, .pure-menu-heading { - padding: .5em 1em; + padding: 0.5em 1em; } .pure-menu-disabled { - opacity: .5; + opacity: 0.5; } .pure-menu-disabled .pure-menu-link:hover { - background-color: transparent; + background-color: transparent; } .pure-menu-active > .pure-menu-link, .pure-menu-link:hover, .pure-menu-link:focus { - background-color: #eee; + background-color: #eee; } .pure-menu-selected .pure-menu-link, .pure-menu-selected .pure-menu-link:visited { - color: #000; + color: #000; } .pure-table { - /* Remove spacing between table cells (from Normalize.css) */ - border-collapse: collapse; - border-spacing: 0; - empty-cells: show; - border: 1px solid #cbcbcb; + /* Remove spacing between table cells (from Normalize.css) */ + border-collapse: collapse; + border-spacing: 0; + empty-cells: show; + border: 1px solid #cbcbcb; } .pure-table caption { - color: #000; - font: italic 85%/1 arial, sans-serif; - padding: 1em 0; - text-align: center; + color: #000; + font: italic 85%/1 arial, sans-serif; + padding: 1em 0; + text-align: center; } .pure-table td, .pure-table th { - border-left: 1px solid #cbcbcb;/* inner column border */ - border-width: 0 0 0 1px; - font-size: inherit; - margin: 0; - overflow: visible; /*to make ths where the title is really long work*/ - padding: 0.5em 1em; /* cell padding */ + border-left: 1px solid #cbcbcb; /* inner column border */ + border-width: 0 0 0 1px; + font-size: inherit; + margin: 0; + overflow: visible; /*to make ths where the title is really long work*/ + padding: 0.5em 1em; /* cell padding */ } /* Consider removing this next declaration block, as it causes problems when there's a rowspan on the first cell. Case added to the tests. issue#432 */ .pure-table td:first-child, .pure-table th:first-child { - border-left-width: 0; + border-left-width: 0; } .pure-table thead { - background-color: #e0e0e0; - color: #000; - text-align: left; - vertical-align: bottom; + background-color: #e0e0e0; + color: #000; + text-align: left; + vertical-align: bottom; } /* @@ -1476,33 +1482,32 @@ striping: odd - #f2f2f2 (light gray) */ .pure-table td { - background-color: transparent; + background-color: transparent; } .pure-table-odd td { - background-color: #f2f2f2; + background-color: #f2f2f2; } /* nth-child selector for modern browsers */ .pure-table-striped tr:nth-child(2n-1) td { - background-color: #f2f2f2; + background-color: #f2f2f2; } /* BORDERED TABLES */ .pure-table-bordered td { - border-bottom: 1px solid #cbcbcb; + border-bottom: 1px solid #cbcbcb; } .pure-table-bordered tbody > tr:last-child > td { - border-bottom-width: 0; + border-bottom-width: 0; } - /* HORIZONTAL BORDERED TABLES */ .pure-table-horizontal td, .pure-table-horizontal th { - border-width: 0 0 1px 0; - border-bottom: 1px solid #cbcbcb; + border-width: 0 0 1px 0; + border-bottom: 1px solid #cbcbcb; } .pure-table-horizontal tbody > tr:last-child > td { - border-bottom-width: 0; + border-bottom-width: 0; } diff --git a/src/webex/style/wallet.css b/src/webex/style/wallet.css index b4bfd6f6d..16a414b3d 100644 --- a/src/webex/style/wallet.css +++ b/src/webex/style/wallet.css @@ -4,75 +4,77 @@ body { } #main { - border: solid 1px black; - border-radius: 10px; - margin-left: auto; - margin-right: auto; - margin-top: 2em; - max-width: 50%; - padding: 2em; + border: solid 1px black; + border-radius: 10px; + margin-left: auto; + margin-right: auto; + margin-top: 2em; + max-width: 50%; + padding: 2em; } header { - width: 100%; - height: 100px; - margin: 0; - padding: 0; - border-bottom: 1px solid black; + width: 100%; + height: 100px; + margin: 0; + padding: 0; + border-bottom: 1px solid black; } header h1 { - font-size: 200%; - margin: 0; - padding: 0 0 0 120px; - position: relative; - top: 50%; - transform: translateY(-50%); + font-size: 200%; + margin: 0; + padding: 0 0 0 120px; + position: relative; + top: 50%; + transform: translateY(-50%); } header #logo { - float: left; - width: 100px; - height: 100px; - padding: 0; - margin: 0; - text-align: center; - border-right: 1px solid black; - background-image: url(/img/logo.png); - background-size: 100px; + float: left; + width: 100px; + height: 100px; + padding: 0; + margin: 0; + text-align: center; + border-right: 1px solid black; + background-image: url(/img/logo.png); + background-size: 100px; } aside { - width: 100px; - float: left; + width: 100px; + float: left; } section#main { - margin: auto; - padding: 20px; - border-left: 1px solid black; - height: 100%; - max-width: 50%; + margin: auto; + padding: 20px; + border-left: 1px solid black; + height: 100%; + max-width: 50%; } section#main h1:first-child { - margin-top: 0; + margin-top: 0; } h1 { - font-size: 160%; + font-size: 160%; } h2 { - font-size: 140%; + font-size: 140%; } h3 { - font-size: 120%; + font-size: 120%; } -h4, h5, h6 { - font-size: 100%; +h4, +h5, +h6 { + font-size: 100%; } .form-row { @@ -92,63 +94,74 @@ input.url { } .json-key { - color: brown; + color: brown; } .json-value { - color: navy; - } + color: navy; +} .json-string { - color: olive; + color: olive; } button { - font-size: 120%; - padding: 0.5em; + font-size: 120%; + padding: 0.5em; } button.confirm-pay { - float: right; + float: right; } /* We use fading to hide slower DOM updates */ .fade { - -webkit-animation: fade 0.7s; - animation: fade 0.7s; - opacity: 1; + -webkit-animation: fade 0.7s; + animation: fade 0.7s; + opacity: 1; } @-webkit-keyframes fade { - from {opacity: 0} - to {opacity: 1} + from { + opacity: 0; + } + to { + opacity: 1; + } } @keyframes fade { - from {opacity: 0} - to {opacity: 1} - } + from { + opacity: 0; + } + to { + opacity: 1; + } +} button.linky { - background:none!important; - border:none; - padding:0!important; + background: none !important; + border: none; + padding: 0 !important; - font-family:arial,sans-serif; - color:#069; - text-decoration:underline; - cursor:pointer; + font-family: arial, sans-serif; + color: #069; + text-decoration: underline; + cursor: pointer; } -.blacklink a:link, .blacklink a:visited, .blacklink a:hover, .blacklink a:active { +.blacklink a:link, +.blacklink a:visited, +.blacklink a:hover, +.blacklink a:active { color: #000; } - -table, th, td { - border: 1px solid black; +table, +th, +td { + border: 1px solid black; } - button.accept { - background-color: #5757D2; + background-color: #5757d2; border: 1px solid black; border-radius: 5px; margin: 1em 0; @@ -157,17 +170,16 @@ button.accept { color: white; } button.linky { - background:none!important; - border:none; - padding:0!important; + background: none !important; + border: none; + padding: 0 !important; - font-family:arial,sans-serif; - color:#069; - text-decoration:underline; - cursor:pointer; + font-family: arial, sans-serif; + color: #069; + text-decoration: underline; + cursor: pointer; } - button.accept:disabled { background-color: #dedbe8; border: 1px solid white; @@ -175,7 +187,7 @@ button.accept:disabled { margin: 1em 0; padding: 0.5em; font-weight: bold; - color: #2C2C2C; + color: #2c2c2c; } input.url { @@ -202,39 +214,38 @@ span.spacer { .button-destructive, .button-warning, .button-secondary { - color: white; - border-radius: 4px; - text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); + color: white; + border-radius: 4px; + text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); } .button-success { - background: rgb(28, 184, 65); + background: rgb(28, 184, 65); } .button-destructive { - background: rgb(202, 60, 60); + background: rgb(202, 60, 60); } .button-warning { - background: rgb(223, 117, 20); + background: rgb(223, 117, 20); } .button-secondary { - background: rgb(66, 184, 221); + background: rgb(66, 184, 221); } a.actionLink { color: black; } - .errorbox { border: 1px solid; display: inline-block; margin: 1em; padding: 1em; font-weight: bold; - background: #FF8A8A; + background: #ff8a8a; } .okaybox { @@ -243,18 +254,17 @@ a.actionLink { margin: 1em; padding: 1em; font-weight: bold; - background: #00FA9A; + background: #00fa9a; } - -a.opener { +a.opener { color: black; } .opener-open::before { - content: "\25bc" + content: "\25bc"; } .opener-collapsed::before { - content: "\25b6 " + content: "\25b6 "; } .svg-icon { @@ -265,8 +275,8 @@ a.opener { width: 1em; } .svg-icon svg { - height:1em; - width:1em; + height: 1em; + width: 1em; } object.svg-icon.svg-baseline { transform: translate(0, 0.125em); diff --git a/src/webex/wxApi.ts b/src/webex/wxApi.ts index 5edd1907b..a530b7506 100644 --- a/src/webex/wxApi.ts +++ b/src/webex/wxApi.ts @@ -79,7 +79,7 @@ async function callBackend<T extends MessageType>( detail: MessageMap[T]["request"], ): Promise<MessageMap[T]["response"]> { return new Promise<MessageMap[T]["response"]>((resolve, reject) => { - chrome.runtime.sendMessage({ type, detail }, resp => { + chrome.runtime.sendMessage({ type, detail }, (resp) => { if (chrome.runtime.lastError) { console.log("Error calling backend"); reject( diff --git a/src/webex/wxBackend.ts b/src/webex/wxBackend.ts index 248e6dfba..dd0b91683 100644 --- a/src/webex/wxBackend.ts +++ b/src/webex/wxBackend.ts @@ -406,7 +406,7 @@ async function reinitWallet() { http, new BrowserCryptoWorkerFactory(), ); - wallet.runRetryLoop().catch(e => { + wallet.runRetryLoop().catch((e) => { console.log("error during wallet retry loop", e); }); // Useful for debugging in the background page. @@ -443,7 +443,7 @@ function injectScript( try { // This needs to be outside of main, as Firefox won't fire the event if // the listener isn't created synchronously on loading the backend. - chrome.runtime.onInstalled.addListener(details => { + chrome.runtime.onInstalled.addListener((details) => { console.log("onInstalled with reason", details.reason); if (details.reason === "install") { const url = chrome.extension.getURL("/src/webex/pages/welcome.html"); @@ -462,12 +462,12 @@ try { export async function wxMain() { // Explicitly unload the extension page as soon as an update is available, // so the update gets installed as soon as possible. - chrome.runtime.onUpdateAvailable.addListener(details => { + chrome.runtime.onUpdateAvailable.addListener((details) => { console.log("update available:", details); chrome.runtime.reload(); }); - chrome.tabs.query({}, tabs => { + chrome.tabs.query({}, (tabs) => { console.log("got tabs", tabs); for (const tab of tabs) { if (!tab.url || !tab.id) { @@ -520,7 +520,7 @@ export async function wxMain() { const run = () => { timers.shift(); - chrome.tabs.get(tabId, tab => { + chrome.tabs.get(tabId, (tab) => { if (chrome.runtime.lastError) { return; } @@ -562,7 +562,7 @@ export async function wxMain() { // Handlers for catching HTTP requests chrome.webRequest.onHeadersReceived.addListener( - details => { + (details) => { const wallet = currentWallet; if (!wallet) { console.warn("wallet not available while handling header"); |