summaryrefslogtreecommitdiff
path: root/packages/taler-wallet-core
diff options
context:
space:
mode:
authorFlorian Dold <florian@dold.me>2022-03-08 19:19:29 +0100
committerFlorian Dold <florian@dold.me>2022-03-08 19:19:29 +0100
commit1d1c847b793620acf3a2b193ab45eabf53234cb2 (patch)
tree7fa92e8a3e7cdc911168f7546b563af10b9535ee /packages/taler-wallet-core
parentd0376d9e685a0e4920ec75b6e7ab176fa148aa4e (diff)
downloadwallet-core-1d1c847b793620acf3a2b193ab45eabf53234cb2.tar.gz
wallet-core-1d1c847b793620acf3a2b193ab45eabf53234cb2.tar.bz2
wallet-core-1d1c847b793620acf3a2b193ab45eabf53234cb2.zip
wallet: throttle all http requests
even from browsers / service workers
Diffstat (limited to 'packages/taler-wallet-core')
-rw-r--r--packages/taler-wallet-core/src/headless/NodeHttpLib.ts2
-rw-r--r--packages/taler-wallet-core/src/util/RequestThrottler.ts156
-rw-r--r--packages/taler-wallet-core/tsconfig.json2
3 files changed, 2 insertions, 158 deletions
diff --git a/packages/taler-wallet-core/src/headless/NodeHttpLib.ts b/packages/taler-wallet-core/src/headless/NodeHttpLib.ts
index 5a90994b1..2a8c9e36c 100644
--- a/packages/taler-wallet-core/src/headless/NodeHttpLib.ts
+++ b/packages/taler-wallet-core/src/headless/NodeHttpLib.ts
@@ -25,7 +25,7 @@ import {
HttpRequestOptions,
HttpResponse,
} from "../util/http.js";
-import { RequestThrottler } from "../util/RequestThrottler.js";
+import { RequestThrottler } from "@gnu-taler/taler-util";
import Axios, { AxiosResponse } from "axios";
import { OperationFailedError, makeErrorDetails } from "../errors.js";
import { Logger, bytesToString } from "@gnu-taler/taler-util";
diff --git a/packages/taler-wallet-core/src/util/RequestThrottler.ts b/packages/taler-wallet-core/src/util/RequestThrottler.ts
deleted file mode 100644
index d79afe47a..000000000
--- a/packages/taler-wallet-core/src/util/RequestThrottler.ts
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2019 GNUnet e.V.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-/**
- * Implementation of token bucket throttling.
- */
-
-/**
- * Imports.
- */
-import {
- getTimestampNow,
- timestampDifference,
- timestampCmp,
- Logger,
- URL,
-} from "@gnu-taler/taler-util";
-
-const logger = new Logger("RequestThrottler.ts");
-
-/**
- * Maximum request per second, per origin.
- */
-const MAX_PER_SECOND = 100;
-
-/**
- * Maximum request per minute, per origin.
- */
-const MAX_PER_MINUTE = 500;
-
-/**
- * Maximum request per hour, per origin.
- */
-const MAX_PER_HOUR = 2000;
-
-/**
- * Throttling state for one origin.
- */
-class OriginState {
- tokensSecond: number = MAX_PER_SECOND;
- tokensMinute: number = MAX_PER_MINUTE;
- tokensHour: number = MAX_PER_HOUR;
- private lastUpdate = getTimestampNow();
-
- private refill(): void {
- const now = getTimestampNow();
- if (timestampCmp(now, this.lastUpdate) < 0) {
- // Did the system time change?
- this.lastUpdate = now;
- return;
- }
- const d = timestampDifference(now, this.lastUpdate);
- if (d.d_ms === "forever") {
- throw Error("assertion failed");
- }
- this.tokensSecond = Math.min(
- MAX_PER_SECOND,
- this.tokensSecond + d.d_ms / 1000,
- );
- this.tokensMinute = Math.min(
- MAX_PER_MINUTE,
- this.tokensMinute + d.d_ms / 1000 / 60,
- );
- this.tokensHour = Math.min(
- MAX_PER_HOUR,
- this.tokensHour + d.d_ms / 1000 / 60 / 60,
- );
- this.lastUpdate = now;
- }
-
- /**
- * Return true if the request for this origin should be throttled.
- * Otherwise, take a token out of the respective buckets.
- */
- applyThrottle(): boolean {
- this.refill();
- if (this.tokensSecond < 1) {
- logger.warn("request throttled (per second limit exceeded)");
- return true;
- }
- if (this.tokensMinute < 1) {
- logger.warn("request throttled (per minute limit exceeded)");
- return true;
- }
- if (this.tokensHour < 1) {
- logger.warn("request throttled (per hour limit exceeded)");
- return true;
- }
- this.tokensSecond--;
- this.tokensMinute--;
- this.tokensHour--;
- return false;
- }
-}
-
-/**
- * Request throttler, used as a "last layer of defense" when some
- * other part of the re-try logic is broken and we're sending too
- * many requests to the same exchange/bank/merchant.
- */
-export class RequestThrottler {
- private perOriginInfo: { [origin: string]: OriginState } = {};
-
- /**
- * Get the throttling state for an origin, or
- * initialize if no state is associated with the
- * origin yet.
- */
- private getState(origin: string): OriginState {
- const s = this.perOriginInfo[origin];
- if (s) {
- return s;
- }
- 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 {
- const origin = new URL(requestUrl).origin;
- return this.getState(origin).applyThrottle();
- }
-
- /**
- * Get the throttle statistics for a particular URL.
- */
- getThrottleStats(requestUrl: string): Record<string, unknown> {
- const origin = new URL(requestUrl).origin;
- const state = this.getState(origin);
- return {
- tokensHour: state.tokensHour,
- tokensMinute: state.tokensMinute,
- tokensSecond: state.tokensSecond,
- maxTokensHour: MAX_PER_HOUR,
- maxTokensMinute: MAX_PER_MINUTE,
- maxTokensSecond: MAX_PER_SECOND,
- };
- }
-}
diff --git a/packages/taler-wallet-core/tsconfig.json b/packages/taler-wallet-core/tsconfig.json
index 3da332364..c3366373e 100644
--- a/packages/taler-wallet-core/tsconfig.json
+++ b/packages/taler-wallet-core/tsconfig.json
@@ -21,7 +21,7 @@
"esModuleInterop": true,
"importHelpers": true,
"rootDir": "./src",
- "typeRoots": ["./node_modules/@types"],
+ "typeRoots": ["./node_modules/@types"]
},
"references": [
{