UNPKG

wasteful-scope

Version:

OAuth2 scope utilities for the wasteful scope parsing, comparing, merging, etc

221 lines (182 loc) 5.86 kB
'use strict'; var PromiseA = require('bluebird').Promise ; function create(scopeGroups) { var fieldGroups ; fieldGroups = ['readable', 'writeable', 'executable']; exports.parse = function parseScope(scope) { var scopeObjs = {} , invalid = [] , scopes ; if (Array.isArray(scope)) { scopes = scope; } else { scopes = (scope||'').split(' '); } // group.subgroup:rfields:wfields:xfields // TODO check individual fields scopes.forEach(function (scope) { var groups = scope.split(':') , group = groups[0] || '' ; if (!groups[0]) { groups = []; } if (!scopeGroups[group]) { invalid.push({ group: group , readable: (groups[1] || '').split(/,/g) , writeable: (groups[2] || '').split(/,/g) , executable: (groups[3] || '').split(/,/g) , raw: scope }); } else { scopeObjs[group] = { group: group , readable: (groups[1] || '').split(/,/g) , writeable: (groups[2] || '').split(/,/g) , executable: (groups[3] || '').split(/,/g) }; if (!scopeObjs[group].readable[0]) { scopeObjs[group].readable = []; } if (!scopeObjs[group].writeable[0]) { scopeObjs[group].writeable = []; } if (!scopeObjs[group].executable[0]) { scopeObjs[group].executable = []; } } }); return { scope: scopeObjs, invalid: invalid }; }; exports.diff = function (grantedScope, requestedScope) { if ('string' === typeof grantedScope) { grantedScope = exports.parse(grantedScope); } if ('string' === typeof requestedScope) { requestedScope = exports.parse(requestedScope); } grantedScope = grantedScope || { scope: {} }; requestedScope = requestedScope || { scope: {} }; var deltaScope = {} ; Object.keys(requestedScope.scope).forEach(function (groupname) { var reqGroup = requestedScope.scope[groupname] , hasGroup = grantedScope.scope[groupname] , newGroup ; if (!reqGroup) { return; } if (!hasGroup) { deltaScope[groupname] = reqGroup; return; } fieldGroups.forEach(function (key) { var reqFields = reqGroup[key] , hasFields = hasGroup[key] ; if (!reqFields || 0 === reqFields.length) { return; } if (!hasFields) { newGroup[key] = reqFields.slice(0); return; } reqFields.forEach(function (field) { if (-1 === hasFields.indexOf(field)) { if (!newGroup) { newGroup = deltaScope[groupname] = { }; newGroup.group = hasGroup.group || reqGroup.group; } if (!newGroup[key]) { newGroup[key] = []; } newGroup[key].push(field); } }); }); }); return exports.stringify({ scope: deltaScope }); }; // TODO make subgroups subojects? exports.merge = function (grantedScope, requestedScope) { if ('string' === typeof grantedScope) { grantedScope = exports.parse(grantedScope); } if ('string' === typeof requestedScope) { requestedScope = exports.parse(requestedScope); } grantedScope = grantedScope || { scope: {} }; requestedScope = requestedScope || { scope: {} }; Object.keys(requestedScope.scope).forEach(function (groupname) { // groupname i.e. stake.leadership // group i.e. { group: "", readable: [], writeable: [], executable: [] } var curGroup = grantedScope.scope[groupname] = grantedScope.scope[groupname] || {} , newGroup = requestedScope.scope[groupname] = requestedScope.scope[groupname] || {} ; curGroup.group = curGroup.group || newGroup.group; fieldGroups.forEach(function (key) { curGroup[key] = curGroup[key] || []; newGroup[key] = newGroup[key] || []; newGroup[key].forEach(function (newField) { if (-1 === curGroup[key].indexOf(newField)) { curGroup[key].push(newField); } }); }); }); return exports.stringify(grantedScope); }; function getScopeDelta(grantedScopeString, reqScopeString) { // We only want to ask the user to grant this application permissions // that the user has not yet given it before. // However, this auth code should be bound to the scope it requested return new PromiseA(function (resolve/*, reject*/) { var grantedScope = exports.parse(grantedScopeString) // wrapped with scope , requestedScope = exports.parse(reqScopeString) , info = { deltaScopeString: exports.diff(grantedScope, requestedScope) , invalids: requestedScope.invalid , requestedScope: requestedScope } ; resolve(info); }); } exports.stringify = function (scopeMap) { scopeMap = scopeMap.scope || scopeMap; var scopeArr ; if (Array.isArray(scopeMap)) { scopeArr = scopeMap; } else { scopeMap = scopeMap.scope || scopeMap; scopeArr = Object.keys(scopeMap).map(function (k) { if (k !== scopeMap[k].group) { throw new Error("index and name do not match '" + k + "' '" + scopeMap[k].group + "'"); } return scopeMap[k]; }); } return scopeArr.map(function (s) { var str = s.group ; // read, write, exec fieldGroups.forEach(function (g) { if (!s[g]) { s[g] = []; } str += ':' + s[g].join(','); }); return str; }).join(' '); }; exports.getScopeDelta = getScopeDelta; return exports; } module.exports.create = create;