diff --git a/backend/python/app/__init__.py b/backend/python/app/__init__.py index 380f1a0b..dd897625 100644 --- a/backend/python/app/__init__.py +++ b/backend/python/app/__init__.py @@ -5,6 +5,8 @@ from flask import Flask from flask.cli import ScriptInfo from flask_cors import CORS +from flask_limiter import Limiter +from flask_limiter.util import get_remote_address from flask_sqlalchemy import SQLAlchemy from logging.config import dictConfig @@ -47,6 +49,15 @@ def create_app(config_name): app.config["CORS_SUPPORTS_CREDENTIALS"] = True CORS(app) + default_minute_rate_limit = ( + os.getenv("BACKEND_API_DEFAULT_PER_MINUTE_RATE_LIMIT") or 15 + ) + Limiter( + app, + key_func=get_remote_address, + default_limits=[f"{default_minute_rate_limit} per minute"], + ) + if os.getenv("FLASK_CONFIG") != "production": app.config[ "SQLALCHEMY_DATABASE_URI" diff --git a/backend/python/requirements.txt b/backend/python/requirements.txt index 677e4320..279760c0 100644 --- a/backend/python/requirements.txt +++ b/backend/python/requirements.txt @@ -10,8 +10,9 @@ chardet==4.0.0 click==7.1.2 dnspython==1.16.0 firebase-admin==4.5.3 -Flask==1.1.2 +Flask==2.0.2 Flask-Cors==3.0.10 +Flask-Limiter==2.1.3 Flask-Migrate==3.0.1 Flask-SQLAlchemy==2.4.4 google-api-core==1.26.3 @@ -29,10 +30,10 @@ httplib2==0.19.1 idna==2.10 importlib-metadata==4.4.0 iniconfig==1.1.1 -itsdangerous==1.1.0 -Jinja2==2.11.2 +itsdangerous==2.0.1 +Jinja2==3.0.3 Mako==1.1.4 -MarkupSafe==1.1.1 +MarkupSafe==2.0.1 mongoengine==0.23.0 mongomock==3.23.0 msgpack==1.0.2 @@ -66,5 +67,5 @@ typed-ast==1.4.2 typing-extensions==3.7.4.3 uritemplate==3.0.1 urllib3==1.26.4 -Werkzeug==1.0.1 +Werkzeug==2.0.3 zipp==3.4.1 diff --git a/backend/typescript/graphql/index.ts b/backend/typescript/graphql/index.ts index 82c96d37..ea323860 100644 --- a/backend/typescript/graphql/index.ts +++ b/backend/typescript/graphql/index.ts @@ -1,6 +1,8 @@ import { makeExecutableSchema, gql } from "apollo-server-express"; import { applyMiddleware } from "graphql-middleware"; import { merge } from "lodash"; +import { createRateLimitRule } from "graphql-rate-limit"; +import { shield } from "graphql-shield"; import { isAuthorizedByEmail, @@ -56,4 +58,28 @@ const graphQLMiddlewares = { }, }; -export default applyMiddleware(executableSchema, graphQLMiddlewares); +const rateLimitRule = createRateLimitRule({ + identifyContext: (ctx) => ctx.id, + formatError: () => "Too many requests, please try again later.", +}); + +const defaultMinuteRateLimit = parseInt( + process.env.BACKEND_API_DEFAULT_PER_MINUTE_RATE_LIMIT || "15", + 10, +); + +const rateLimiters = shield( + {}, + { + fallbackRule: rateLimitRule({ + window: "1m", + max: defaultMinuteRateLimit, + }), + }, +); + +export default applyMiddleware( + executableSchema, + graphQLMiddlewares, + rateLimiters, +); diff --git a/backend/typescript/package.json b/backend/typescript/package.json index fbb1954c..428726d8 100644 --- a/backend/typescript/package.json +++ b/backend/typescript/package.json @@ -26,9 +26,12 @@ "cors": "^2.8.5", "dotenv": "^8.2.0", "express": "^4.17.1", + "express-rate-limit": "^6.2.0", "firebase-admin": "^9.5.0", "graphql": "^15.5.0", "graphql-middleware": "^6.0.6", + "graphql-rate-limit": "^3.3.0", + "graphql-shield": "^7.5.0", "graphql-upload": "^12.0.0", "json2csv": "^5.0.6", "lodash": "^4.17.21", diff --git a/backend/typescript/server.ts b/backend/typescript/server.ts index ff7717dc..42309ac0 100644 --- a/backend/typescript/server.ts +++ b/backend/typescript/server.ts @@ -1,6 +1,7 @@ import cookieParser from "cookie-parser"; import cors from "cors"; import express from "express"; +import RateLimit from "express-rate-limit"; import * as firebaseAdmin from "firebase-admin"; import swaggerUi from "swagger-ui-express"; import YAML from "yamljs"; @@ -27,11 +28,23 @@ const CORS_OPTIONS: cors.CorsOptions = { const swaggerDocument = YAML.load("swagger.yml"); +const defaultMinuteRateLimit = parseInt( + process.env.BACKEND_API_DEFAULT_PER_MINUTE_RATE_LIMIT || "15", + 10, +); +const limiter = RateLimit({ + windowMs: 1 * 60 * 1000, // 1 minute + max: defaultMinuteRateLimit, + standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers + legacyHeaders: false, // Disable the `X-RateLimit-*` headers +}); + const app = express(); app.use(cookieParser()); app.use(cors(CORS_OPTIONS)); app.use(express.json()); app.use(express.urlencoded({ extended: true })); +// app.use(limiter); app.use("/auth", authRouter); app.use("/entities", entityRouter); diff --git a/backend/typescript/yarn.lock b/backend/typescript/yarn.lock index f8d49854..913cab16 100644 --- a/backend/typescript/yarn.lock +++ b/backend/typescript/yarn.lock @@ -339,6 +339,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" +"@babel/runtime@^7.10.5": + version "7.17.0" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.0.tgz#b8d142fc0f7664fb3d9b5833fd40dcbab89276c0" + integrity sha512-etcO/ohMNaNA2UBdaXBBSX/3aEzFMRrVfaPv8Ptc0k+cWpWW0QFiGZ2XnVqQZI1Cf734LbPGmqBKWESfW4x/dQ== + dependencies: + regenerator-runtime "^0.13.4" + "@babel/template@^7.14.5", "@babel/template@^7.3.3": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.14.5.tgz#a9bc9d8b33354ff6e55a9c60d1109200a68974f4" @@ -544,6 +551,14 @@ is-promise "4.0.0" tslib "~2.1.0" +"@graphql-tools/merge@^8.2.1": + version "8.2.1" + resolved "https://registry.yarnpkg.com/@graphql-tools/merge/-/merge-8.2.1.tgz#bf83aa06a0cfc6a839e52a58057a84498d0d51ff" + integrity sha512-Q240kcUszhXiAYudjuJgNuLgy9CryDP3wp83NOZQezfA6h3ByYKU7xI6DiKrdjyVaGpYN3ppUmdj0uf5GaXzMA== + dependencies: + "@graphql-tools/utils" "^8.5.1" + tslib "~2.3.0" + "@graphql-tools/schema@^7.0.0", "@graphql-tools/schema@^7.1.3": version "7.1.3" resolved "https://registry.yarnpkg.com/@graphql-tools/schema/-/schema-7.1.3.tgz#d816400da51fbac1f0086e35540ab63b5e30e858" @@ -552,6 +567,16 @@ "@graphql-tools/utils" "^7.1.2" tslib "~2.1.0" +"@graphql-tools/schema@^8.0.0": + version "8.3.1" + resolved "https://registry.yarnpkg.com/@graphql-tools/schema/-/schema-8.3.1.tgz#1ee9da494d2da457643b3c93502b94c3c4b68c74" + integrity sha512-3R0AJFe715p4GwF067G5i0KCr/XIdvSfDLvTLEiTDQ8V/hwbOHEKHKWlEBHGRQwkG5lwFQlW1aOn7VnlPERnWQ== + dependencies: + "@graphql-tools/merge" "^8.2.1" + "@graphql-tools/utils" "^8.5.1" + tslib "~2.3.0" + value-or-promise "1.0.11" + "@graphql-tools/utils@^7.1.2", "@graphql-tools/utils@^7.7.0", "@graphql-tools/utils@^7.7.1": version "7.7.1" resolved "https://registry.yarnpkg.com/@graphql-tools/utils/-/utils-7.7.1.tgz#81f32cb4819b34b3a378d51ab2cd60935977f0b4" @@ -561,6 +586,22 @@ camel-case "4.1.2" tslib "~2.1.0" +"@graphql-tools/utils@^7.6.0": + version "7.10.0" + resolved "https://registry.yarnpkg.com/@graphql-tools/utils/-/utils-7.10.0.tgz#07a4cb5d1bec1ff1dc1d47a935919ee6abd38699" + integrity sha512-d334r6bo9mxdSqZW6zWboEnnOOFRrAPVQJ7LkU8/6grglrbcu6WhwCLzHb90E94JI3TD3ricC3YGbUqIi9Xg0w== + dependencies: + "@ardatan/aggregate-error" "0.0.6" + camel-case "4.1.2" + tslib "~2.2.0" + +"@graphql-tools/utils@^8.0.0", "@graphql-tools/utils@^8.5.1": + version "8.6.1" + resolved "https://registry.yarnpkg.com/@graphql-tools/utils/-/utils-8.6.1.tgz#52c7eb108f2ca2fd01bdba8eef85077ead1bf882" + integrity sha512-uxcfHCocp4ENoIiovPxUWZEHOnbXqj3ekWc0rm7fUhW93a1xheARNHcNKhwMTR+UKXVJbTFQdGI1Rl5XdyvDBg== + dependencies: + tslib "~2.3.0" + "@grpc/grpc-js@~1.2.0": version "1.2.10" resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.2.10.tgz#f316d29a45fcc324e923d593cb849d292b1ed598" @@ -1371,6 +1412,11 @@ dependencies: "@types/yargs-parser" "*" +"@types/yup@0.29.11": + version "0.29.11" + resolved "https://registry.yarnpkg.com/@types/yup/-/yup-0.29.11.tgz#d654a112973f5e004bf8438122bd7e56a8e5cd7e" + integrity sha512-9cwk3c87qQKZrT251EDoibiYRILjCmxBvvcb4meofCmx1vdnNcR9gyildy5vOHASpOKMsn42CugxUvcwK5eu1g== + "@typescript-eslint/eslint-plugin@^4.4.1": version "4.15.2" resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.15.2.tgz#981b26b4076c62a5a55873fbef3fe98f83360c61" @@ -3046,6 +3092,11 @@ expect@^27.0.6: jest-message-util "^27.0.6" jest-regex-util "^27.0.6" +express-rate-limit@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/express-rate-limit/-/express-rate-limit-6.2.0.tgz#be644be082d4d5da8c368aed07cef80152f6e218" + integrity sha512-q9xfttbPX79HiBsHA4LT3PZEeJR96CJ5/2jloAKSEECMx8XlOOOpjxx6iK/kBw3hFJ8uhx6Q9lCfSGp70yV0tQ== + express@^4.0.0, express@^4.17.1: version "4.17.1" resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134" @@ -3560,6 +3611,35 @@ graphql-middleware@^6.0.6: "@graphql-tools/delegate" "^7.1.1" "@graphql-tools/schema" "^7.1.3" +graphql-rate-limit-directive@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/graphql-rate-limit-directive/-/graphql-rate-limit-directive-2.0.0.tgz#cbebcaeefe5b4a0ac21e5981ccf6a5f2a292242b" + integrity sha512-+3HVJngzeWH7J8yTZ92Niu+9r8l7qCyyrXRe99DKvUdvaK3yC1qOVzja4aK7jctz31CECY6UC7Hvy3TJCWWD5Q== + dependencies: + "@graphql-tools/schema" "^8.0.0" + "@graphql-tools/utils" "^8.0.0" + graphql "^15.0.0" + rate-limiter-flexible "^2.0.0" + +graphql-rate-limit@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/graphql-rate-limit/-/graphql-rate-limit-3.3.0.tgz#241e3f6dc4cc3cbd139d63d40e2ce613f8485646" + integrity sha512-mbbEv5z3SjkDLvVVdHi0XrVLavw2Mwo93GIqgQB/fx8dhcNSEv3eYI1OGdp8mhsm/MsZm7hjrRlwQMVRKBVxhA== + dependencies: + "@graphql-tools/utils" "^7.6.0" + graphql-shield "^7.5.0" + lodash.get "^4.4.2" + ms "^2.1.3" + +graphql-shield@^7.5.0: + version "7.5.0" + resolved "https://registry.yarnpkg.com/graphql-shield/-/graphql-shield-7.5.0.tgz#aa3af226946946dfadac33eccc6cbe7fec6e9000" + integrity sha512-T1A6OreOe/dHDk/1Qg3AHCrKLmTkDJ3fPFGYpSOmUbYXyDnjubK4J5ab5FjHdKHK5fWQRZNTvA0SrBObYsyfaw== + dependencies: + "@types/yup" "0.29.11" + object-hash "^2.0.3" + yup "^0.31.0" + graphql-subscriptions@^1.0.0: version "1.2.1" resolved "https://registry.yarnpkg.com/graphql-subscriptions/-/graphql-subscriptions-1.2.1.tgz#2142b2d729661ddf967b7388f7cf1dd4cf2e061d" @@ -3605,6 +3685,11 @@ graphql-upload@^12.0.0: isobject "^4.0.0" object-path "^0.11.5" +graphql@^15.0.0: + version "15.8.0" + resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.8.0.tgz#33410e96b012fa3bdb1091cc99a94769db212b38" + integrity sha512-5gghUc24tP9HRznNpV2+FIoq3xKkj5dTQqf4v0CpdPbFVwFkWoxOM+o+2OC9ZSvjEMTjfmG9QT+gcvggTwW1zw== + graphql@^15.3.0: version "15.5.1" resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.5.1.tgz#f2f84415d8985e7b84731e7f3536f8bb9d383aad" @@ -4708,6 +4793,11 @@ locate-path@^5.0.0: dependencies: p-locate "^4.1.0" +lodash-es@^4.17.11: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee" + integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw== + lodash.camelcase@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" @@ -5057,7 +5147,7 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@^2.1.1: +ms@^2.1.1, ms@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -5184,6 +5274,11 @@ object-assign@^4, object-assign@^4.1.1: resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= +object-hash@^2.0.3: + version "2.2.0" + resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-2.2.0.tgz#5ad518581eefc443bd763472b8ff2e9c2c0d54a5" + integrity sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw== + object-inspect@^1.9.0: version "1.9.0" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.9.0.tgz#c90521d74e1127b67266ded3394ad6116986533a" @@ -5618,6 +5713,11 @@ prompts@^2.0.1: kleur "^3.0.3" sisteransi "^1.0.5" +property-expr@^2.0.4: + version "2.0.5" + resolved "https://registry.yarnpkg.com/property-expr/-/property-expr-2.0.5.tgz#278bdb15308ae16af3e3b9640024524f4dc02cb4" + integrity sha512-IJUkICM5dP5znhCckHSv30Q4b5/JA5enCtkRHYaOVOAocnH/1BQEYTC5NMfT3AVl/iXKdr3aqQbQn9DxyWknwA== + protobufjs@^6.10.2, protobufjs@^6.8.6: version "6.10.2" resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-6.10.2.tgz#b9cb6bd8ec8f87514592ba3fdfd28e93f33a469b" @@ -5699,6 +5799,11 @@ range-parser@~1.2.1: resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== +rate-limiter-flexible@^2.0.0: + version "2.3.6" + resolved "https://registry.yarnpkg.com/rate-limiter-flexible/-/rate-limiter-flexible-2.3.6.tgz#b1a2549dca91069c8a33d57c08a27262c0356c60" + integrity sha512-8DVFOe89rreyut/vzwBI7vgXJynyYoYnH5XogtAKs0F/neAbCTTglXxSJ7fZeZamcFXZDvMidCBvps4KM+1srw== + raw-body@2.4.0: version "2.4.0" resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332" @@ -5785,6 +5890,11 @@ reflect-metadata@^0.1.13: resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08" integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg== +regenerator-runtime@^0.13.4: + version "0.13.9" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" + integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== + regexp-clone@1.0.0, regexp-clone@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/regexp-clone/-/regexp-clone-1.0.0.tgz#222db967623277056260b992626354a04ce9bf63" @@ -6479,6 +6589,11 @@ toposort-class@^1.0.1: resolved "https://registry.yarnpkg.com/toposort-class/-/toposort-class-1.0.1.tgz#7ffd1f78c8be28c3ba45cd4e1a3f5ee193bd9988" integrity sha1-f/0feMi+KMO6Rc1OGj9e4ZO9mYg= +toposort@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/toposort/-/toposort-2.0.2.tgz#ae21768175d1559d48bef35420b2f4962f09c330" + integrity sha1-riF2gXXRVZ1IvvNUILL0li8JwzA= + touch@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/touch/-/touch-3.1.0.tgz#fe365f5f75ec9ed4e56825e0bb76d24ab74af83b" @@ -6559,12 +6674,12 @@ tslib@^1.10.0, tslib@^1.11.1, tslib@^1.8.1, tslib@^1.9.3: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.0.3: +tslib@^2.0.3, tslib@~2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.2.0.tgz#fb2c475977e35e241311ede2693cee1ec6698f5c" integrity sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w== -tslib@^2.1.0, tslib@^2.3.0: +tslib@^2.1.0, tslib@^2.3.0, tslib@~2.3.0: version "2.3.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== @@ -6773,6 +6888,11 @@ validator@^10.11.0: resolved "https://registry.yarnpkg.com/validator/-/validator-10.11.0.tgz#003108ea6e9a9874d31ccc9e5006856ccd76b228" integrity sha512-X/p3UZerAIsbBfN/IwahhYaBbY68EN/UQBWHtsbXGT5bfrH/p4NQzUCG1kF/rtKaNpnJ7jAu6NGTdSNtyNIXMw== +value-or-promise@1.0.11: + version "1.0.11" + resolved "https://registry.yarnpkg.com/value-or-promise/-/value-or-promise-1.0.11.tgz#3e90299af31dd014fe843fe309cefa7c1d94b140" + integrity sha512-41BrgH+dIbCFXClcSapVs5M6GkENd3gQOJpEfPDNa71LsUGMXDL0jMWpI/Rh7WhX+Aalfz2TTS3Zt5pUsbnhLg== + vary@^1, vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" @@ -7027,6 +7147,17 @@ yocto-queue@^0.1.0: resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== +yup@^0.31.0: + version "0.31.1" + resolved "https://registry.yarnpkg.com/yup/-/yup-0.31.1.tgz#0954cb181161f397b804346037a04f8a4b31599e" + integrity sha512-Lf6648jDYOWR75IlWkVfwesPyW6oj+50NpxlKvsQlpPsB8eI+ndI7b4S1VrwbmeV9hIZDu1MzrlIL4W+gK1jPw== + dependencies: + "@babel/runtime" "^7.10.5" + lodash "^4.17.20" + lodash-es "^4.17.11" + property-expr "^2.0.4" + toposort "^2.0.2" + zen-observable-ts@^0.8.21: version "0.8.21" resolved "https://registry.yarnpkg.com/zen-observable-ts/-/zen-observable-ts-0.8.21.tgz#85d0031fbbde1eba3cd07d3ba90da241215f421d" diff --git a/frontend/src/APIClients/AuthAPIClient.ts b/frontend/src/APIClients/AuthAPIClient.ts index 35a676f6..4f784e5a 100644 --- a/frontend/src/APIClients/AuthAPIClient.ts +++ b/frontend/src/APIClients/AuthAPIClient.ts @@ -144,13 +144,18 @@ const logout = async ( authenticatedUserId: string, logoutFunction: LogoutFunction, ): Promise => { - const result = await logoutFunction({ - variables: { userId: authenticatedUserId }, - }); let success = false; - if (result.data?.logout === null) { - success = true; - localStorage.removeItem(AUTHENTICATED_USER_KEY); + try { + const result = await logoutFunction({ + variables: { userId: authenticatedUserId }, + }); + if (result.data?.logout === null) { + success = true; + localStorage.removeItem(AUTHENTICATED_USER_KEY); + } + } catch (e: unknown) { + // eslint-disable-next-line no-alert + window.alert("Failed to logout"); } return success; }; @@ -175,12 +180,17 @@ type RefreshFunction = ( >; const refresh = async (refreshFunction: RefreshFunction): Promise => { - const result = await refreshFunction(); let success = false; - const token = result.data?.refresh; - if (token) { - success = true; - setLocalStorageObjProperty(AUTHENTICATED_USER_KEY, "accessToken", token); + try { + const result = await refreshFunction(); + const token = result.data?.refresh; + if (token) { + success = true; + setLocalStorageObjProperty(AUTHENTICATED_USER_KEY, "accessToken", token); + } + } catch (e: unknown) { + // eslint-disable-next-line no-alert + window.alert("Failed to refresh credentials"); } return success; };