oidc-lib
Version:
A library for creating OIDC Service Providers
334 lines (276 loc) • 10.6 kB
JavaScript
module.exports = {
initialize: initialize,
createOrUpdateDocument: createOrUpdateDocument,
getDocument: getDocument,
deleteDocument: deleteDocument,
queryCollection: queryCollection
};
var pk = null;
const HttpStatusCodes = { NOTFOUND: 404 };
async function initialize(pkInput, contentModuleName, provider){
try{
pk = pkInput;
var dbInfo = {
provider: provider,
contentModuleName: contentModuleName
};
validateModuleConfig(contentModuleName);
pk.util.log_debug("Initializing FileDb in content module " + contentModuleName);
dbInfo.contentModuleName = contentModuleName;
dbInfo.databaseName = getDbModuleConfigProperty(contentModuleName, 'databaseName');
dbInfo.databasePath = './oidc_lib_data/filedb_data/' + dbInfo.databaseName;
dbInfo.collections = {};
var collections = getDbModuleConfigProperty(contentModuleName, 'collections');
for (var collectionName in collections){
var collectionInfo = {
definition: { "id": collectionName },
path: dbInfo.databasePath + '/' + collectionName
};
dbInfo.collections[collectionName] = collectionInfo;
}
pk.dbs[contentModuleName] = dbInfo;
getDatabase(dbInfo);
for (var key in dbInfo.collections){
getCollection(dbInfo, key);
}
return dbInfo;
}
catch(err){
}
};
function getDatabase (dbInfo) {
var db_path_segs = dbInfo.databasePath.split('/');
var root = db_path_segs[0];
for (var count=1; count < db_path_segs.length; count++){
root += '/' + db_path_segs[count];
if (!pk.fs.existsSync(root)){
pk.fs.mkdirSync(root);
}
}
return;
};
function getCollection(dbInfo, collectionName) {
var collectionInfo = dbInfo.collections[collectionName];
if (!pk.fs.existsSync(collectionInfo.path)){
pk.fs.mkdirSync(collectionInfo.path);
}
}
function getDocument(dbInfo, collectionName, id) {
return new Promise((resolve, reject) => {
let documentPath = createIdPath(dbInfo, collectionName, id);
if (!documentPath){
reject('configuration error creating IdPath in getDocument');
}
var document;
pk.fs.readFile(documentPath, "utf8", (err, data) => {
if (err){
if (err.code === 'ENOENT'){
reject(err);
}
else{
pk.util.log_detail('unexpected error checking existance of record in file_db', err);
reject('unexpected error id createOrUpdateDocument');
}
return;
}
document = db_parse(data);
resolve (db_export(document));
});
});
};
function createDocument(dbInfo, collectionName, document){
return new Promise((resolve, reject) => {
let documentPath = createIdPath(dbInfo, collectionName, document.id);
if (!documentPath){
reject('configuration error creating IdPath in createDocument');
}
if (pk.fs.exists(documentPath)){
reject('Document already exists');
}
else {
var storedDoc = db_import(document);
pk.fs.writeFileSync(documentPath, db_stringify(storedDoc));
resolve(document);
}
});
};
function createOrUpdateDocument(dbInfo, collectionName, document, options){
return new Promise((resolve, reject) => {
if (!document.id){
reject("undefined document id needed for file_db")
}
let documentPath = createIdPath(dbInfo, collectionName, document.id);
if (!documentPath){
reject('configuration error creating IdPath in updateOrCreateDocument');
}
pk.fs.stat(documentPath, (err, stats) => {
if (err && err.code !== 'ENOENT'){
pk.util.log_detail('unexpected error checking existance of record in file_db', err);
reject('unexpected error id createOrUpdateDocument');
}
if (stats){
var previousdocument = db_export(db_parse(pk.fs.readFileSync(documentPath, "utf8")));
if (options && options.updateLogic !== undefined){
pk.util.log_debug('Document existed - update logic being applied');
options.updateLogic(previousdocument, document);
}
}
var storedDoc = db_import(document);
pk.fs.writeFile(documentPath, db_stringify(storedDoc), (err) => {
if (err){
var message = 'Error writing file-based db record to collection ' + collection;
pk.util.log_detail(message, err);
reject(message);
return;
}
resolve(document);
});
});
});
}
function queryCollection(dbInfo, collectionName, queryDictionaryOrString, indexName) {
if (typeof queryDictionaryOrString !== 'object'){
if (queryDictionaryOrString === undefined){
queryDictionaryOrString = {};
}
else {
throw 'file_db queryCollection currently does not support string queries';
}
}
var queryResponse = [];
var collectionInfo = dbInfo.collections[collectionName];
var collection = readCollection(collectionInfo.path);
return new Promise((resolve, reject) => {
for (var id in collection){
var entry = db_export(collection[id]);
var matchFound = true;
for (var attribute in queryDictionaryOrString){
if (entry[attribute] !== queryDictionaryOrString[attribute]){
matchFound = false;
break;
}
}
if (matchFound){
queryResponse.push(entry);
}
}
resolve(queryResponse);
});
}
function readCollection(collectionPath) {
var collection = {};
var fnames = pk.fs.readdirSync(collectionPath);
for (var i=0; i < fnames.length; i++){
var id = fnames[i];
var content = pk.fs.readFileSync(collectionPath + '/' + id, 'utf8');
collection[id] = db_parse(content);
}
return collection;
}
function deleteDocument(dbInfo, collectionName, id) {
let documentPath = createIdPath(dbInfo, collectionName, id);
if (!documentPath){
pk.util.log_error('configuration error creating IdPath in deleteDocument');
return;
}
pk.fs.unlink(documentPath, function (err) {
if (!err){
pk.util.log_detail('filedb deleteDocument succeeded');
}
});
};
function cleanup(pkInput, contentModuleName) {
pk = pkInput;
validateModuleConfig(contentModuleName);
var endpoint = getDbModuleConfigProperty(contentModuleName, 'endpoint');
var primaryKey = getDbModuleConfigProperty(contentModuleName, 'primaryKey');
var client = new documentDbDocumentClient(endpoint, { "masterKey": primaryKey });
var databaseName = getDbModuleConfigProperty(contentModuleName, 'databaseName');
var databaseDefinition = { id: databaseName };
var databaseUrl = `dbs/${databaseDefinition.id}`;
pk.util.log_debug(`Cleaning up by deleting database ${databaseDefinition.id}`);
return new Promise((resolve, reject) => {
client.deleteDatabase(databaseUrl, (err) => {
if (err) reject(err)
else resolve(null);
});
});
}
function validateModuleConfig(contentModuleName){
if (contentModuleName !== 'sts'){
if (pk.util.config.content_modules[contentModuleName].db === undefined){
throw "The " + contentModuleName + " content module does not define a db property in claimer_config";
}
}
}
function getDbModuleConfigProperty(contentModuleName, propertyName, throwOnUndefined)
{
if (throwOnUndefined === undefined || throwOnUndefined === true){
var dbInstance = pk.util.config.sts.db;
if (contentModuleName !== 'sts'){
dbInstance = pk.util.config.content_modules[contentModuleName].db;
}
if (dbInstance[propertyName] === undefined){
throw "Configuration property " + propertyName + " is not defined in content module " + contentModuleName;
}
}
return dbInstance[propertyName];
}
function isDbDisabled(pkInput, contentModuleName){
pk = pkInput;
var isDisabled = getDbModuleConfigProperty('disabled', false, contentModuleName);
if (isDisabled === undefined){
isDisabled = false;
}
return isDisabled;
}
function isset(param){
if (typeof param !== 'object'){
if (param === undefined || param === null || param.length === 0)
return false;
}
return true;
}
function createIdPath(dbInfo, collectionName, id){
var collectionInfo = dbInfo.collections[collectionName];
if (!collectionInfo){
pk.util.log_error('FileDB attempt to access undefined collection: ' + collectionName);
return;
}
return collectionInfo.path + '/' + encodeId(id);
}
function encodeId(id){
return encodeURIComponent(id);
}
function db_parse(data){
return JSON.parse(data);
}
function db_stringify(obj){
return JSON.stringify(obj);
}
function db_export(document){
var external = {};
for (var attr in document) {
if (document.hasOwnProperty(attr)){
var val = document[attr];
if (attr === 'id'){
val = decodeURIComponent(val);
}
external[attr] = val;
}
}
return external;
}
function db_import(external){
var document = {};
for (var attr in external) {
if (external.hasOwnProperty(attr)){
var val = external[attr];
if (attr === 'id'){
val = encodeURIComponent(val);
}
document[attr] = val;
}
}
return document;
}