oidc-lib
Version:
A library for creating OIDC Service Providers
454 lines (415 loc) • 20.3 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
var hub_mgmt = require('./hub_sw_mgmt');
var indexed_db_module = require('../claimer_sts/dbs/indexed_db');
var moduleName = 'hub_sw_provider';
module.exports = {
hub_provider: hub_provider,
}
function hub_provider(){
var pk;
const HttpStatusCodes = { NOTFOUND: 404 };
var indexed_db;
var METADATACOLLECTIONNAME;
var hubConfig;
Object.defineProperty(this, "initialize", {
value: function(pkInput, contentModuleName, provider){
return new Promise((resolve, reject) => {
var hubDbInfo;
var hubDbContents = {};
var schemas = [];
var hubInfo;
pk = pkInput;
hubConfig = pk.util.config.hub;
METADATACOLLECTIONNAME = indexed_db_module.METADATACOLLECTIONNAME;
hub_mgmt.loadHubInfo(hub_mgmt.HUBINSTANCEMONIKER)
.then(instanceInfo => {
if (instanceInfo){
hubInfo = instanceInfo;
if (hubInfo.flockDid !== hub_mgmt.FLOCKNOTPRESENT && hub_mgmt.syncInForeground()){
return pk.util.simpleResolver.resolve(hubConfig.did)
}
else{
// used to be by default assume connection
// return true;
return false;
}
}
}, err => {
reject(err);
})
.then(res => {
if (res){
pk.util.offline = false;
}
}, err => {
pk.util.offline = true;
})
.then(() => {
indexed_db = new indexed_db_module.indexed_db_provider();
return indexed_db.initialize(pkInput, contentModuleName, indexed_db)
})
.then(dbInfo => {
if (dbInfo){
hubDbInfo = {
contentModuleName: dbInfo.contentModuleName,
collections: dbInfo.collections,
databaseDefinition: dbInfo.databaseDefinition,
databaseName: dbInfo.databaseName,
databaseUrl: dbInfo.databaseUrl,
schemaVersion: dbInfo.schemaVersion,
didLocalOnly: hubInfo.didLocalOnly,
provider: this,
dbInfo: dbInfo
};
hubDbInfo.authenticationBundle = new hub_mgmt.authenticationBundleFactory(hubInfo);
resolve(hubDbInfo);
}
}, function(err){
pk.util.log_detail('ERROR getting authentication token', err);
})
});
}
})
Object.defineProperty(this, "fullSync", {
value: function(hubDbInfo){
return new Promise((resolve, reject) => {
if (pk.util.offline || !hubDbInfo.authenticationBundle || hubDbInfo.authenticationBundle.instanceDid === undefined){
return resolve(true);
}
var collectionNames = [];
var hubCollectionPromises = [];
var hubDbContents = {};
var localDbContents = {};
if (hub_mgmt.syncInForeground() === false){
resolve(false);
return;
}
var i=0;
for (var collectionName in hubDbInfo.collections){
collectionNames[i++] = collectionName;
hubCollectionPromises.push(hubDbInfo.provider.queryHubCollection(hubDbInfo, collectionName, {}, { decrypt: false }));
}
Promise.all(hubCollectionPromises)
.then(collectionInfos => {
for (var i=0; i < collectionInfos.length; i++){
var collectionName = collectionNames[i];
var collectionElements = collectionInfos[i];
var hubCollection = {};
for (var j=0; j < collectionElements.length; j++){
var hubElement = collectionElements[j];
hubCollection[hubElement.didMeta.object_id] = hubElement;
}
hubDbContents[collectionName] = hubCollection;
}
var promises = [];
//query the underlying indexeddb so it is not decrypted
for (var collectionName in hubDbInfo.collections){
promises.push(hubDbInfo.dbInfo.provider.queryCollection(hubDbInfo.dbInfo, collectionName, {}));
}
return Promise.all(promises);
}, err => {
reject(err);
})
.then(dbCollections => {
for (var i=0; i < dbCollections.length; i++){
var dbCollection = dbCollections[i];
var sync_id;
var unsynced_count = 0;
var localCollection = {};
for (var j=0; j < dbCollection.length; j++){
var localElement = dbCollection[j];
if (localElement.didMeta.object_id === undefined){
sync_id = '_' + (unsynced_count++).toString();
}
else{
sync_id = localElement.didMeta.object_id;
}
localCollection[sync_id] = localElement;
}
localDbContents[collectionNames[i]] = localCollection;
}
hubDbInfo.suppressHubUpdate = true;
var localUpdatePromises = []
for (var collection in hubDbContents){
var hubCollection = hubDbContents[collection];
for (var element in hubCollection){
var hubElement = hubCollection[element];
var localElement = localDbContents[collection][element];
if (localElement === undefined || Date.parse(localElement.didMeta.updated_at) < Date.parse(hubElement.didMeta.updated_at)){
localUpdatePromises.push(hubDbInfo.dbInfo.provider.createOrUpdateDocument(hubDbInfo.dbInfo, collection, hubElement, null));
}
}
}
return Promise.all(localUpdatePromises);
}, err => {
reject(err);
})
.then(localUpdateResults => {
hubDbInfo.suppressHubUpdate = false;
var hubUpdatePromises = []
for (var collectionName in localDbContents){
var localCollection = localDbContents[collectionName];
for (var elementId in localCollection){
var element = localCollection[elementId];
if (element.didMeta.object_id === undefined){
hubUpdatePromises.push(hub_mgmt.updateHub(hubDbInfo, collectionName, element, { encrypt: false }));
}
}
}
return Promise.all(hubUpdatePromises);
}, err => {
hubDbInfo.suppressHubUpdate = false;
reject(err);
})
.then(hubUpdateResults => {
var date = new Date();
var now = date.getTime();
pk.util.sync_info.last_sync_time = now;
resolve(true);
}, err => {
reject(err);
delete hubDbInfo.suppressHubUpdate;
})
});
}
})
Object.defineProperty(this, "createOrUpdateDocument", {
value: function (hubDbInfo, collectionName, objectToWrite) {
return new Promise((resolve, reject) => {
hub_mgmt.updateHub(hubDbInfo, collectionName, objectToWrite)
.then(function(writeResult){
resolve(objectToWrite);
}, function(err){
reject(err);
})
});
}
});
Object.defineProperty(this, "getDocument", {
value: function (hubDbInfo, collectionName, local_id) {
return new Promise((resolve, reject) => {
indexed_db.getDocument(hubDbInfo.dbInfo, collectionName, local_id)
.then( record => {
return hub_mgmt.decryptDbRecord(hubDbInfo, collectionName, record);
}, err => {
reject(err);
})
.then( plaintext => {
resolve(plaintext);
}, err => {
reject(err);
})
});
}
});
Object.defineProperty(this, "queryCollection", {
value: function (hubDbInfo, collectionName, queryDictionaryOrString, indexName) {
return new Promise((resolve, reject) => {
var encryptedRecords;
indexed_db.queryCollection(hubDbInfo.dbInfo, collectionName, queryDictionaryOrString, indexName)
.then(function(queryResult){
encryptedRecords = queryResult;
var plaintextPromises = [];
for (var i=0; i < queryResult.length; i++){
var record = queryResult[i];
plaintextPromises.push(hub_mgmt.decryptDbRecord(hubDbInfo, collectionName, record));
}
return Promise.all(plaintextPromises);
}, function(err){
reject(err);
})
.then(plaintextRecords => {
if (plaintextRecords){
resolve(plaintextRecords);
}
}, err => {
reject(err);
})
});
}
});
Object.defineProperty(this, "deleteDocument", {
value: function(hubDbInfo, collectionName, local_id){
return indexed_db.deleteDocument(hubDbInfo.dbInfo, collectionName, local_id);
}
});
// options: decrypt - when false, do not decrypt payload
// revisions - when true, return revisions
Object.defineProperty(this, "queryHubCollection", {
value: function (hubDbInfo, collectionName, queryDictionary, options) {
var collectionInfo = hubDbInfo.collections[collectionName];
var decodedCommitArray = [];
var messageTransmitted;
return new Promise((resolve, reject) => {
messageTransmitted = {
"@context": "https://schema.identity.foundation/0.1",
"@type": "ObjectQueryRequest",
"iss": hubDbInfo.authenticationBundle.instanceDid,
"aud": hubConfig.did,
"sub": hubDbInfo.authenticationBundle.flockDid,
"query": {
"interface": collectionInfo.hubInterface,
"context": collectionInfo.hubContext,
"type": collectionInfo.hubType
// "object_id": ["3a9de008f526d239..", "a8f3e7..."]
}
}
hub_mgmt.hubRequest(messageTransmitted, hubDbInfo.authenticationBundle, hubConfig.did, 'queryHubCollection meta')
.then(function(response){
if (response){
switch (response['@type']){
case 'ObjectQueryResponse':
return(response.objects);
break;
}
}
}, function(err){
reject(err);
})
.then(objectMetaArray => {
if (objectMetaArray){
var objectIdArray = [];
if (objectMetaArray.length < 1){
// nothing to return
resolve([]);
return;
}
for (var i=0; i < objectMetaArray.length; i++){
var obj = objectMetaArray[i];
objectIdArray.push(obj.id);
}
var message = {
"@context": "https://schema.identity.foundation/0.1",
"@type": "CommitQueryRequest",
"iss": hubDbInfo.authenticationBundle.instanceDid,
"aud": hubConfig.did,
"sub": hubDbInfo.authenticationBundle.flockDid,
"query": {
"object_id": objectIdArray
}
}
return hub_mgmt.hubRequest(message, hubDbInfo.authenticationBundle, hubConfig.did, 'queryHubCollection commits');
}
}, err => {
reject(err);
})
.then(function(response){
if (response){
switch (response['@type']){
case 'CommitQueryResponse':
return(response.commits);
break;
}
}
}, function(err){
reject(err);
})
.then(rawCommitArray => {
if (rawCommitArray){
var plaintextPromises = [];
for (var i=0; i < rawCommitArray.length; i++){
var commit = rawCommitArray[i];
commit.protected = JSON.parse(pk.base64url.decode(commit.protected));
commit.payload = JSON.parse(pk.base64url.decode(commit.payload));
decodedCommitArray.push(commit);
if (options && options.decrypt === false){
plaintextPromises.push(commit.payload);
}
else{
plaintextPromises.push(hub_mgmt.decryptDbRecord(hubDbInfo, collectionName, commit.payload));
}
}
return Promise.all(plaintextPromises);
}
}, err => {
reject(err);
})
.then(plaintextPayloads => {
if (plaintextPayloads){
var hubCollection = {};
for (var i=0; i < plaintextPayloads.length; i++){
var plaintext = plaintextPayloads[i];
var commit = decodedCommitArray[i];
commit.payload = plaintext;
var object_id = commit.header.object_id;
if (object_id === undefined){
object_id = commit.protected.object_id;
}
var hubObject = hubCollection[object_id];
if (hubObject === undefined){
hubObject = {
object_id: object_id,
integral: {},
revisions: []
};
}
hubObject.revisions.push(commit);
hubCollection[object_id] = hubObject;
}
return integrateHubCollection(hubCollection);
}
}, err => {
reject(err);
})
.then(integratedCollection => {
if (integratedCollection){
var hubCollection = [];
for (var key in integratedCollection){
var record = integratedCollection[key].integral;
var matchFound = true;
if (queryDictionary){
for (var prop in queryDictionary){
if (record[prop] !== queryDictionary[prop]){
matchFound = false;
break;
}
}
}
if (matchFound){
// when revisions required substitute
// the integratedCollection for a record
if (options && options.revisions === true){
var ic = integratedCollection[key];
ic.didMeta = {
object_id: ic.object_id
};
hubCollection.push(ic);
}
else{
if (record.didMeta === undefined){
record.didMeta = {};
}
record.didMeta.object_id = key;
var revisions = integratedCollection[key].revisions;
record.didMeta.revision = revisions[revisions.length - 1].header.rev;
hubCollection.push(record);
}
}
}
resolve(hubCollection);
}
}, err => {
reject(err);
})
});
}
});
function integrateHubCollection(hubCollection){
for(var key in hubCollection){
var hubObject = hubCollection[key];
if (hubObject.revisions.length > 0){
hubObject.revisions.sort(compareRevisions);
var assembledObject = hubObject.revisions[hubObject.revisions.length - 1];
var record = assembledObject.payload;
record.didMeta.object_id = hubObject.object_id;
record.didMeta.updated_at = assembledObject.protected.committed_at;
hubObject.integral = record;
}
}
return hubCollection;
}
function compareRevisions(a, b){
return Date.parse(a.protected.committed_at) - Date.parse(b.protected.committed_at);
}
}