UNPKG

oidc-lib

Version:

A library for creating OIDC Service Providers

454 lines (415 loc) 20.3 kB
"use strict" 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); } }