From 274ed0d3bc3ba75e61f7cbe26394057b2e54eb03 Mon Sep 17 00:00:00 2001 From: Macharia Muguku Date: Wed, 6 Apr 2022 09:59:56 +0300 Subject: [PATCH 01/24] add connect redis and redis dependencies --- package.json | 3 ++ yarn.lock | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 102 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 6d0f0e9..1b4c273 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "@onaio/gatekeeper": "^0.1.2", "client-oauth2": "^4.3.3", "compression": "^1.7.4", + "connect-redis": "^6.1.3", "cookie-parser": "^1.4.6", "dotenv": "^16.0.0", "express": "^4.17.3", @@ -39,6 +40,7 @@ "react-redux": "^7.2.6", "react-router": "^5.2.1", "react-router-dom": "^5.2.1", + "redis": "^4.0.6", "redux": "^4.1.2", "request": "^2.88.0", "seamless-immutable": "^7.1.4", @@ -48,6 +50,7 @@ }, "devDependencies": { "@types/compression": "^1.7.2", + "@types/connect-redis": "^0.0.18", "@types/cookie-parser": "^1.4.2", "@types/express": "^4.17.13", "@types/express-session": "^1.17.4", diff --git a/yarn.lock b/yarn.lock index 036e5d8..60f61a4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -546,6 +546,41 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" +"@node-redis/bloom@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@node-redis/bloom/-/bloom-1.0.1.tgz#144474a0b7dc4a4b91badea2cfa9538ce0a1854e" + integrity sha512-mXEBvEIgF4tUzdIN89LiYsbi6//EdpFA7L8M+DHCvePXg+bfHWi+ct5VI6nHUFQE5+ohm/9wmgihCH3HSkeKsw== + +"@node-redis/client@1.0.5": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@node-redis/client/-/client-1.0.5.tgz#ebac5e2bbf12214042a37621604973a954ede755" + integrity sha512-ESZ3bd1f+od62h4MaBLKum+klVJfA4wAeLHcVQBkoXa1l0viFesOWnakLQqKg+UyrlJhZmXJWtu0Y9v7iTMrig== + dependencies: + cluster-key-slot "1.1.0" + generic-pool "3.8.2" + redis-parser "3.0.0" + yallist "4.0.0" + +"@node-redis/graph@1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@node-redis/graph/-/graph-1.0.0.tgz#baf8eaac4a400f86ea04d65ec3d65715fd7951ab" + integrity sha512-mRSo8jEGC0cf+Rm7q8mWMKKKqkn6EAnA9IA2S3JvUv/gaWW/73vil7GLNwion2ihTptAm05I9LkepzfIXUKX5g== + +"@node-redis/json@1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@node-redis/json/-/json-1.0.2.tgz#8ad2d0f026698dc1a4238cc3d1eb099a3bee5ab8" + integrity sha512-qVRgn8WfG46QQ08CghSbY4VhHFgaTY71WjpwRBGEuqGPfWwfRcIf3OqSpR7Q/45X+v3xd8mvYjywqh0wqJ8T+g== + +"@node-redis/search@1.0.5": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@node-redis/search/-/search-1.0.5.tgz#96050007eb7c50a7e47080320b4f12aca8cf94c4" + integrity sha512-MCOL8iCKq4v+3HgEQv8zGlSkZyXSXtERgrAJ4TSryIG/eLFy84b57KmNNa/V7M1Q2Wd2hgn2nPCGNcQtk1R1OQ== + +"@node-redis/time-series@1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@node-redis/time-series/-/time-series-1.0.2.tgz#5dd3638374edd85ebe0aa6b0e87addc88fb9df69" + integrity sha512-HGQ8YooJ8Mx7l28tD7XjtB3ImLEjlUxG1wC1PAjxu6hPJqjPshUZxAICzDqDjtIbhDTf48WXXUcx8TQJB1XTKA== + "@nodelib/fs.scandir@2.1.5": version "2.1.5" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" @@ -671,6 +706,16 @@ dependencies: "@types/express" "*" +"@types/connect-redis@^0.0.18": + version "0.0.18" + resolved "https://registry.yarnpkg.com/@types/connect-redis/-/connect-redis-0.0.18.tgz#f2dd17607626a741177efa22641cc2030924eda3" + integrity sha512-iGygGbXgPIr94DEAuoluWhzre3c2/ew5NPlbW9IWvwCTXMM1YCmc7M9wpXMkYqt6kB9aO1sjZnmDzyugUu+2vQ== + dependencies: + "@types/express" "*" + "@types/express-session" "*" + "@types/ioredis" "*" + "@types/redis" "^2.8.0" + "@types/connect@*": version "3.4.35" resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.35.tgz#5fcf6ae445e4021d1fc2219a4873cc73a3bb2ad1" @@ -743,6 +788,13 @@ "@types/react" "*" hoist-non-react-statics "^3.3.0" +"@types/ioredis@*": + version "4.28.10" + resolved "https://registry.yarnpkg.com/@types/ioredis/-/ioredis-4.28.10.tgz#40ceb157a4141088d1394bb87c98ed09a75a06ff" + integrity sha512-69LyhUgrXdgcNDv7ogs1qXZomnfOEnSmrmMFqKgt1XMJxmoOSG/u3wYy13yACIfKuMJ8IhKgHafDO3sx19zVQQ== + dependencies: + "@types/node" "*" + "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": version "2.0.4" resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz#8467d4b3c087805d63580480890791277ce35c44" @@ -857,6 +909,13 @@ "@types/scheduler" "*" csstype "^3.0.2" +"@types/redis@^2.8.0": + version "2.8.32" + resolved "https://registry.yarnpkg.com/@types/redis/-/redis-2.8.32.tgz#1d3430219afbee10f8cfa389dad2571a05ecfb11" + integrity sha512-7jkMKxcGq9p242exlbsVzuJb57KqHRhNl4dHoQu2Y5v9bCAbtIXXH0R3HleSQW4CTOqpHIYUW3t6tpUj4BVQ+w== + dependencies: + "@types/node" "*" + "@types/request@^2.48.8": version "2.48.8" resolved "https://registry.yarnpkg.com/@types/request/-/request-2.48.8.tgz#0b90fde3b655ab50976cb8c5ac00faca22f5a82c" @@ -1586,6 +1645,11 @@ clone-response@^1.0.2: dependencies: mimic-response "^1.0.0" +cluster-key-slot@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz#30474b2a981fb12172695833052bc0d01336d10d" + integrity sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw== + co@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" @@ -1708,6 +1772,11 @@ confusing-browser-globals@^1.0.10: resolved "https://registry.yarnpkg.com/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz#ae40e9b57cdd3915408a2805ebd3a5585608dc81" integrity sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA== +connect-redis@^6.1.3: + version "6.1.3" + resolved "https://registry.yarnpkg.com/connect-redis/-/connect-redis-6.1.3.tgz#0a83c953f9ece45ae37d304a8e8d1c3c6a60b4b9" + integrity sha512-aaNluLlAn/3JPxRwdzw7lhvEoU6Enb+d83xnokUNhC9dktqBoawKWL+WuxinxvBLTz6q9vReTnUDnUslaz74aw== + content-disposition@0.5.4: version "0.5.4" resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" @@ -2643,6 +2712,11 @@ functional-red-black-tree@^1.0.1: resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= +generic-pool@3.8.2: + version "3.8.2" + resolved "https://registry.yarnpkg.com/generic-pool/-/generic-pool-3.8.2.tgz#aab4f280adb522fdfbdc5e5b64d718d3683f04e9" + integrity sha512-nGToKy6p3PAbYQ7p1UlWl6vSPwfwU6TMSWK7TTu+WUY4ZjyZQGniGGt2oNVvyNSpyZYSB43zMXVLcBm08MTMkg== + gensync@^1.0.0-beta.2: version "1.0.0-beta.2" resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" @@ -4913,6 +4987,30 @@ readdirp@~3.6.0: dependencies: picomatch "^2.2.1" +redis-errors@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/redis-errors/-/redis-errors-1.2.0.tgz#eb62d2adb15e4eaf4610c04afe1529384250abad" + integrity sha1-62LSrbFeTq9GEMBK/hUpOEJQq60= + +redis-parser@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-3.0.0.tgz#b66d828cdcafe6b4b8a428a7def4c6bcac31c8b4" + integrity sha1-tm2CjNyv5rS4pCin3vTGvKwxyLQ= + dependencies: + redis-errors "^1.0.0" + +redis@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/redis/-/redis-4.0.6.tgz#a2ded4d9f4f4bad148e54781051618fc684cd858" + integrity sha512-IaPAxgF5dV0jx+A9l6yd6R9/PAChZIoAskDVRzUODeLDNhsMlq7OLLTmu0AwAr0xjrJ1bibW5xdpRwqIQ8Q0Xg== + dependencies: + "@node-redis/bloom" "1.0.1" + "@node-redis/client" "1.0.5" + "@node-redis/graph" "1.0.0" + "@node-redis/json" "1.0.2" + "@node-redis/search" "1.0.5" + "@node-redis/time-series" "1.0.2" + redux@^4.0.0, redux@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/redux/-/redux-4.1.2.tgz#140f35426d99bb4729af760afcf79eaaac407104" @@ -6084,7 +6182,7 @@ y18n@^5.0.5: resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== -yallist@^4.0.0: +yallist@4.0.0, yallist@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== From a86c37861453f8b78cba5205f25fdf45243a14dc Mon Sep 17 00:00:00 2001 From: Macharia Muguku Date: Wed, 6 Apr 2022 10:02:59 +0300 Subject: [PATCH 02/24] add support for redis session store --- src/app/index.ts | 42 ++++++++++++++++++++++++++++++++++-------- src/configs/envs.ts | 2 ++ 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/src/app/index.ts b/src/app/index.ts index de8745a..8cbf877 100644 --- a/src/app/index.ts +++ b/src/app/index.ts @@ -4,6 +4,8 @@ import compression from 'compression'; import cookieParser from 'cookie-parser'; import express from 'express'; import session from 'express-session'; +import connectRedis from 'connect-redis'; +import { createClient } from 'redis'; import helmet from 'helmet'; import fetch from 'node-fetch'; import morgan from 'morgan'; @@ -34,6 +36,7 @@ import { EXPRESS_SESSION_NAME, EXPRESS_SESSION_PATH, EXPRESS_SESSION_SECRET, + EXPRESS_REDIS_URL, } from '../configs/envs'; import { SESSION_IS_EXPIRED, TOKEN_NOT_FOUND, TOKEN_REFRESH_FAILED } from '../constants'; import { getOriginFromUrl } from '../utils'; @@ -76,14 +79,37 @@ app.use( crossOriginEmbedderPolicy: false, }), ); -app.use(morgan('combined', { stream: winstonStream })); // send logs to winston +app.use(morgan('combined', { stream: winstonStream })); // send request logs to winston streamer -const FileStore = sessionFileStore(session); -const fileStoreOptions: sessionFileStore.Options = { - path: EXPRESS_SESSION_FILESTORE_PATH || './sessions', - // channel session-file-store warnings to winston - logFn: (message) => winstonLogger.info(message), -}; +let sessionStore: session.Store; + +// use redis session store if redis is available +if (EXPRESS_REDIS_URL !== undefined) { + const RedisStore = connectRedis(session); + const redisClient = createClient({ + legacyMode: true, + url: EXPRESS_REDIS_URL, + }); + + redisClient.on('connect', () => winstonLogger.info('Redis client connected!')); + redisClient.on('error', (err) => winstonLogger.error('Redis error:', err)); + redisClient.on('reconnecting', () => winstonLogger.info('Redis trying to reconnect')); + redisClient.on('end', () => winstonLogger.error('Redis client disconnected')); + + redisClient.connect().catch((err) => winstonLogger.error(err)); + + sessionStore = new RedisStore({ client: redisClient }); +} +// else default to file store +else { + winstonLogger.error('Redis Connection Error: Redis url not defined, using file session store'); + + const FileStore = sessionFileStore(session); + sessionStore = new FileStore({ + path: EXPRESS_SESSION_FILESTORE_PATH || './sessions', + logFn: (message) => winstonLogger.info(message), + }); +} let nextPath: string | undefined; @@ -97,7 +123,7 @@ const sess = { resave: true, saveUninitialized: true, secret: EXPRESS_SESSION_SECRET || 'hunter2', - store: new FileStore(fileStoreOptions), + store: sessionStore, }; if (app.get('env') === 'production') { diff --git a/src/configs/envs.ts b/src/configs/envs.ts index a97b419..74d3835 100644 --- a/src/configs/envs.ts +++ b/src/configs/envs.ts @@ -98,3 +98,5 @@ export type EXPRESS_LOGS_FILE_PATH = typeof EXPRESS_LOGS_FILE_PATH; export const EXPRESS_COMBINED_LOGS_FILE_PATH = process.env.EXPRESS_COMBINED_LOGS_FILE_PATH || './logs/default-error-and-info.log'; export type EXPRESS_COMBINED_LOGS_FILE_PATH = typeof EXPRESS_COMBINED_LOGS_FILE_PATH; + +export const { EXPRESS_REDIS_URL } = process.env; From 668e2849da54d9dcbcb782ef33049cbdb8177e26 Mon Sep 17 00:00:00 2001 From: Macharia Muguku Date: Wed, 6 Apr 2022 10:04:29 +0300 Subject: [PATCH 03/24] connect-redis throws missing interface error --- src/types/index.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/types/index.ts b/src/types/index.ts index 6b1f681..90c1f25 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -1,8 +1,14 @@ +/* eslint-disable @typescript-eslint/no-empty-interface */ +/* eslint-disable @typescript-eslint/no-explicit-any */ import 'express-session'; +import 'redis'; declare module 'express-session' { interface Session { - // eslint-disable-next-line @typescript-eslint/no-explicit-any preloadedState?: Record; } } + +declare module 'redis' { + interface RedisClient {} +} From fb8046439895edf14ec19ba5e5a95af435dcd00a Mon Sep 17 00:00:00 2001 From: Macharia Muguku Date: Sat, 16 Apr 2022 05:48:17 +0300 Subject: [PATCH 04/24] switch to ioredis - supports sentinel and redis clusters --- package.json | 1 + src/app/index.ts | 13 ++++------- src/configs/envs.ts | 1 + yarn.lock | 53 ++++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 56 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index 1b4c273..4c3bd40 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "express": "^4.17.3", "express-session": "^1.17.2", "helmet": "^5.0.2", + "ioredis": "^5.0.4", "morgan": "^1.10.0", "node-fetch": "2.6.7", "react": "^17.0.2", diff --git a/src/app/index.ts b/src/app/index.ts index 8cbf877..ad1278e 100644 --- a/src/app/index.ts +++ b/src/app/index.ts @@ -5,7 +5,7 @@ import cookieParser from 'cookie-parser'; import express from 'express'; import session from 'express-session'; import connectRedis from 'connect-redis'; -import { createClient } from 'redis'; +import Redis from 'ioredis'; import helmet from 'helmet'; import fetch from 'node-fetch'; import morgan from 'morgan'; @@ -86,17 +86,12 @@ let sessionStore: session.Store; // use redis session store if redis is available if (EXPRESS_REDIS_URL !== undefined) { const RedisStore = connectRedis(session); - const redisClient = createClient({ - legacyMode: true, - url: EXPRESS_REDIS_URL, - }); + const redisClient = new Redis(EXPRESS_REDIS_URL); redisClient.on('connect', () => winstonLogger.info('Redis client connected!')); - redisClient.on('error', (err) => winstonLogger.error('Redis error:', err)); redisClient.on('reconnecting', () => winstonLogger.info('Redis trying to reconnect')); - redisClient.on('end', () => winstonLogger.error('Redis client disconnected')); - - redisClient.connect().catch((err) => winstonLogger.error(err)); + redisClient.on('error', (err) => winstonLogger.error('Redis error:', err)); + redisClient.on('end', () => winstonLogger.error('Redis error: Redis client disconnected')); sessionStore = new RedisStore({ client: redisClient }); } diff --git a/src/configs/envs.ts b/src/configs/envs.ts index 74d3835..6801a6b 100644 --- a/src/configs/envs.ts +++ b/src/configs/envs.ts @@ -99,4 +99,5 @@ export const EXPRESS_COMBINED_LOGS_FILE_PATH = process.env.EXPRESS_COMBINED_LOGS_FILE_PATH || './logs/default-error-and-info.log'; export type EXPRESS_COMBINED_LOGS_FILE_PATH = typeof EXPRESS_COMBINED_LOGS_FILE_PATH; +// see https://github.com/luin/ioredis#connect-to-redis export const { EXPRESS_REDIS_URL } = process.env; diff --git a/yarn.lock b/yarn.lock index 60f61a4..f816f4b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -343,6 +343,11 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== +"@ioredis/commands@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@ioredis/commands/-/commands-1.1.1.tgz#2ba4299ea624a6bfac15b35f6df90b0015691ec3" + integrity sha512-fsR4P/ROllzf/7lXYyElUJCheWdTJVJvOTps8v9IWKFATxR61ANOlnoPqhH099xYLrJGpc2ZQ28B3rMeUt5VQg== + "@istanbuljs/load-nyc-config@^1.0.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" @@ -1645,7 +1650,7 @@ clone-response@^1.0.2: dependencies: mimic-response "^1.0.0" -cluster-key-slot@1.1.0: +cluster-key-slot@1.1.0, cluster-key-slot@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz#30474b2a981fb12172695833052bc0d01336d10d" integrity sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw== @@ -1924,6 +1929,13 @@ debug@^3.2.7: dependencies: ms "^2.1.1" +debug@^4.3.4: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + decimal.js@^10.2.1: version "10.3.1" resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.3.1.tgz#d8c3a444a9c6774ba60ca6ad7261c3a94fd5e783" @@ -1978,6 +1990,11 @@ delayed-stream@~1.0.0: resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= +denque@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/denque/-/denque-2.0.1.tgz#bcef4c1b80dc32efe97515744f21a4229ab8934a" + integrity sha512-tfiWc6BQLXNLpNiR5iGd0Ocu3P3VpxfzFiqubLgMfhfOw9WyvgJBd46CClNn9k3qfbjvT//0cf7AlYRX/OslMQ== + depd@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" @@ -3089,6 +3106,21 @@ internal-slot@^1.0.3: has "^1.0.3" side-channel "^1.0.4" +ioredis@^5.0.4: + version "5.0.4" + resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-5.0.4.tgz#0d4abfd818adfc5ef5029fddac4b8f503a1433b7" + integrity sha512-qFJw3MnPNsJF1lcIOP3vztbsasOXK3nDdNAgjQj7t7/Bn/w10PGchTOpqylQNxjzPbLoYDu34LjeJtSWiKBntQ== + dependencies: + "@ioredis/commands" "^1.1.1" + cluster-key-slot "^1.1.0" + debug "^4.3.4" + denque "^2.0.1" + lodash.defaults "^4.2.0" + lodash.isarguments "^3.1.0" + redis-errors "^1.2.0" + redis-parser "^3.0.0" + standard-as-callback "^2.1.0" + ip-regex@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" @@ -3994,6 +4026,16 @@ locate-path@^5.0.0: dependencies: p-locate "^4.1.0" +lodash.defaults@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" + integrity sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw= + +lodash.isarguments@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" + integrity sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo= + lodash.isfunction@^3.0.9: version "3.0.9" resolved "https://registry.yarnpkg.com/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz#06de25df4db327ac931981d1bdb067e5af68d051" @@ -4987,12 +5029,12 @@ readdirp@~3.6.0: dependencies: picomatch "^2.2.1" -redis-errors@^1.0.0: +redis-errors@^1.0.0, redis-errors@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/redis-errors/-/redis-errors-1.2.0.tgz#eb62d2adb15e4eaf4610c04afe1529384250abad" integrity sha1-62LSrbFeTq9GEMBK/hUpOEJQq60= -redis-parser@3.0.0: +redis-parser@3.0.0, redis-parser@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-3.0.0.tgz#b66d828cdcafe6b4b8a428a7def4c6bcac31c8b4" integrity sha1-tm2CjNyv5rS4pCin3vTGvKwxyLQ= @@ -5451,6 +5493,11 @@ stack-utils@^2.0.3: dependencies: escape-string-regexp "^2.0.0" +standard-as-callback@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/standard-as-callback/-/standard-as-callback-2.1.0.tgz#8953fc05359868a77b5b9739a665c5977bb7df45" + integrity sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A== + "statuses@>= 1.5.0 < 2", statuses@~1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" From 0a8d0fcdc6326df410e04021d1ab7cb669ce7a87 Mon Sep 17 00:00:00 2001 From: Macharia Muguku Date: Sat, 16 Apr 2022 05:50:06 +0300 Subject: [PATCH 05/24] implement retry strategy - retry after every 2 seconds, stop trying after 20 attempts --- src/app/index.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/app/index.ts b/src/app/index.ts index ad1278e..d836476 100644 --- a/src/app/index.ts +++ b/src/app/index.ts @@ -86,7 +86,17 @@ let sessionStore: session.Store; // use redis session store if redis is available if (EXPRESS_REDIS_URL !== undefined) { const RedisStore = connectRedis(session); - const redisClient = new Redis(EXPRESS_REDIS_URL); + const redisClient = new Redis(EXPRESS_REDIS_URL, { + retryStrategy(times) { + // wait 2 seconds between retries + const delay = 2000; + // stop retrying to reconnect after 20th attempt + if (times >= 20) { + return undefined; + } + return delay; + }, + }); redisClient.on('connect', () => winstonLogger.info('Redis client connected!')); redisClient.on('reconnecting', () => winstonLogger.info('Redis trying to reconnect')); From 7bf523b5b8ccb74bf96ea1f6f794078ba059f0a3 Mon Sep 17 00:00:00 2001 From: Macharia Muguku Date: Thu, 28 Apr 2022 08:37:23 +0300 Subject: [PATCH 06/24] switch from basic redis connection to redis sentinel --- src/app/index.ts | 30 +++++++++++++++++++++++------- src/configs/envs.ts | 8 ++++++-- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/src/app/index.ts b/src/app/index.ts index d836476..61a8f2d 100644 --- a/src/app/index.ts +++ b/src/app/index.ts @@ -36,7 +36,9 @@ import { EXPRESS_SESSION_NAME, EXPRESS_SESSION_PATH, EXPRESS_SESSION_SECRET, - EXPRESS_REDIS_URL, + EXPRESS_REDIS_SENTINEL_CONFIG, + EXPRESS_REDIS_DELAY_TIME, + EXPRESS_REDIS_MAX_RETRY_TIMES, } from '../configs/envs'; import { SESSION_IS_EXPIRED, TOKEN_NOT_FOUND, TOKEN_REFRESH_FAILED } from '../constants'; import { getOriginFromUrl } from '../utils'; @@ -84,14 +86,28 @@ app.use(morgan('combined', { stream: winstonStream })); // send request logs to let sessionStore: session.Store; // use redis session store if redis is available -if (EXPRESS_REDIS_URL !== undefined) { +if (EXPRESS_REDIS_SENTINEL_CONFIG !== undefined) { + // parse redis sentinel config from string to object + const parsedSentinelConfigs = JSON.parse(EXPRESS_REDIS_SENTINEL_CONFIG); + // delay time between redis connection retries (in milliseconds) + const delay = parseInt(EXPRESS_REDIS_DELAY_TIME, 10); + const maxRetries = parseInt(EXPRESS_REDIS_MAX_RETRY_TIMES, 10); + const RedisStore = connectRedis(session); - const redisClient = new Redis(EXPRESS_REDIS_URL, { + + const redisClient = new Redis({ + ...parsedSentinelConfigs, + // retry when all sentinel nodes are unreachable during connecting + sentinelRetryStrategy(times) { + // stop retrying to reconnect after nth attempt + if (times >= maxRetries) { + return undefined; + } + return delay; + }, + // retry to reconnect when connection to Redis is lost retryStrategy(times) { - // wait 2 seconds between retries - const delay = 2000; - // stop retrying to reconnect after 20th attempt - if (times >= 20) { + if (times >= maxRetries) { return undefined; } return delay; diff --git a/src/configs/envs.ts b/src/configs/envs.ts index 6801a6b..6654ab8 100644 --- a/src/configs/envs.ts +++ b/src/configs/envs.ts @@ -99,5 +99,9 @@ export const EXPRESS_COMBINED_LOGS_FILE_PATH = process.env.EXPRESS_COMBINED_LOGS_FILE_PATH || './logs/default-error-and-info.log'; export type EXPRESS_COMBINED_LOGS_FILE_PATH = typeof EXPRESS_COMBINED_LOGS_FILE_PATH; -// see https://github.com/luin/ioredis#connect-to-redis -export const { EXPRESS_REDIS_URL } = process.env; +// see https://github.com/luin/ioredis#sentinel +export const { + EXPRESS_REDIS_SENTINEL_CONFIG, + EXPRESS_REDIS_DELAY_TIME = '2000', + EXPRESS_REDIS_MAX_RETRY_TIMES = '20', +} = process.env; From 3c71ec3bb90cb67ffd7259c52b96bde736ac4783 Mon Sep 17 00:00:00 2001 From: Macharia Muguku Date: Thu, 2 Jun 2022 16:20:32 +0300 Subject: [PATCH 07/24] simplify config - default delay and retry times, parse config on env file, check if config object has keys, add sample env --- .env.sample | 2 ++ src/app/index.ts | 24 ++++++++---------------- src/configs/envs.ts | 6 +----- 3 files changed, 11 insertions(+), 21 deletions(-) diff --git a/.env.sample b/.env.sample index 01e62ea..b95948a 100644 --- a/.env.sample +++ b/.env.sample @@ -34,3 +34,5 @@ EXPRESS_LOGS_FILE_PATH='/home/.express/reveal-express-server.log # https://github.com/helmetjs/helmet#reference EXPRESS_CONTENT_SECURITY_POLICY_CONFIG=`{"default-src":["'self'"]}` + +EXPRESS_REDIS_SENTINEL_CONFIG='{"name":"master","sentinelUsername":"u_name","sentinelPassword":"pass","db":4,"sentinels":[{"host":"127.0.0.1","port":6379},{"host":"127.0.0.1","port":6379}]}' diff --git a/src/app/index.ts b/src/app/index.ts index d4579e3..05e2e6a 100644 --- a/src/app/index.ts +++ b/src/app/index.ts @@ -37,8 +37,6 @@ import { EXPRESS_SESSION_PATH, EXPRESS_SESSION_SECRET, EXPRESS_REDIS_SENTINEL_CONFIG, - EXPRESS_REDIS_DELAY_TIME, - EXPRESS_REDIS_MAX_RETRY_TIMES, EXPRESS_CONTENT_SECURITY_POLICY_CONFIG, } from '../configs/envs'; import { SESSION_IS_EXPIRED, TOKEN_NOT_FOUND, TOKEN_REFRESH_FAILED } from '../constants'; @@ -76,32 +74,26 @@ app.use(morgan('combined', { stream: winstonStream })); // send request logs to let sessionStore: session.Store; -// use redis session store if redis is available -if (EXPRESS_REDIS_SENTINEL_CONFIG !== undefined) { - // parse redis sentinel config from string to object - const parsedSentinelConfigs = JSON.parse(EXPRESS_REDIS_SENTINEL_CONFIG); - // delay time between redis connection retries (in milliseconds) - const delay = parseInt(EXPRESS_REDIS_DELAY_TIME, 10); - const maxRetries = parseInt(EXPRESS_REDIS_MAX_RETRY_TIMES, 10); - +// use redis session store if redis config is available +if (Object.keys(EXPRESS_REDIS_SENTINEL_CONFIG).length > 0) { const RedisStore = connectRedis(session); const redisClient = new Redis({ - ...parsedSentinelConfigs, + ...EXPRESS_REDIS_SENTINEL_CONFIG, // retry when all sentinel nodes are unreachable during connecting sentinelRetryStrategy(times) { - // stop retrying to reconnect after nth attempt - if (times >= maxRetries) { + // stop retrying to reconnect after 20th attempt + if (times >= 20) { return undefined; } - return delay; + return 2000; }, // retry to reconnect when connection to Redis is lost retryStrategy(times) { - if (times >= maxRetries) { + if (times >= 20) { return undefined; } - return delay; + return 2000; }, }); diff --git a/src/configs/envs.ts b/src/configs/envs.ts index 385af45..1556622 100644 --- a/src/configs/envs.ts +++ b/src/configs/envs.ts @@ -108,8 +108,4 @@ export const EXPRESS_CONTENT_SECURITY_POLICY_CONFIG = JSON.parse( export type EXPRESS_CONTENT_SECURITY_POLICY_CONFIG = typeof EXPRESS_CONTENT_SECURITY_POLICY_CONFIG; // see https://github.com/luin/ioredis#sentinel -export const { - EXPRESS_REDIS_SENTINEL_CONFIG, - EXPRESS_REDIS_DELAY_TIME = '2000', - EXPRESS_REDIS_MAX_RETRY_TIMES = '20', -} = process.env; +export const EXPRESS_REDIS_SENTINEL_CONFIG = JSON.parse(process.env.EXPRESS_REDIS_SENTINEL_CONFIG || '{}'); From 09e93bd1d7ddea1e552423e0c5b604c40b252160 Mon Sep 17 00:00:00 2001 From: Macharia Muguku Date: Thu, 2 Jun 2022 17:16:58 +0300 Subject: [PATCH 08/24] add support for redis single node client --- src/app/index.ts | 36 +++++++++++++++++++++++++++++------- src/configs/envs.ts | 3 +++ 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/src/app/index.ts b/src/app/index.ts index 05e2e6a..3ece23f 100644 --- a/src/app/index.ts +++ b/src/app/index.ts @@ -36,6 +36,7 @@ import { EXPRESS_SESSION_NAME, EXPRESS_SESSION_PATH, EXPRESS_SESSION_SECRET, + EXPRESS_REDIS_URL, EXPRESS_REDIS_SENTINEL_CONFIG, EXPRESS_CONTENT_SECURITY_POLICY_CONFIG, } from '../configs/envs'; @@ -74,8 +75,31 @@ app.use(morgan('combined', { stream: winstonStream })); // send request logs to let sessionStore: session.Store; -// use redis session store if redis config is available -if (Object.keys(EXPRESS_REDIS_SENTINEL_CONFIG).length > 0) { +// use redis session store if redis is available else default to file store +// check for and use a single redis node +if (EXPRESS_REDIS_URL !== undefined) { + const RedisStore = connectRedis(session); + const redisClient = new Redis(EXPRESS_REDIS_URL, { + retryStrategy(times) { + // wait 2 seconds between retries + const delay = 2000; + // stop retrying to reconnect after 20th attempt + if (times >= 20) { + return undefined; + } + return delay; + }, + }); + + redisClient.on('connect', () => winstonLogger.info('Redis single node client connected!')); + redisClient.on('reconnecting', () => winstonLogger.info('Redis trying to reconnect')); + redisClient.on('error', (err) => winstonLogger.error('Redis error:', err)); + redisClient.on('end', () => winstonLogger.error('Redis error: Redis client disconnected')); + + sessionStore = new RedisStore({ client: redisClient }); +} +// check for and use redis sentinel if available +else if (Object.keys(EXPRESS_REDIS_SENTINEL_CONFIG).length > 0) { const RedisStore = connectRedis(session); const redisClient = new Redis({ @@ -97,16 +121,14 @@ if (Object.keys(EXPRESS_REDIS_SENTINEL_CONFIG).length > 0) { }, }); - redisClient.on('connect', () => winstonLogger.info('Redis client connected!')); + redisClient.on('connect', () => winstonLogger.info('Redis sentinel client connected!')); redisClient.on('reconnecting', () => winstonLogger.info('Redis trying to reconnect')); redisClient.on('error', (err) => winstonLogger.error('Redis error:', err)); redisClient.on('end', () => winstonLogger.error('Redis error: Redis client disconnected')); sessionStore = new RedisStore({ client: redisClient }); -} -// else default to file store -else { - winstonLogger.error('Redis Connection Error: Redis url not defined, using file session store'); +} else { + winstonLogger.error('Redis Connection Error: Redis configs not provided using file session store'); const FileStore = sessionFileStore(session); sessionStore = new FileStore({ diff --git a/src/configs/envs.ts b/src/configs/envs.ts index 1556622..486e62c 100644 --- a/src/configs/envs.ts +++ b/src/configs/envs.ts @@ -107,5 +107,8 @@ export const EXPRESS_CONTENT_SECURITY_POLICY_CONFIG = JSON.parse( ); export type EXPRESS_CONTENT_SECURITY_POLICY_CONFIG = typeof EXPRESS_CONTENT_SECURITY_POLICY_CONFIG; +// see https://github.com/luin/ioredis#connect-to-redis +export const { EXPRESS_REDIS_URL } = process.env; + // see https://github.com/luin/ioredis#sentinel export const EXPRESS_REDIS_SENTINEL_CONFIG = JSON.parse(process.env.EXPRESS_REDIS_SENTINEL_CONFIG || '{}'); From 7bf11b7549409db86538dfc860d22586622a9d19 Mon Sep 17 00:00:00 2001 From: Macharia Muguku Date: Thu, 2 Jun 2022 17:31:17 +0300 Subject: [PATCH 09/24] add context to logs --- src/app/index.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/app/index.ts b/src/app/index.ts index 3ece23f..b1fc8cd 100644 --- a/src/app/index.ts +++ b/src/app/index.ts @@ -92,9 +92,9 @@ if (EXPRESS_REDIS_URL !== undefined) { }); redisClient.on('connect', () => winstonLogger.info('Redis single node client connected!')); - redisClient.on('reconnecting', () => winstonLogger.info('Redis trying to reconnect')); - redisClient.on('error', (err) => winstonLogger.error('Redis error:', err)); - redisClient.on('end', () => winstonLogger.error('Redis error: Redis client disconnected')); + redisClient.on('reconnecting', () => winstonLogger.info('Redis single node client trying to reconnect')); + redisClient.on('error', (err) => winstonLogger.error('Redis single node client error:', err)); + redisClient.on('end', () => winstonLogger.error('Redis single node client error: Redis client disconnected')); sessionStore = new RedisStore({ client: redisClient }); } @@ -122,9 +122,9 @@ else if (Object.keys(EXPRESS_REDIS_SENTINEL_CONFIG).length > 0) { }); redisClient.on('connect', () => winstonLogger.info('Redis sentinel client connected!')); - redisClient.on('reconnecting', () => winstonLogger.info('Redis trying to reconnect')); - redisClient.on('error', (err) => winstonLogger.error('Redis error:', err)); - redisClient.on('end', () => winstonLogger.error('Redis error: Redis client disconnected')); + redisClient.on('reconnecting', () => winstonLogger.info('Redis sentinel client trying to reconnect')); + redisClient.on('error', (err) => winstonLogger.error('Redis sentinel client error:', err)); + redisClient.on('end', () => winstonLogger.error('Redis sentinel client error: Redis client disconnected')); sessionStore = new RedisStore({ client: redisClient }); } else { From ee14996a594aa9144dd9afc31b30b77d9bc6d87c Mon Sep 17 00:00:00 2001 From: Macharia Muguku Date: Thu, 2 Jun 2022 18:17:21 +0300 Subject: [PATCH 10/24] add test redis url --- .env.sample | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.env.sample b/.env.sample index b95948a..62aeda4 100644 --- a/.env.sample +++ b/.env.sample @@ -35,4 +35,6 @@ EXPRESS_LOGS_FILE_PATH='/home/.express/reveal-express-server.log # https://github.com/helmetjs/helmet#reference EXPRESS_CONTENT_SECURITY_POLICY_CONFIG=`{"default-src":["'self'"]}` +EXPRESS_REDIS_URL=redis://username:authpassword@127.0.0.1:6379/4 + EXPRESS_REDIS_SENTINEL_CONFIG='{"name":"master","sentinelUsername":"u_name","sentinelPassword":"pass","db":4,"sentinels":[{"host":"127.0.0.1","port":6379},{"host":"127.0.0.1","port":6379}]}' From e2cd42c674242f7ef8d450b72bf6eb723f3e1f1e Mon Sep 17 00:00:00 2001 From: Macharia Muguku Date: Thu, 2 Jun 2022 18:42:59 +0300 Subject: [PATCH 11/24] use the default retry strategy - dont stop retrying after 20 tries --- src/app/index.ts | 27 +-------------------------- 1 file changed, 1 insertion(+), 26 deletions(-) diff --git a/src/app/index.ts b/src/app/index.ts index b1fc8cd..e6a3199 100644 --- a/src/app/index.ts +++ b/src/app/index.ts @@ -79,17 +79,7 @@ let sessionStore: session.Store; // check for and use a single redis node if (EXPRESS_REDIS_URL !== undefined) { const RedisStore = connectRedis(session); - const redisClient = new Redis(EXPRESS_REDIS_URL, { - retryStrategy(times) { - // wait 2 seconds between retries - const delay = 2000; - // stop retrying to reconnect after 20th attempt - if (times >= 20) { - return undefined; - } - return delay; - }, - }); + const redisClient = new Redis(EXPRESS_REDIS_URL); redisClient.on('connect', () => winstonLogger.info('Redis single node client connected!')); redisClient.on('reconnecting', () => winstonLogger.info('Redis single node client trying to reconnect')); @@ -104,21 +94,6 @@ else if (Object.keys(EXPRESS_REDIS_SENTINEL_CONFIG).length > 0) { const redisClient = new Redis({ ...EXPRESS_REDIS_SENTINEL_CONFIG, - // retry when all sentinel nodes are unreachable during connecting - sentinelRetryStrategy(times) { - // stop retrying to reconnect after 20th attempt - if (times >= 20) { - return undefined; - } - return 2000; - }, - // retry to reconnect when connection to Redis is lost - retryStrategy(times) { - if (times >= 20) { - return undefined; - } - return 2000; - }, }); redisClient.on('connect', () => winstonLogger.info('Redis sentinel client connected!')); From 3e002813da61b15afcea7605e8c9156cb7c2972c Mon Sep 17 00:00:00 2001 From: Macharia Muguku Date: Thu, 2 Jun 2022 18:44:41 +0300 Subject: [PATCH 12/24] add comment --- src/app/index.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/app/index.ts b/src/app/index.ts index e6a3199..c97d397 100644 --- a/src/app/index.ts +++ b/src/app/index.ts @@ -102,7 +102,9 @@ else if (Object.keys(EXPRESS_REDIS_SENTINEL_CONFIG).length > 0) { redisClient.on('end', () => winstonLogger.error('Redis sentinel client error: Redis client disconnected')); sessionStore = new RedisStore({ client: redisClient }); -} else { +} +// else default to file store +else { winstonLogger.error('Redis Connection Error: Redis configs not provided using file session store'); const FileStore = sessionFileStore(session); From 4924f414860fc6cd002543fc8614bcbb7ad2c6a8 Mon Sep 17 00:00:00 2001 From: Macharia Muguku Date: Sun, 5 Jun 2022 01:11:47 +0300 Subject: [PATCH 13/24] add undefined check for sentinel config --- src/app/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/index.ts b/src/app/index.ts index c97d397..051caa7 100644 --- a/src/app/index.ts +++ b/src/app/index.ts @@ -89,7 +89,7 @@ if (EXPRESS_REDIS_URL !== undefined) { sessionStore = new RedisStore({ client: redisClient }); } // check for and use redis sentinel if available -else if (Object.keys(EXPRESS_REDIS_SENTINEL_CONFIG).length > 0) { +else if (EXPRESS_REDIS_SENTINEL_CONFIG !== undefined && Object.keys(EXPRESS_REDIS_SENTINEL_CONFIG).length > 0) { const RedisStore = connectRedis(session); const redisClient = new Redis({ From 7446bdfd68a7afb19fc07ef1da552a61bc6a6564 Mon Sep 17 00:00:00 2001 From: Macharia Muguku Date: Mon, 6 Jun 2022 01:09:02 +0300 Subject: [PATCH 14/24] add ioredis mock --- package.json | 2 ++ yarn.lock | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/package.json b/package.json index 4c3bd40..70bdcd6 100644 --- a/package.json +++ b/package.json @@ -56,6 +56,7 @@ "@types/express": "^4.17.13", "@types/express-session": "^1.17.4", "@types/helmet": "^4.0.0", + "@types/ioredis-mock": "^5.6.0", "@types/jest": "^27.4.1", "@types/morgan": "^1.9.3", "@types/node": "^17.0.21", @@ -79,6 +80,7 @@ "eslint-plugin-prettier": "^4.0.0", "eslint-plugin-sonarjs": "^0.12.0", "husky": "^7.0.4", + "ioredis-mock": "^8.2.2", "jest": "^27.5.1", "lint-staged": "^12.3.4", "mockdate": "^3.0.5", diff --git a/yarn.lock b/yarn.lock index f816f4b..1d0c056 100644 --- a/yarn.lock +++ b/yarn.lock @@ -343,6 +343,11 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== +"@ioredis/as-callback@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@ioredis/as-callback/-/as-callback-3.0.0.tgz#b96c9b05e6701e85ec6a5e62fa254071b0aec97f" + integrity sha512-Kqv1rZ3WbgOrS+hgzJ5xG5WQuhvzzSTRYvNeyPMLOAM78MHSnuKI20JeJGbpuAt//LCuP0vsexZcorqW7kWhJg== + "@ioredis/commands@^1.1.1": version "1.1.1" resolved "https://registry.yarnpkg.com/@ioredis/commands/-/commands-1.1.1.tgz#2ba4299ea624a6bfac15b35f6df90b0015691ec3" @@ -793,6 +798,13 @@ "@types/react" "*" hoist-non-react-statics "^3.3.0" +"@types/ioredis-mock@^5.6.0": + version "5.6.0" + resolved "https://registry.yarnpkg.com/@types/ioredis-mock/-/ioredis-mock-5.6.0.tgz#78078fedf8323c94234abba0a6b2f10ecbdcb0fe" + integrity sha512-2L20NMYTzNlCeLbi7aXQ/VlFTBu7qYoGefwB0NIDYN5TWzOslzvfl7ttoIN9IVO2LEeY+MBpSWO8oJQklL/o4Q== + dependencies: + "@types/ioredis" "*" + "@types/ioredis@*": version "4.28.10" resolved "https://registry.yarnpkg.com/@types/ioredis/-/ioredis-4.28.10.tgz#40ceb157a4141088d1394bb87c98ed09a75a06ff" @@ -2574,6 +2586,20 @@ fecha@^4.2.0: resolved "https://registry.yarnpkg.com/fecha/-/fecha-4.2.1.tgz#0a83ad8f86ef62a091e22bb5a039cd03d23eecce" integrity sha512-MMMQ0ludy/nBs1/o0zVOiKTpG7qMbonKUzjJgQFEuvq6INZ1OraKPRAWkBq5vlKLOUMpmNYG1JoN3oDPUQ9m3Q== +fengari-interop@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/fengari-interop/-/fengari-interop-0.1.3.tgz#3ad37a90e7430b69b365441e9fc0ba168942a146" + integrity sha512-EtZ+oTu3kEwVJnoymFPBVLIbQcCoy9uWCVnMA6h3M/RqHkUBsLYp29+RRHf9rKr6GwjubWREU1O7RretFIXjHw== + +fengari@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/fengari/-/fengari-0.1.4.tgz#72416693cd9e43bd7d809d7829ddc0578b78b0bb" + integrity sha512-6ujqUuiIYmcgkGz8MGAdERU57EIluGGPSUgGPTsco657EHa+srq0S3/YUl/r9kx1+D+d4rGfYObd+m8K22gB1g== + dependencies: + readline-sync "^1.4.9" + sprintf-js "^1.1.1" + tmp "^0.0.33" + file-entry-cache@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" @@ -3106,6 +3132,16 @@ internal-slot@^1.0.3: has "^1.0.3" side-channel "^1.0.4" +ioredis-mock@^8.2.2: + version "8.2.2" + resolved "https://registry.yarnpkg.com/ioredis-mock/-/ioredis-mock-8.2.2.tgz#9bae98378a396d3ba748fab604ede1b90c53eadf" + integrity sha512-XyJfcF6pqcLHwAYtldkzaLtjRxPw7d8U0FUfjgQ5U/d0vVhFxiXbqsILR4FEOp+ygzyZgBA8xye+uPKu74IH1A== + dependencies: + "@ioredis/as-callback" "^3.0.0" + "@ioredis/commands" "^1.1.1" + fengari "^0.1.4" + fengari-interop "^0.1.3" + ioredis@^5.0.4: version "5.0.4" resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-5.0.4.tgz#0d4abfd818adfc5ef5029fddac4b8f503a1433b7" @@ -4495,6 +4531,11 @@ optionator@^0.9.1: type-check "^0.4.0" word-wrap "^1.2.3" +os-tmpdir@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g== + p-cancelable@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" @@ -5029,6 +5070,11 @@ readdirp@~3.6.0: dependencies: picomatch "^2.2.1" +readline-sync@^1.4.9: + version "1.4.10" + resolved "https://registry.yarnpkg.com/readline-sync/-/readline-sync-1.4.10.tgz#41df7fbb4b6312d673011594145705bf56d8873b" + integrity sha512-gNva8/6UAe8QYepIQH/jQ2qn91Qj0B9sYjMBBs3QOB8F2CXcKgLxQaJRP76sWVRQt+QU+8fAkCbCvjjMFu7Ycw== + redis-errors@^1.0.0, redis-errors@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/redis-errors/-/redis-errors-1.2.0.tgz#eb62d2adb15e4eaf4610c04afe1529384250abad" @@ -5461,6 +5507,11 @@ split-on-first@^1.0.0: resolved "https://registry.yarnpkg.com/split-on-first/-/split-on-first-1.1.0.tgz#f610afeee3b12bce1d0c30425e76398b78249a5f" integrity sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw== +sprintf-js@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.2.tgz#da1765262bf8c0f571749f2ad6c26300207ae673" + integrity sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug== + sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" @@ -5731,6 +5782,13 @@ tiny-warning@^1.0.0, tiny-warning@^1.0.3: resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== +tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== + dependencies: + os-tmpdir "~1.0.2" + tmpl@1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" From ea889e0ed634ca09dea935bff23a622029856d83 Mon Sep 17 00:00:00 2001 From: Macharia Muguku Date: Mon, 13 Jun 2022 11:43:12 +0300 Subject: [PATCH 15/24] update tests - mock ioredis client, add tests for different session clients --- src/app/tests/index.test.ts | 65 ++++++++++++++++++++++++++++++++++- src/configs/__mocks__/envs.ts | 4 +++ 2 files changed, 68 insertions(+), 1 deletion(-) diff --git a/src/app/tests/index.test.ts b/src/app/tests/index.test.ts index 9c57afa..6cf910f 100644 --- a/src/app/tests/index.test.ts +++ b/src/app/tests/index.test.ts @@ -4,6 +4,8 @@ import ClientOauth2 from 'client-oauth2'; import nock from 'nock'; import request from 'supertest'; import express from 'express'; +import RedisMock from 'ioredis-mock'; +import Redis from 'ioredis'; import { EXPRESS_FRONTEND_OPENSRP_CALLBACK_URL, EXPRESS_SESSION_LOGIN_URL, @@ -29,6 +31,7 @@ const panic = (err: Error, done: jest.DoneCallback): void => { } }; +jest.mock('ioredis', () => RedisMock); jest.mock('../../configs/envs'); // mock out winston logger and stream methods - reduce log noise in test output jest.mock('../../configs/winston', () => ({ @@ -113,10 +116,14 @@ describe('src/index.ts', () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any let cookie: { [key: string]: any }; - afterEach(() => { + afterEach((done) => { JSON.parse = actualJsonParse; jest.resetAllMocks(); jest.clearAllMocks(); + new Redis() + .flushall() + .then(() => done()) + .catch((err) => panic(err, done)); }); it('serves the build.index.html file', (done) => { @@ -433,4 +440,60 @@ describe('src/index.ts', () => { done(); }); + // it('uses single redis node as session storage', (done) => { + // const logsSpy = jest.spyOn(winstonLogger, 'info'); + + // request(app) + // .get('/test/endpoint') + // .then(() => { + // expect(logsSpy).toHaveBeenCalledWith('Redis single node client connected!'); + // done(); + // }) + // .catch((err: Error) => { + // panic(err, done); + // }); + // }); + // it('uses redis sentinel as session storage', (done) => { + // const logsSpy = jest.spyOn(winstonLogger, 'info'); + + // request(app) + // .get('/test/endpoint') + // .then(() => { + // expect(logsSpy).toHaveBeenCalledWith('Redis sentinel client connected!'); + // done(); + // }) + // .catch((err: Error) => { + // panic(err, done); + // }); + // }); + // it('shows no redis configs', (done) => { + // const logsSpy = jest.spyOn(winstonLogger, 'error'); + + // request(app) + // .get('/test/endpoint') + // .then(() => { + // expect(logsSpy).toHaveBeenCalledWith( + // 'Redis Connection Error: Redis configs not provided using file session store', + // ); + // done(); + // }) + // .catch((err: Error) => { + // panic(err, done); + // }); + // }); + // it('shows errors when single redis node disconnects', (done) => { + // const logsSpy = jest.spyOn(winstonLogger, 'info'); + + // request(app) + // .get('/test/endpoint') + // .then(() => { + // new Redis().quit().catch((err) => panic(err, done)); + + // expect(logsSpy).toHaveBeenCalledWith('Redis single node client error: Redis client disconnected'); + // done(); + // }) + // .catch((err: Error) => { + // panic(err, done); + // }); + // }); }); diff --git a/src/configs/__mocks__/envs.ts b/src/configs/__mocks__/envs.ts index 7e24fc3..ca9be6c 100644 --- a/src/configs/__mocks__/envs.ts +++ b/src/configs/__mocks__/envs.ts @@ -68,3 +68,7 @@ export const EXPRESS_LOGS_FILE_PATH = './logs/default-error.log'; export const EXPRESS_COMBINED_LOGS_FILE_PATH = './logs/default-error-and-info.log'; export const EXPRESS_CONTENT_SECURITY_POLICY_CONFIG = { 'default-src': ["'self'"], reportUri: 'https://example.com' }; + +// export const EXPRESS_REDIS_URL = 'redis://:@127.0.0.1:6379'; +// export const EXPRESS_REDIS_SENTINEL_CONFIG = +// '{"name":"mymaster","sentinels":[{"host":"127.0.0.1","port":26379},{"host":"127.0.0.1","port":6380},{"host":"127.0.0.1","port":6379}]}'; From 874b230dff9d37e72635e6fe48881588572c05ea Mon Sep 17 00:00:00 2001 From: Macharia Muguku Date: Wed, 15 Jun 2022 03:58:21 +0300 Subject: [PATCH 16/24] mock directly --- src/app/tests/index.test.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/app/tests/index.test.ts b/src/app/tests/index.test.ts index 6cf910f..350282a 100644 --- a/src/app/tests/index.test.ts +++ b/src/app/tests/index.test.ts @@ -4,7 +4,6 @@ import ClientOauth2 from 'client-oauth2'; import nock from 'nock'; import request from 'supertest'; import express from 'express'; -import RedisMock from 'ioredis-mock'; import Redis from 'ioredis'; import { EXPRESS_FRONTEND_OPENSRP_CALLBACK_URL, @@ -31,7 +30,7 @@ const panic = (err: Error, done: jest.DoneCallback): void => { } }; -jest.mock('ioredis', () => RedisMock); +jest.mock('ioredis', () => jest.requireActual('ioredis-mock')); jest.mock('../../configs/envs'); // mock out winston logger and stream methods - reduce log noise in test output jest.mock('../../configs/winston', () => ({ From 7915fce57707447658cb145b8fe26de9b8f1798f Mon Sep 17 00:00:00 2001 From: Macharia Muguku Date: Wed, 15 Jun 2022 04:45:43 +0300 Subject: [PATCH 17/24] remove default redis mocks --- src/configs/__mocks__/envs.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/configs/__mocks__/envs.ts b/src/configs/__mocks__/envs.ts index ca9be6c..7e24fc3 100644 --- a/src/configs/__mocks__/envs.ts +++ b/src/configs/__mocks__/envs.ts @@ -68,7 +68,3 @@ export const EXPRESS_LOGS_FILE_PATH = './logs/default-error.log'; export const EXPRESS_COMBINED_LOGS_FILE_PATH = './logs/default-error-and-info.log'; export const EXPRESS_CONTENT_SECURITY_POLICY_CONFIG = { 'default-src': ["'self'"], reportUri: 'https://example.com' }; - -// export const EXPRESS_REDIS_URL = 'redis://:@127.0.0.1:6379'; -// export const EXPRESS_REDIS_SENTINEL_CONFIG = -// '{"name":"mymaster","sentinels":[{"host":"127.0.0.1","port":26379},{"host":"127.0.0.1","port":6380},{"host":"127.0.0.1","port":6379}]}'; From 3ffb8f3a0beac7292c3afc763e2cdf076cc466f5 Mon Sep 17 00:00:00 2001 From: Macharia Muguku Date: Wed, 15 Jun 2022 05:22:56 +0300 Subject: [PATCH 18/24] fix redis tests, disable winston mock - interfers with redis tests --- src/app/tests/index.test.ts | 119 ++++++++++++++++-------------------- 1 file changed, 52 insertions(+), 67 deletions(-) diff --git a/src/app/tests/index.test.ts b/src/app/tests/index.test.ts index 350282a..21a085a 100644 --- a/src/app/tests/index.test.ts +++ b/src/app/tests/index.test.ts @@ -33,17 +33,16 @@ const panic = (err: Error, done: jest.DoneCallback): void => { jest.mock('ioredis', () => jest.requireActual('ioredis-mock')); jest.mock('../../configs/envs'); // mock out winston logger and stream methods - reduce log noise in test output -jest.mock('../../configs/winston', () => ({ - winstonLogger: { - info: jest.fn(), - error: jest.fn(), - }, - winstonStream: { - write: jest.fn(), - }, -})); +// jest.mock('../../configs/winston', () => ({ +// winstonLogger: { +// info: jest.fn(), +// error: jest.fn(), +// }, +// winstonStream: { +// write: jest.fn(), +// }, +// })); jest.mock('node-fetch'); - jest.mock('client-oauth2', () => { class CodeFlow { private client: ClientOauth2; @@ -436,63 +435,49 @@ describe('src/index.ts', () => { ); expect(winston).toHaveBeenCalledTimes(2); - done(); }); - // it('uses single redis node as session storage', (done) => { - // const logsSpy = jest.spyOn(winstonLogger, 'info'); - - // request(app) - // .get('/test/endpoint') - // .then(() => { - // expect(logsSpy).toHaveBeenCalledWith('Redis single node client connected!'); - // done(); - // }) - // .catch((err: Error) => { - // panic(err, done); - // }); - // }); - // it('uses redis sentinel as session storage', (done) => { - // const logsSpy = jest.spyOn(winstonLogger, 'info'); - - // request(app) - // .get('/test/endpoint') - // .then(() => { - // expect(logsSpy).toHaveBeenCalledWith('Redis sentinel client connected!'); - // done(); - // }) - // .catch((err: Error) => { - // panic(err, done); - // }); - // }); - // it('shows no redis configs', (done) => { - // const logsSpy = jest.spyOn(winstonLogger, 'error'); - - // request(app) - // .get('/test/endpoint') - // .then(() => { - // expect(logsSpy).toHaveBeenCalledWith( - // 'Redis Connection Error: Redis configs not provided using file session store', - // ); - // done(); - // }) - // .catch((err: Error) => { - // panic(err, done); - // }); - // }); - // it('shows errors when single redis node disconnects', (done) => { - // const logsSpy = jest.spyOn(winstonLogger, 'info'); - - // request(app) - // .get('/test/endpoint') - // .then(() => { - // new Redis().quit().catch((err) => panic(err, done)); - - // expect(logsSpy).toHaveBeenCalledWith('Redis single node client error: Redis client disconnected'); - // done(); - // }) - // .catch((err: Error) => { - // panic(err, done); - // }); - // }); + + it('uses single redis node as session storage', (done) => { + jest.resetModules(); + jest.mock('../../configs/envs', () => ({ + ...jest.requireActual('../../configs/envs'), + EXPRESS_REDIS_URL: 'redis://:@127.0.0.1:1234', + })); + const { default: app2 } = jest.requireActual('../index'); + const { winstonLogger: winstonLogger2 } = jest.requireActual('../../configs/winston'); + const logsSpy = jest.spyOn(winstonLogger2, 'info'); + + request(app2) + .get('/test/endpoint') + .then(() => { + expect(logsSpy).toHaveBeenCalledWith('Redis single node client connected!'); + done(); + }) + .catch((err) => { + panic(err, done); + }); + }); + + it('uses redis sentinel as session storage', (done) => { + jest.resetModules(); + jest.mock('../../configs/envs', () => ({ + ...jest.requireActual('../../configs/envs'), + EXPRESS_REDIS_SENTINEL_CONFIG: + '{"name":"mymaster","sentinels":[{"host":"127.0.0.1","port":26379},{"host":"127.0.0.1","port":6380},{"host":"127.0.0.1","port":6379}]}', + })); + const { default: app2 } = jest.requireActual('../index'); + const { winstonLogger: winstonLogger2 } = jest.requireActual('../../configs/winston'); + const logsSpy = jest.spyOn(winstonLogger2, 'info'); + + request(app2) + .get('/test/endpoint') + .then(() => { + expect(logsSpy).toHaveBeenCalledWith('Redis sentinel client connected!'); + done(); + }) + .catch((err) => { + panic(err, done); + }); + }); }); From 09661a163cc03fbe91161c7b3c618765230b64d8 Mon Sep 17 00:00:00 2001 From: Macharia Muguku Date: Wed, 15 Jun 2022 05:49:41 +0300 Subject: [PATCH 19/24] mock out console logs - reduce log noise in console --- jest.config.js | 1 + jest.setup.js | 4 ++++ src/app/tests/index.errors.test.ts | 10 ---------- src/app/tests/index.logging.test.ts | 12 +----------- src/app/tests/index.test.ts | 10 ---------- 5 files changed, 6 insertions(+), 31 deletions(-) create mode 100644 jest.setup.js diff --git a/jest.config.js b/jest.config.js index 11d086f..b530cff 100644 --- a/jest.config.js +++ b/jest.config.js @@ -9,4 +9,5 @@ module.exports = { testEnvironment: 'node', collectCoverageFrom: ['src/**/*.{ts,tsx}', '!src/**/tests/', '!src/index.ts'], coverageReporters: ['lcov', 'html'], + setupFilesAfterEnv: ['/jest.setup.js'], }; diff --git a/jest.setup.js b/jest.setup.js new file mode 100644 index 0000000..17aef4e --- /dev/null +++ b/jest.setup.js @@ -0,0 +1,4 @@ +global.console = { + ...console, + log: jest.fn(), +}; diff --git a/src/app/tests/index.errors.test.ts b/src/app/tests/index.errors.test.ts index af3da58..00656b9 100644 --- a/src/app/tests/index.errors.test.ts +++ b/src/app/tests/index.errors.test.ts @@ -13,16 +13,6 @@ const panic = (err: Error, done: jest.DoneCallback): void => { } }; -// mock out winston logger and stream methods - reduce log noise in test output -jest.mock('../../configs/winston', () => ({ - winstonLogger: { - info: jest.fn(), - error: jest.fn(), - }, - winstonStream: { - write: jest.fn(), - }, -})); jest.mock('client-oauth2', () => { class CodeFlow { private client: ClientOauth2; diff --git a/src/app/tests/index.logging.test.ts b/src/app/tests/index.logging.test.ts index d1414e8..903d20c 100644 --- a/src/app/tests/index.logging.test.ts +++ b/src/app/tests/index.logging.test.ts @@ -17,16 +17,6 @@ const panic = (err: Error, done: jest.DoneCallback): void => { }; jest.mock('../../configs/envs'); -// mock out winston logger and stream methods - reduce log noise in test output -jest.mock('../../configs/winston', () => ({ - winstonLogger: { - info: jest.fn(), - error: jest.fn(), - }, - winstonStream: { - write: jest.fn(), - }, -})); const errorText = 'Token not found'; @@ -116,7 +106,7 @@ describe('src/index.ts', () => { .get('/oauth/state') .then((res) => { // one by winston, other by morgan - expect(logsSpy).toHaveBeenCalledTimes(1); + expect(logsSpy).toHaveBeenCalledTimes(2); expect(logsSpy).toHaveBeenCalledWith('Not authorized'); expect(res.status).toBe(200); expect(res.text).toMatch('Not authorized'); diff --git a/src/app/tests/index.test.ts b/src/app/tests/index.test.ts index 21a085a..d1ebd6b 100644 --- a/src/app/tests/index.test.ts +++ b/src/app/tests/index.test.ts @@ -32,16 +32,6 @@ const panic = (err: Error, done: jest.DoneCallback): void => { jest.mock('ioredis', () => jest.requireActual('ioredis-mock')); jest.mock('../../configs/envs'); -// mock out winston logger and stream methods - reduce log noise in test output -// jest.mock('../../configs/winston', () => ({ -// winstonLogger: { -// info: jest.fn(), -// error: jest.fn(), -// }, -// winstonStream: { -// write: jest.fn(), -// }, -// })); jest.mock('node-fetch'); jest.mock('client-oauth2', () => { class CodeFlow { From e734245401b2758105d5ea14b7f8d960f7e9b043 Mon Sep 17 00:00:00 2001 From: Macharia Muguku Date: Wed, 15 Jun 2022 13:17:15 +0300 Subject: [PATCH 20/24] update ioredis --- package.json | 2 +- yarn.lock | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index 70bdcd6..2e09968 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "express": "^4.17.3", "express-session": "^1.17.2", "helmet": "^5.0.2", - "ioredis": "^5.0.4", + "ioredis": "^5.0.6", "morgan": "^1.10.0", "node-fetch": "2.6.7", "react": "^17.0.2", diff --git a/yarn.lock b/yarn.lock index 1d0c056..db83cae 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3142,10 +3142,10 @@ ioredis-mock@^8.2.2: fengari "^0.1.4" fengari-interop "^0.1.3" -ioredis@^5.0.4: - version "5.0.4" - resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-5.0.4.tgz#0d4abfd818adfc5ef5029fddac4b8f503a1433b7" - integrity sha512-qFJw3MnPNsJF1lcIOP3vztbsasOXK3nDdNAgjQj7t7/Bn/w10PGchTOpqylQNxjzPbLoYDu34LjeJtSWiKBntQ== +ioredis@^5.0.6: + version "5.0.6" + resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-5.0.6.tgz#e50b8cc945f1f3ac932b0b8aab4bd8073d1402a9" + integrity sha512-KUm7wPzIet9QrFMoMm09/4bkfVKBUD9KXwBitP3hrNkZ+A6NBndweXGwYIB/7szHcTZgfo7Kvx88SxljJV4D9A== dependencies: "@ioredis/commands" "^1.1.1" cluster-key-slot "^1.1.0" @@ -4065,12 +4065,12 @@ locate-path@^5.0.0: lodash.defaults@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" - integrity sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw= + integrity sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ== lodash.isarguments@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" - integrity sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo= + integrity sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg== lodash.isfunction@^3.0.9: version "3.0.9" From 0dc8325585630585ede2916547890e6c9a05c5a1 Mon Sep 17 00:00:00 2001 From: Macharia Muguku Date: Wed, 15 Jun 2022 13:17:37 +0300 Subject: [PATCH 21/24] skip lib check --- tsconfig.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tsconfig.json b/tsconfig.json index 0972767..f08cbf5 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,7 +11,8 @@ "paths": { "*": ["node_modules/*"] }, - "strictNullChecks": true + "strictNullChecks": true, + "skipLibCheck": true }, "include": ["src/**/*"], "typeRoots": [ From 6c4254290af0e115c404ba5a8cf0090c2ed83c8d Mon Sep 17 00:00:00 2001 From: Macharia Muguku Date: Wed, 15 Jun 2022 13:24:19 +0300 Subject: [PATCH 22/24] add jest setup file to eslint ignore list --- .eslintignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.eslintignore b/.eslintignore index 21c4329..87cd9d0 100644 --- a/.eslintignore +++ b/.eslintignore @@ -3,3 +3,4 @@ dist coverage .eslintrc.js jest.config.js +jest.setup.js From 3921bcfe952719bf2b720a1b1f3159a142e11ebe Mon Sep 17 00:00:00 2001 From: Macharia Muguku Date: Wed, 15 Jun 2022 13:44:44 +0300 Subject: [PATCH 23/24] update redis --- package.json | 2 +- yarn.lock | 93 ++++++++++++++++++++++++++-------------------------- 2 files changed, 47 insertions(+), 48 deletions(-) diff --git a/package.json b/package.json index 2e09968..74a7fbb 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "react-redux": "^7.2.6", "react-router": "^5.2.1", "react-router-dom": "^5.2.1", - "redis": "^4.0.6", + "redis": "^4.1.0", "redux": "^4.1.2", "request": "^2.88.0", "seamless-immutable": "^7.1.4", diff --git a/yarn.lock b/yarn.lock index db83cae..729bc0c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -556,41 +556,6 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" -"@node-redis/bloom@1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@node-redis/bloom/-/bloom-1.0.1.tgz#144474a0b7dc4a4b91badea2cfa9538ce0a1854e" - integrity sha512-mXEBvEIgF4tUzdIN89LiYsbi6//EdpFA7L8M+DHCvePXg+bfHWi+ct5VI6nHUFQE5+ohm/9wmgihCH3HSkeKsw== - -"@node-redis/client@1.0.5": - version "1.0.5" - resolved "https://registry.yarnpkg.com/@node-redis/client/-/client-1.0.5.tgz#ebac5e2bbf12214042a37621604973a954ede755" - integrity sha512-ESZ3bd1f+od62h4MaBLKum+klVJfA4wAeLHcVQBkoXa1l0viFesOWnakLQqKg+UyrlJhZmXJWtu0Y9v7iTMrig== - dependencies: - cluster-key-slot "1.1.0" - generic-pool "3.8.2" - redis-parser "3.0.0" - yallist "4.0.0" - -"@node-redis/graph@1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@node-redis/graph/-/graph-1.0.0.tgz#baf8eaac4a400f86ea04d65ec3d65715fd7951ab" - integrity sha512-mRSo8jEGC0cf+Rm7q8mWMKKKqkn6EAnA9IA2S3JvUv/gaWW/73vil7GLNwion2ihTptAm05I9LkepzfIXUKX5g== - -"@node-redis/json@1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@node-redis/json/-/json-1.0.2.tgz#8ad2d0f026698dc1a4238cc3d1eb099a3bee5ab8" - integrity sha512-qVRgn8WfG46QQ08CghSbY4VhHFgaTY71WjpwRBGEuqGPfWwfRcIf3OqSpR7Q/45X+v3xd8mvYjywqh0wqJ8T+g== - -"@node-redis/search@1.0.5": - version "1.0.5" - resolved "https://registry.yarnpkg.com/@node-redis/search/-/search-1.0.5.tgz#96050007eb7c50a7e47080320b4f12aca8cf94c4" - integrity sha512-MCOL8iCKq4v+3HgEQv8zGlSkZyXSXtERgrAJ4TSryIG/eLFy84b57KmNNa/V7M1Q2Wd2hgn2nPCGNcQtk1R1OQ== - -"@node-redis/time-series@1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@node-redis/time-series/-/time-series-1.0.2.tgz#5dd3638374edd85ebe0aa6b0e87addc88fb9df69" - integrity sha512-HGQ8YooJ8Mx7l28tD7XjtB3ImLEjlUxG1wC1PAjxu6hPJqjPshUZxAICzDqDjtIbhDTf48WXXUcx8TQJB1XTKA== - "@nodelib/fs.scandir@2.1.5": version "2.1.5" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" @@ -627,6 +592,40 @@ resolved "https://registry.yarnpkg.com/@onaio/session-reducer/-/session-reducer-0.0.13.tgz#96c5749b4c84b47a662ce753a5bec414b565f0df" integrity sha512-A5FdwFyV1Y4NQiyo/aA3g1nlNFsu7rXzR7jGT6J0Nj6ag9xuh6XOG3fyLgBLRbNTB1+Y1g3iFYX8MN89sJrAeQ== +"@redis/bloom@1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@redis/bloom/-/bloom-1.0.2.tgz#42b82ec399a92db05e29fffcdfd9235a5fc15cdf" + integrity sha512-EBw7Ag1hPgFzdznK2PBblc1kdlj5B5Cw3XwI9/oG7tSn85/HKy3X9xHy/8tm/eNXJYHLXHJL/pkwBpFMVVefkw== + +"@redis/client@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@redis/client/-/client-1.1.0.tgz#e52a85aee802796ceb14bf27daf9550f51f238b8" + integrity sha512-xO9JDIgzsZYDl3EvFhl6LC52DP3q3GCMUer8zHgKV6qSYsq1zB+pZs9+T80VgcRogrlRYhi4ZlfX6A+bHiBAgA== + dependencies: + cluster-key-slot "1.1.0" + generic-pool "3.8.2" + yallist "4.0.0" + +"@redis/graph@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@redis/graph/-/graph-1.0.1.tgz#eabc58ba99cd70d0c907169c02b55497e4ec8a99" + integrity sha512-oDE4myMCJOCVKYMygEMWuriBgqlS5FqdWerikMoJxzmmTUErnTRRgmIDa2VcgytACZMFqpAOWDzops4DOlnkfQ== + +"@redis/json@1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@redis/json/-/json-1.0.3.tgz#a13fde1d22ebff0ae2805cd8e1e70522b08ea866" + integrity sha512-4X0Qv0BzD9Zlb0edkUoau5c1bInWSICqXAGrpwEltkncUwcxJIGEcVryZhLgb0p/3PkKaLIWkjhHRtLe9yiA7Q== + +"@redis/search@1.0.6": + version "1.0.6" + resolved "https://registry.yarnpkg.com/@redis/search/-/search-1.0.6.tgz#53d7451c2783f011ebc48ec4c2891264e0b22f10" + integrity sha512-pP+ZQRis5P21SD6fjyCeLcQdps+LuTzp2wdUbzxEmNhleighDDTD5ck8+cYof+WLec4csZX7ks+BuoMw0RaZrA== + +"@redis/time-series@1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@redis/time-series/-/time-series-1.0.3.tgz#4cfca8e564228c0bddcdf4418cba60c20b224ac4" + integrity sha512-OFp0q4SGrTH0Mruf6oFsHGea58u8vS/iI5+NpYdicaM+7BgqBZH8FFvNZ8rYYLrUO/QRqMq72NpXmxLVNcdmjA== + "@servie/events@^1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@servie/events/-/events-1.0.0.tgz#8258684b52d418ab7b86533e861186638ecc5dc1" @@ -5080,24 +5079,24 @@ redis-errors@^1.0.0, redis-errors@^1.2.0: resolved "https://registry.yarnpkg.com/redis-errors/-/redis-errors-1.2.0.tgz#eb62d2adb15e4eaf4610c04afe1529384250abad" integrity sha1-62LSrbFeTq9GEMBK/hUpOEJQq60= -redis-parser@3.0.0, redis-parser@^3.0.0: +redis-parser@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-3.0.0.tgz#b66d828cdcafe6b4b8a428a7def4c6bcac31c8b4" integrity sha1-tm2CjNyv5rS4pCin3vTGvKwxyLQ= dependencies: redis-errors "^1.0.0" -redis@^4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/redis/-/redis-4.0.6.tgz#a2ded4d9f4f4bad148e54781051618fc684cd858" - integrity sha512-IaPAxgF5dV0jx+A9l6yd6R9/PAChZIoAskDVRzUODeLDNhsMlq7OLLTmu0AwAr0xjrJ1bibW5xdpRwqIQ8Q0Xg== - dependencies: - "@node-redis/bloom" "1.0.1" - "@node-redis/client" "1.0.5" - "@node-redis/graph" "1.0.0" - "@node-redis/json" "1.0.2" - "@node-redis/search" "1.0.5" - "@node-redis/time-series" "1.0.2" +redis@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/redis/-/redis-4.1.0.tgz#6e400e8edf219e39281afe95e66a3d5f7dcf7289" + integrity sha512-5hvJ8wbzpCCiuN1ges6tx2SAh2XXCY0ayresBmu40/SGusWHFW86TAlIPpbimMX2DFHOX7RN34G2XlPA1Z43zg== + dependencies: + "@redis/bloom" "1.0.2" + "@redis/client" "1.1.0" + "@redis/graph" "1.0.1" + "@redis/json" "1.0.3" + "@redis/search" "1.0.6" + "@redis/time-series" "1.0.3" redux@^4.0.0, redux@^4.1.2: version "4.1.2" From fd9ca535ae5daa71e9b7b4537b34786f180ecaea Mon Sep 17 00:00:00 2001 From: Macharia Muguku Date: Thu, 23 Jun 2022 03:28:38 +0300 Subject: [PATCH 24/24] rename redis standalone url for clarity --- .env.sample | 2 +- src/app/index.ts | 6 +++--- src/app/tests/index.test.ts | 2 +- src/configs/envs.ts | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.env.sample b/.env.sample index 62aeda4..7d0590a 100644 --- a/.env.sample +++ b/.env.sample @@ -35,6 +35,6 @@ EXPRESS_LOGS_FILE_PATH='/home/.express/reveal-express-server.log # https://github.com/helmetjs/helmet#reference EXPRESS_CONTENT_SECURITY_POLICY_CONFIG=`{"default-src":["'self'"]}` -EXPRESS_REDIS_URL=redis://username:authpassword@127.0.0.1:6379/4 +EXPRESS_REDIS_STAND_ALONE_URL=redis://username:authpassword@127.0.0.1:6379/4 EXPRESS_REDIS_SENTINEL_CONFIG='{"name":"master","sentinelUsername":"u_name","sentinelPassword":"pass","db":4,"sentinels":[{"host":"127.0.0.1","port":6379},{"host":"127.0.0.1","port":6379}]}' diff --git a/src/app/index.ts b/src/app/index.ts index 051caa7..9593120 100644 --- a/src/app/index.ts +++ b/src/app/index.ts @@ -36,7 +36,7 @@ import { EXPRESS_SESSION_NAME, EXPRESS_SESSION_PATH, EXPRESS_SESSION_SECRET, - EXPRESS_REDIS_URL, + EXPRESS_REDIS_STAND_ALONE_URL, EXPRESS_REDIS_SENTINEL_CONFIG, EXPRESS_CONTENT_SECURITY_POLICY_CONFIG, } from '../configs/envs'; @@ -77,9 +77,9 @@ let sessionStore: session.Store; // use redis session store if redis is available else default to file store // check for and use a single redis node -if (EXPRESS_REDIS_URL !== undefined) { +if (EXPRESS_REDIS_STAND_ALONE_URL !== undefined) { const RedisStore = connectRedis(session); - const redisClient = new Redis(EXPRESS_REDIS_URL); + const redisClient = new Redis(EXPRESS_REDIS_STAND_ALONE_URL); redisClient.on('connect', () => winstonLogger.info('Redis single node client connected!')); redisClient.on('reconnecting', () => winstonLogger.info('Redis single node client trying to reconnect')); diff --git a/src/app/tests/index.test.ts b/src/app/tests/index.test.ts index d1ebd6b..240ca59 100644 --- a/src/app/tests/index.test.ts +++ b/src/app/tests/index.test.ts @@ -432,7 +432,7 @@ describe('src/index.ts', () => { jest.resetModules(); jest.mock('../../configs/envs', () => ({ ...jest.requireActual('../../configs/envs'), - EXPRESS_REDIS_URL: 'redis://:@127.0.0.1:1234', + EXPRESS_REDIS_STAND_ALONE_URL: 'redis://:@127.0.0.1:1234', })); const { default: app2 } = jest.requireActual('../index'); const { winstonLogger: winstonLogger2 } = jest.requireActual('../../configs/winston'); diff --git a/src/configs/envs.ts b/src/configs/envs.ts index 486e62c..b38b37d 100644 --- a/src/configs/envs.ts +++ b/src/configs/envs.ts @@ -108,7 +108,7 @@ export const EXPRESS_CONTENT_SECURITY_POLICY_CONFIG = JSON.parse( export type EXPRESS_CONTENT_SECURITY_POLICY_CONFIG = typeof EXPRESS_CONTENT_SECURITY_POLICY_CONFIG; // see https://github.com/luin/ioredis#connect-to-redis -export const { EXPRESS_REDIS_URL } = process.env; +export const { EXPRESS_REDIS_STAND_ALONE_URL } = process.env; // see https://github.com/luin/ioredis#sentinel export const EXPRESS_REDIS_SENTINEL_CONFIG = JSON.parse(process.env.EXPRESS_REDIS_SENTINEL_CONFIG || '{}');