diff --git a/package.json b/package.json index a490e05..697ddd1 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,6 @@ "@types/compression": "^1.7.0", "@types/config": "^0.0.38", "@types/connect-flash": "^0.0.36", - "@types/connect-redis": "^0.0.16", "@types/cookie": "^0.4.0", "@types/cookie-parser": "^1.4.2", "@types/express": "^4.17.6", @@ -61,7 +60,6 @@ "compression": "^1.7.4", "config": "^3.3.1", "connect-flash": "^0.1.1", - "connect-redis": "^5.0.0", "cookie": "^0.4.1", "cookie-parser": "^1.4.5", "express": "^4.17.1", diff --git a/src/components/RedisComponent.ts b/src/components/RedisComponent.ts index be78dfd..a5a986b 100644 --- a/src/components/RedisComponent.ts +++ b/src/components/RedisComponent.ts @@ -4,11 +4,8 @@ import redis, {RedisClient} from "redis"; import config from "config"; import {logger} from "../Logger"; import session, {Store} from "express-session"; -import connect_redis from "connect-redis"; import CacheProvider from "../CacheProvider"; -const RedisStore = connect_redis(session); - export default class RedisComponent extends ApplicationComponent implements CacheProvider { private redisClient?: RedisClient; private store?: Store; @@ -20,10 +17,8 @@ export default class RedisComponent extends ApplicationComponent implements Cach this.redisClient.on('error', (err: Error) => { logger.error(err, 'An error occurred with redis.'); }); - this.store = new RedisStore({ - client: this.redisClient, - prefix: config.get('redis.prefix') + '-session:', - }); + + this.store = new RedisStore(this); } public async stop(): Promise { @@ -45,7 +40,7 @@ export default class RedisComponent extends ApplicationComponent implements Cach public async get(key: string, defaultValue?: T): Promise { return await new Promise((resolve, reject) => { if (!this.redisClient) { - reject(`Redis store was not initialized.`); + reject(`Redis client was not initialized.`); return; } @@ -66,7 +61,7 @@ export default class RedisComponent extends ApplicationComponent implements Cach public async forget(key: string): Promise { return await new Promise((resolve, reject) => { if (!this.redisClient) { - reject(`Redis store was not initialized.`); + reject(`Redis client was not initialized.`); return; } @@ -84,17 +79,69 @@ export default class RedisComponent extends ApplicationComponent implements Cach public async remember(key: string, value: string, ttl: number): Promise { return await new Promise((resolve, reject) => { if (!this.redisClient) { - reject(`Redis store was not initialized.`); + reject(`Redis client was not initialized.`); return; } this.redisClient.psetex(key, ttl, value, (err) => { - if (err) { - reject(err); - return; - } + if (err) return reject(err); + resolve(); + }); + }); + } + + public async persist(key: string, ttl: number): Promise { + return await new Promise((resolve, reject) => { + if (!this.redisClient) { + reject(`Redis client was not initialized.`); + return; + } + + this.redisClient.pexpire(key, ttl, (err) => { + if (err) return reject(err); resolve(); }); }); } } + +class RedisStore extends Store { + private readonly redisComponent: RedisComponent; + + public constructor(redisComponent: RedisComponent) { + super(); + this.redisComponent = redisComponent; + } + + public get(sid: string, callback: (err?: Error, session?: (session.SessionData | null)) => void): void { + this.redisComponent.get('-session:' + sid) + .then(value => { + if (value) { + this.redisComponent.persist('-session:' + sid, 2592000000) // 30 days + .then(() => { + callback(undefined, JSON.parse(value)); + }) + .catch(callback); + } else { + callback(undefined, null); + } + }) + .catch(callback); + } + + public set(sid: string, session: session.SessionData, callback?: (err?: Error) => void): void { + this.redisComponent.remember('-session:' + sid, JSON.stringify(session), 2592000000) // 30 days + .then(() => { + if (callback) callback(); + }) + .catch(callback); + } + + public destroy(sid: string, callback?: (err?: Error) => void): void { + this.redisComponent.forget('-session:' + sid) + .then(() => { + if (callback) callback(); + }) + .catch(callback); + } +} diff --git a/src/components/SessionComponent.ts b/src/components/SessionComponent.ts index f3050fc..e915397 100644 --- a/src/components/SessionComponent.ts +++ b/src/components/SessionComponent.ts @@ -26,7 +26,7 @@ export default class SessionComponent extends ApplicationComponent { saveUninitialized: true, secret: config.get('session.secret'), store: this.storeComponent.getStore(), - resave: true, + resave: false, cookie: { httpOnly: true, secure: config.get('session.cookie.secure'), diff --git a/yarn.lock b/yarn.lock index 1857064..a0c7731 100644 --- a/yarn.lock +++ b/yarn.lock @@ -600,16 +600,6 @@ dependencies: "@types/express" "*" -"@types/connect-redis@^0.0.16": - version "0.0.16" - resolved "https://registry.yarnpkg.com/@types/connect-redis/-/connect-redis-0.0.16.tgz#fd98a26ffbe6ac3037baa4aecc940951b9f78cdc" - integrity sha512-ToZRmwoeqRhzGIqMO9k8Hs1B9pFSGYCjHvMpPlgo+kQ4M7xaPwi2/5HjikJ0MOfPDFcAe9Qwl1SaULYCNE6jYg== - dependencies: - "@types/express" "*" - "@types/express-session" "*" - "@types/ioredis" "*" - "@types/redis" "*" - "@types/connect@*": version "3.4.34" resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.34.tgz#170a40223a6d666006d93ca128af2beb1d9b1901" @@ -643,7 +633,7 @@ "@types/qs" "*" "@types/range-parser" "*" -"@types/express-session@*", "@types/express-session@^1.17.0": +"@types/express-session@^1.17.0": version "1.17.3" resolved "https://registry.yarnpkg.com/@types/express-session/-/express-session-1.17.3.tgz#4a37c5c4428b8f922ac8ac1cb4bd9190a4d2b097" integrity sha512-57DnyxiqClXOIjoCgeKCUYfKxBPOlOY/k+l1TPK+7bSwyiPTrS5FIk1Ycql7twk4wO7P5lfOVy6akDGiaMSLfw== @@ -679,13 +669,6 @@ dependencies: "@types/node" "*" -"@types/ioredis@*": - version "4.19.2" - resolved "https://registry.yarnpkg.com/@types/ioredis/-/ioredis-4.19.2.tgz#68215d2fab93dd4f5d1d1225938389c32e7b98a2" - integrity sha512-fejSsJ4pYvA8zVLvAgQFI9T2uvxhUW7Ph95KodnNxMZvnUhQrn4ohxjH7fuU+jUw7Q4JCDcaba7JxDmszFmrCA== - dependencies: - "@types/node" "*" - "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": version "2.0.3" resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz#4ba8ddb720221f432e443bd5f9117fd22cfd4762" @@ -801,7 +784,7 @@ resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.3.tgz#7ee330ba7caafb98090bece86a5ee44115904c2c" integrity sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA== -"@types/redis@*", "@types/redis@^2.8.18": +"@types/redis@^2.8.18": version "2.8.28" resolved "https://registry.yarnpkg.com/@types/redis/-/redis-2.8.28.tgz#5862b2b64aa7f7cbc76dafd7e6f06992b52c55e3" integrity sha512-8l2gr2OQ969ypa7hFOeKqtFoY70XkHxISV0pAwmQ2nm6CSPb1brmTmqJCGGrekCo+pAZyWlNXr+Kvo6L/1wijA== @@ -1824,11 +1807,6 @@ connect-flash@^0.1.1: resolved "https://registry.yarnpkg.com/connect-flash/-/connect-flash-0.1.1.tgz#d8630f26d95a7f851f9956b1e8cc6732f3b6aa30" integrity sha1-2GMPJtlaf4UfmVax6MxnMvO2qjA= -connect-redis@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/connect-redis/-/connect-redis-5.0.0.tgz#68fe890117e761ee98e13a14b835338bd6bf044c" - integrity sha512-R4nTW5uXeG5s6zr/q4abmtcdloglZrL/A3cpa0JU0RLFJU4mTR553HUY8OZ0ngeySkGDclwQ5xmCcjjKkxdOSg== - console-control-strings@^1.0.0, console-control-strings@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"