Skip to content

Commit 8fbeb3d

Browse files
author
Peter Marton
committed
feat(expire): expire in redis instead of token
1 parent 099a682 commit 8fbeb3d

File tree

4 files changed

+55
-40
lines changed

4 files changed

+55
-40
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ var session = new TokenSession({
2222

2323
```
2424
session.create({
25-
userId: '1',
25+
uid: '1',
2626
[ttl]: 7200,
2727
[ip]: '127.0.0.1'
2828
})

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
},
2626
"devDependencies": {
2727
"chai": "^3.3.0",
28-
"co-mocha": "^1.1.2",
28+
"co-mocha": "^1.1.2",
2929
"eslint-plugin-standard": "^1.3.1",
3030
"mocha": "^2.3.3",
3131
"sinon": "^1.17.0",

src/e2e.spec.js

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,30 @@ describe('e2e', () => {
2121

2222
describe('#create', () => {
2323
it('should create a session', function *() {
24+
var expireAt = Date.now() + 7200000
2425
var token = yield session.create({
25-
userId: '1'
26+
uid: '1'
2627
})
2728

28-
var userId = yield jwt.verify(token, 'secret')
29+
var tokenPayload = yield jwt.verify(token, 'secret')
2930
var props = yield redis.hgetall(session.namespaceKey + 't:' + token)
3031

31-
expect(userId).to.have.property('userId', '1')
32+
expect(tokenPayload).to.have.property('uid', '1')
33+
34+
expect(props).to.have.property('uid', '1')
35+
expect(props).to.have.property('exp')
36+
expect(Number(props.exp)).to.be.at.least(expireAt)
37+
})
3238

33-
expect(props).to.be.eql({
34-
ttl: '7200',
39+
it('should create a session which expires', function *() {
40+
var token = yield session.create({
3541
uid: '1'
3642
})
43+
44+
var ttl = yield redis.pttl(session.namespaceKey + 't:' + token)
45+
46+
expect(ttl).to.be.above(7198000)
47+
expect(ttl).to.be.below(7200000)
3748
})
3849

3950
afterEach(function *() {
@@ -42,12 +53,10 @@ describe('e2e', () => {
4253
})
4354

4455
describe('#cleanup', () => {
45-
var token1
46-
4756
beforeEach(function *() {
48-
token1 = yield session.create({
49-
userId: '1',
50-
ttl: -1
57+
yield session.create({
58+
uid: '1',
59+
ttl: 0
5160
})
5261
})
5362

@@ -69,20 +78,16 @@ describe('e2e', () => {
6978

7079
it('should remove only expired sessions', function *() {
7180
var token2 = yield session.create({
72-
userId: '2'
81+
uid: '1'
7382
})
7483

7584
yield session.cleanup()
7685

77-
var props1 = yield redis.hgetall(session.namespaceKey + 't:' + token1)
78-
var props2 = yield redis.hgetall(session.namespaceKey + 't:' + token2)
86+
var tokens = yield redis.smembers(session.namespaceKey + 'u:1')
7987

80-
expect(props1).to.be.eql({})
81-
82-
expect(props2).to.be.eql({
83-
ttl: '7200',
84-
uid: '2'
85-
})
88+
expect(tokens).to.be.eql([
89+
token2
90+
])
8691
})
8792
})
8893
})

src/tokenSession.js

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -53,51 +53,51 @@ function TokenSession (opts) {
5353
/**
5454
* @method create
5555
* @param {Object} opts {
56-
* userId: String
56+
* uid: String
5757
* [ttl]: Number in second
5858
* [ip]: String
5959
* }
6060
* @return {String} token, jwt
6161
*/
6262
TokenSession.prototype.create = function (opts) {
63+
var _this = this
64+
6365
opts = opts || {}
6466
opts = _.defaults(opts, {
6567
ttl: DEFAULT.TTL
6668
})
6769

68-
if (!opts.userId) {
69-
return Promise.reject(new Error('userId is required'))
70+
if (!opts.uid) {
71+
return Promise.reject(new Error('uid is required'))
7072
}
7173

7274
if (!_.isNumber(opts.ttl)) {
7375
return Promise.reject(new Error('ttl is required and should be a Number'))
7476
}
7577

76-
opts.userId = String(opts.userId)
78+
opts.uid = String(opts.uid)
7779

7880
// create JWT token
7981
var token = jwt.sign({
80-
userId: opts.userId
81-
}, this.jwtSecret, {
82-
expiresInSeconds: opts.ttl
83-
})
82+
uid: opts.uid
83+
}, _this.jwtSecret)
8484

85-
var userKey = this.namespaceKey + PREFIX.USER + opts.userId
86-
var tokenListKey = this.namespaceKey + PREFIX.TOKEN + 'list'
87-
var tokenListValue = opts.userId + ':' + token
88-
var tokenKey = this.namespaceKey + PREFIX.TOKEN + token
85+
var userKey = _this.namespaceKey + PREFIX.USER + opts.uid
86+
var tokenListKey = _this.namespaceKey + PREFIX.TOKEN + 'list'
87+
var tokenListValue = opts.uid + ':' + token
88+
var tokenKey = _this.namespaceKey + PREFIX.TOKEN + token
8989

9090
var expiresAt = Date.now() + (opts.ttl * 1000)
9191
var tokenPayload = {
92-
uid: opts.userId,
93-
ttl: opts.ttl
92+
uid: opts.uid,
93+
exp: expiresAt
9494
}
9595

9696
if (opts.ip) {
9797
tokenPayload.ip = opts.ip
9898
}
9999

100-
return this.redis
100+
return _this.redis
101101
.multi()
102102

103103
// add token to the list by score
@@ -111,7 +111,14 @@ TokenSession.prototype.create = function (opts) {
111111
.hmset(tokenKey, tokenPayload)
112112
.exec()
113113
.then(function () {
114-
return token
114+
return _this.redis.pexpireat(tokenKey, expiresAt)
115+
.then(function (result) {
116+
if (result !== 1) {
117+
throw new Error('cannot set expiration on token')
118+
}
119+
120+
return token
121+
})
115122
})
116123
}
117124

@@ -144,15 +151,18 @@ TokenSession.prototype.cleanup = function (cleanupAll) {
144151

145152
// remove from token list and token properties
146153
var multi = _this.redis.multi()
147-
.del(tokenKeys)
148154
.zremrangebyscore(tokenListKey, 0, to)
149155

156+
if (cleanupAll) {
157+
multi = multi.del(tokenKeys)
158+
}
159+
150160
// remove tokens from users
151161
expiredItems.forEach(function (item) {
152162
var tmp = item.split(':')
153-
var userId = tmp[0]
163+
var uid = tmp[0]
154164
var token = tmp[1]
155-
var userKey = _this.namespaceKey + PREFIX.USER + userId
165+
var userKey = _this.namespaceKey + PREFIX.USER + uid
156166

157167
multi = multi.srem(userKey, token)
158168
})

0 commit comments

Comments
 (0)