-
-
Notifications
You must be signed in to change notification settings - Fork 767
/
redis_rejson.js
111 lines (88 loc) · 2.57 KB
/
redis_rejson.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
/*
* requires Redis ReJSON plugin (https://oss.redislabs.com/rejson/)
*/
// npm i ioredis@^4.0.0
import Redis from 'ioredis'; // eslint-disable-line import/no-unresolved
const client = new Redis(process.env.REDIS_URL);
const grantable = new Set([
'AccessToken',
'AuthorizationCode',
'RefreshToken',
'DeviceCode',
'BackchannelAuthenticationRequest',
]);
function grantKeyFor(id) {
return `oidc:grant:${id}`;
}
function userCodeKeyFor(userCode) {
return `oidc:userCode:${userCode}`;
}
function uidKeyFor(uid) {
return `oidc:uid:${uid}`;
}
class RedisAdapter {
constructor(name) {
this.name = name;
}
async upsert(id, payload, expiresIn) {
const key = this.key(id);
const multi = client.multi();
multi.call('JSON.SET', key, '.', JSON.stringify(payload));
if (expiresIn) {
multi.expire(key, expiresIn);
}
if (grantable.has(this.name) && payload.grantId) {
const grantKey = grantKeyFor(payload.grantId);
multi.rpush(grantKey, key);
// if you're seeing grant key lists growing out of acceptable proportions consider using LTRIM
// here to trim the list to an appropriate length
const ttl = await client.ttl(grantKey);
if (expiresIn > ttl) {
multi.expire(grantKey, expiresIn);
}
}
if (payload.userCode) {
const userCodeKey = userCodeKeyFor(payload.userCode);
multi.set(userCodeKey, id);
multi.expire(userCodeKey, expiresIn);
}
if (payload.uid) {
const uidKey = uidKeyFor(payload.uid);
multi.set(uidKey, id);
multi.expire(uidKey, expiresIn);
}
await multi.exec();
}
async find(id) {
const key = this.key(id);
const data = await client.call('JSON.GET', key);
if (!data) return undefined;
return JSON.parse(data);
}
async findByUid(uid) {
const id = await client.get(uidKeyFor(uid));
return this.find(id);
}
async findByUserCode(userCode) {
const id = await client.get(userCodeKeyFor(userCode));
return this.find(id);
}
async destroy(id) {
const key = this.key(id);
await client.del(key);
}
async revokeByGrantId(grantId) { // eslint-disable-line class-methods-use-this
const multi = client.multi();
const tokens = await client.lrange(grantKeyFor(grantId), 0, -1);
tokens.forEach((token) => multi.del(token));
multi.del(grantKeyFor(grantId));
await multi.exec();
}
async consume(id) {
await client.call('JSON.SET', this.key(id), 'consumed', Math.floor(Date.now() / 1000));
}
key(id) {
return `oidc:${this.name}:${id}`;
}
}
export default RedisAdapter;