oidc: use better json based file store for objects

This commit is contained in:
Johannes Zellner
2023-03-24 20:08:17 +01:00
parent 44706b9c70
commit 99e0979c2e
7 changed files with 129 additions and 47 deletions

View File

@@ -3,6 +3,7 @@
exports = module.exports = {
start,
stop,
revokeByUserId,
clients: {
add: clientsAdd,
get: clientsGet,
@@ -97,6 +98,69 @@ async function clientsList() {
return results;
}
// -----------------------------
// Basic in-memory json file backed based data store
// -----------------------------
const DATA_STORE = {};
function load(modelName) {
assert.strictEqual(typeof modelName, 'string');
if (DATA_STORE[modelName]) return;
const filePath = path.join(paths.OIDC_STORE_DIR, `${modelName}.json`);
debug(`load: model ${modelName} based on ${filePath}.`);
let data = {};
try {
data = JSON.parse(fs.readFileSync(filePath), 'utf8');
} catch (e) {
debug(`load: failed to read ${filePath}, start with new one.`, e);
}
DATA_STORE[modelName] = data;
}
function save(modelName) {
assert.strictEqual(typeof modelName, 'string');
if (!DATA_STORE[modelName]) return;
const filePath = path.join(paths.OIDC_STORE_DIR, `${modelName}.json`);
debug(`save: model ${modelName} to ${filePath}.`);
try {
fs.writeFileSync(filePath, JSON.stringify(DATA_STORE[modelName]), 'utf8');
} catch (e) {
debug(`revokeByUserId: failed to write ${filePath}`, e);
}
}
// -----------------------------
// Session, Grant and Token management
// -----------------------------
// This is based on the same storage as the below CloudronAdapter
async function revokeByUserId(userId) {
assert.strictEqual(typeof userId, 'string');
debug(`revokeByUserId: userId:${userId}`);
function revokeObjects(modelName) {
load(modelName);
for (let id in DATA_STORE[modelName]) {
if (DATA_STORE[modelName][id].payload?.accountId === userId) delete DATA_STORE[modelName][id];
}
save(modelName);
}
revokeObjects('Session');
revokeObjects('Grant');
revokeObjects('AuthorizationCode');
revokeObjects('AccessToken');
}
// -----------------------------
// Generic oidc node module data store model
// -----------------------------
@@ -115,22 +179,10 @@ class CloudronAdapter {
constructor(name) {
this.name = name;
if (this.name === 'Client') {
this.store = null;
this.fileStorePath = null;
} else {
this.fileStorePath = path.join(paths.OIDC_STORE_DIR, `${name}.json`);
debug(`Creating storage adapter for ${name}`);
debug(`Creating storage adapter for ${name} backed by ${this.fileStorePath}`);
let data = {};
try {
data = JSON.parse(fs.readFileSync(this.fileStorePath), 'utf8');
} catch (e) {
debug(`filestore for adapter ${name} not found, start with new one`);
}
this.store = data;
if (this.name !== 'Client') {
load(name);
}
}
@@ -152,8 +204,8 @@ class CloudronAdapter {
if (this.name === 'Client') {
console.log('WARNING!! this should not happen as it is stored in our db');
} else {
this.store[id] = { id, expiresIn, payload, consumed: false };
if (this.fileStorePath) fs.writeFileSync(this.fileStorePath, JSON.stringify(this.store), 'utf8');
DATA_STORE[this.name][id] = { id, expiresIn, payload, consumed: false };
save(this.name);
}
}
@@ -191,11 +243,11 @@ class CloudronAdapter {
return tmp;
} else {
if (!this.store[id]) return null;
if (!DATA_STORE[this.name][id]) return null;
debug(`[${this.name}] find id:${id}`, this.store[id]);
debug(`[${this.name}] find id:${id}`, DATA_STORE[this.name][id]);
return this.store[id].payload;
return DATA_STORE[this.name][id].payload;
}
}
@@ -230,8 +282,8 @@ class CloudronAdapter {
if (this.name === 'Client') {
console.log('WARNING!! this should not happen as it is stored in our db');
} else {
for (let d in this.store) {
if (this.store[d].payload.uid === uid) return this.store[d].payload;
for (let d in DATA_STORE[this.name]) {
if (DATA_STORE[this.name][d].payload.uid === uid) return DATA_STORE[this.name][d].payload;
}
return false;
@@ -255,9 +307,8 @@ class CloudronAdapter {
if (this.name === 'Client') {
console.log('WARNING!! this should not happen as it is stored in our db');
} else {
if (this.store[id]) this.store[id].consumed = true;
if (this.fileStorePath) fs.writeFileSync(this.fileStorePath, JSON.stringify(this.store), 'utf8');
if (DATA_STORE[this.name][id]) DATA_STORE[this.name][id].consumed = true;
save(this.name);
}
}
@@ -277,9 +328,8 @@ class CloudronAdapter {
if (this.name === 'Client') {
console.log('WARNING!! this should not happen as it is stored in our db');
} else {
delete this.store[id];
if (this.fileStorePath) fs.writeFileSync(this.fileStorePath, JSON.stringify(this.store), 'utf8');
delete DATA_STORE[this.name][id];
save(this.name);
}
}
@@ -299,10 +349,10 @@ class CloudronAdapter {
if (this.name === 'Client') {
console.log('WARNING!! this should not happen as it is stored in our db');
} else {
for (let d in this.store) {
if (this.store[d].grantId === grantId) {
delete this.store[d];
return;
for (let d in DATA_STORE[this.name]) {
if (DATA_STORE[this.name][d].grantId === grantId) {
delete DATA_STORE[this.name][d];
return save(this.name);
}
}
}