|
| 1 | +/* |
| 2 | + * Tests, pakcage.json and usage examples can be found here : |
| 3 | + * https://github.com/ydarma/oidc-provider-knex-adapter |
| 4 | + * This code is provided under "The Unlicense" |
| 5 | + */ |
| 6 | + |
| 7 | +const knex = require("knex"); |
| 8 | +const oidc_payloads = "oidc_payloads"; |
| 9 | + |
| 10 | +const types = [ |
| 11 | + "Session", |
| 12 | + "AccessToken", |
| 13 | + "AuthorizationCode", |
| 14 | + "RefreshToken", |
| 15 | + "DeviceCode", |
| 16 | + "ClientCredentials", |
| 17 | + "Client", |
| 18 | + "InitialAccessToken", |
| 19 | + "RegistrationAccessToken", |
| 20 | + "Interaction", |
| 21 | + "ReplayDetection", |
| 22 | + "PushedAuthorizationRequest", |
| 23 | + "Grant", |
| 24 | +].reduce((map, name, i) => ({ ...map, [name]: i + 1 }), {}); |
| 25 | + |
| 26 | +function knexAdapter(client, cleanInterval = 3600000) { |
| 27 | + |
| 28 | + let _client = undefined; |
| 29 | + let _lastCleaned = Date.now(); |
| 30 | + |
| 31 | + function getClient() { |
| 32 | + if (typeof _client == "undefined") |
| 33 | + _client = typeof client == "function" ? client : knex(client); |
| 34 | + return _client; |
| 35 | + } |
| 36 | + |
| 37 | + function shouldClean() { |
| 38 | + return Date.now() > _lastCleaned + cleanInterval; |
| 39 | + } |
| 40 | + |
| 41 | + function clean() { |
| 42 | + return getClient() |
| 43 | + .table(oidc_payloads) |
| 44 | + .where("expiresAt", "<", new Date()) |
| 45 | + .delete().then(() => { |
| 46 | + _cleaned = Date.now(); |
| 47 | + }); |
| 48 | + } |
| 49 | + |
| 50 | + function getExpireAt(expiresIn) { |
| 51 | + return expiresIn |
| 52 | + ? new Date(Date.now() + expiresIn * 1000) |
| 53 | + : undefined; |
| 54 | + } |
| 55 | + |
| 56 | + return class DbAdapter { |
| 57 | + constructor(name) { |
| 58 | + this.name = name; |
| 59 | + this.type = types[name]; |
| 60 | + if (shouldClean()) DbAdapter._cleaned = clean(); |
| 61 | + } |
| 62 | + |
| 63 | + async upsert(id, payload, expiresIn) { |
| 64 | + const expiresAt = getExpireAt(expiresIn); |
| 65 | + await getClient() |
| 66 | + .table(oidc_payloads) |
| 67 | + .insert({ |
| 68 | + id, |
| 69 | + type: this.type, |
| 70 | + payload: JSON.stringify(payload), |
| 71 | + grantId: payload.grantId, |
| 72 | + userCode: payload.userCode, |
| 73 | + uid: payload.uid, |
| 74 | + expiresAt, |
| 75 | + }) |
| 76 | + .onConflict(["id", "type"]) |
| 77 | + .merge(); |
| 78 | + } |
| 79 | + |
| 80 | + get _table() { |
| 81 | + return getClient() |
| 82 | + .table(oidc_payloads) |
| 83 | + .where("type", this.type); |
| 84 | + } |
| 85 | + |
| 86 | + _rows(obj) { |
| 87 | + return this._table.where(obj); |
| 88 | + } |
| 89 | + |
| 90 | + _result(r) { |
| 91 | + return r.length > 0 |
| 92 | + ? { |
| 93 | + ...JSON.parse(r[0].payload), |
| 94 | + ...(r[0].consumedAt ? { consumed: true } : undefined), |
| 95 | + } |
| 96 | + : undefined; |
| 97 | + } |
| 98 | + |
| 99 | + _findBy(obj) { |
| 100 | + return this._rows(obj).then(this._result); |
| 101 | + } |
| 102 | + |
| 103 | + find(id) { |
| 104 | + return this._findBy({ id }); |
| 105 | + } |
| 106 | + |
| 107 | + findByUserCode(userCode) { |
| 108 | + return this._findBy({ userCode }); |
| 109 | + } |
| 110 | + |
| 111 | + findByUid(uid) { |
| 112 | + return this._findBy({ uid }); |
| 113 | + } |
| 114 | + |
| 115 | + destroy(id) { |
| 116 | + return this._rows({ id }).delete(); |
| 117 | + } |
| 118 | + |
| 119 | + revokeByGrantId(grantId) { |
| 120 | + return this._rows({ grantId }).delete(); |
| 121 | + } |
| 122 | + |
| 123 | + consume(id) { |
| 124 | + return this._rows({ id }).update({ consumedAt: new Date() }); |
| 125 | + } |
| 126 | + }; |
| 127 | +} |
| 128 | + |
| 129 | +const defaultConfig = { |
| 130 | + client: "pg", |
| 131 | + connection: "postgresql://" |
| 132 | +}; |
| 133 | + |
| 134 | +const defaultAdapter = knexAdapter(defaultConfig) |
| 135 | +defaultAdapter.knexAdapter = knexAdapter |
| 136 | + |
| 137 | +module.exports = defaultAdapter |
0 commit comments