From 92f929152f713646ec8836891718c2ac18fff81f Mon Sep 17 00:00:00 2001 From: Ahmed Bouhuolia Date: Sun, 16 Jul 2023 21:15:13 +0200 Subject: [PATCH 1/2] feat(server): expose the api rate limit to the env vars --- .env.example | 3 +++ packages/server/src/config/index.ts | 11 +++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/.env.example b/.env.example index 4978f6a78..f07f28c5f 100644 --- a/.env.example +++ b/.env.example @@ -47,3 +47,6 @@ AGENDASH_AUTH_PASSWORD=123123 SIGNUP_DISABLED=false SIGNUP_ALLOWED_DOMAINS= SIGNUP_ALLOWED_EMAILS= + +# API rate limit (points,duration,block duration). +API_RATE_LIMIT=120,60,600 \ No newline at end of file diff --git a/packages/server/src/config/index.ts b/packages/server/src/config/index.ts index ff1fedb6a..bc6833130 100644 --- a/packages/server/src/config/index.ts +++ b/packages/server/src/config/index.ts @@ -1,9 +1,12 @@ import dotenv from 'dotenv'; import path from 'path'; +import { toInteger } from 'lodash'; import { castCommaListEnvVarToArray, parseBoolean } from '@/utils'; dotenv.config(); +const API_RATE_LIMIT = process.env.API_RATE_LIMIT?.split(',') || []; + module.exports = { /** * Your favorite port @@ -97,7 +100,7 @@ module.exports = { jwtSecret: process.env.JWT_SECRET, /** - * + * */ resetPasswordSeconds: 600, @@ -130,9 +133,9 @@ module.exports = { blockDuration: 60 * 15, }, requests: { - points: 60, - duration: 60, - blockDuration: 60 * 10, + points: API_RATE_LIMIT[0] ? toInteger(API_RATE_LIMIT[0]) : 120, + duration: API_RATE_LIMIT[1] ? toInteger(API_RATE_LIMIT[1]) : 60, + blockDuration: API_RATE_LIMIT[2] ? toInteger(API_RATE_LIMIT[2]) : 60 * 10, }, }, From 8b0feb902284ff36350663b2b2113ac13b70f5f6 Mon Sep 17 00:00:00 2001 From: Ahmed Bouhuolia Date: Sun, 16 Jul 2023 21:19:06 +0200 Subject: [PATCH 2/2] fix(webapp): handle the too many requests error --- .../src/containers/GlobalErrors/GlobalErrors.tsx | 13 +++++++++++++ packages/webapp/src/hooks/useRequest.tsx | 3 +++ packages/webapp/src/lang/en/index.json | 3 ++- .../src/style/components/BigcapitalLoading.scss | 6 ++++-- packages/webapp/src/style/variables.scss | 4 ++++ 5 files changed, 26 insertions(+), 3 deletions(-) diff --git a/packages/webapp/src/containers/GlobalErrors/GlobalErrors.tsx b/packages/webapp/src/containers/GlobalErrors/GlobalErrors.tsx index 211402c0f..e972733d8 100644 --- a/packages/webapp/src/containers/GlobalErrors/GlobalErrors.tsx +++ b/packages/webapp/src/containers/GlobalErrors/GlobalErrors.tsx @@ -9,6 +9,7 @@ import { compose } from '@/utils'; let toastKeySessionExpired; let toastKeySomethingWrong; +let toastTooManyRequests; function GlobalErrors({ // #withGlobalErrors @@ -41,6 +42,18 @@ function GlobalErrors({ toastKeySomethingWrong, ); } + if (globalErrors.too_many_requests) { + toastTooManyRequests = AppToaster.show( + { + message: intl.get('global_error.too_many_requests'), + intent: Intent.DANGER, + onDismiss: () => { + globalErrorsSet({ too_many_requests: false }); + }, + }, + toastTooManyRequests, + ); + } if (globalErrors.access_denied) { toastKeySomethingWrong = AppToaster.show( { diff --git a/packages/webapp/src/hooks/useRequest.tsx b/packages/webapp/src/hooks/useRequest.tsx index c092f1faf..12635ad0a 100644 --- a/packages/webapp/src/hooks/useRequest.tsx +++ b/packages/webapp/src/hooks/useRequest.tsx @@ -60,6 +60,9 @@ export default function useApiRequest() { if (status === 403) { setGlobalErrors({ access_denied: true }); } + if (status === 429) { + setGlobalErrors({ too_many_requests: true }); + } if (status === 400) { const lockedError = data.errors.find( (error) => error.type === 'TRANSACTIONS_DATE_LOCKED', diff --git a/packages/webapp/src/lang/en/index.json b/packages/webapp/src/lang/en/index.json index 2010d32b1..6fb394354 100644 --- a/packages/webapp/src/lang/en/index.json +++ b/packages/webapp/src/lang/en/index.json @@ -2292,5 +2292,6 @@ "sidebar.projects": "Projects", "sidebar.new_project": "New Project", "sidebar.new_time_entry": "New Time Entry", - "sidebar.project_profitability_summary": "Project Profitability Summary" + "sidebar.project_profitability_summary": "Project Profitability Summary", + "global_error.too_many_requests": "Too many requests" } \ No newline at end of file diff --git a/packages/webapp/src/style/components/BigcapitalLoading.scss b/packages/webapp/src/style/components/BigcapitalLoading.scss index 2375d2a1f..c387b5b13 100644 --- a/packages/webapp/src/style/components/BigcapitalLoading.scss +++ b/packages/webapp/src/style/components/BigcapitalLoading.scss @@ -1,10 +1,12 @@ +@import '@/style/variables.scss'; + .bigcapital-loading { height: 100%; width: 100%; position: fixed; display: flex; background: #fff; - z-index: 999999; + z-index: $zindex-dashboard-splash-screen; .center { width: auto; @@ -18,4 +20,4 @@ opacity: 0.85; display: none; } -} +} \ No newline at end of file diff --git a/packages/webapp/src/style/variables.scss b/packages/webapp/src/style/variables.scss index bea903aa4..21fe0ded6 100644 --- a/packages/webapp/src/style/variables.scss +++ b/packages/webapp/src/style/variables.scss @@ -45,3 +45,7 @@ $form-check-input-checked-color: #fff; $form-check-input-checked-bg-color: $blue1; $form-check-input-checked-bg-image: url("data:image/svg+xml,") !default; $form-check-input-indeterminate-bg-image: url("data:image/svg+xml,") !default; + +// z-indexs +$zindex-dashboard-splash-screen: 39; +$zindex-toast: 40; \ No newline at end of file