249 lines
7.1 KiB
JavaScript
249 lines
7.1 KiB
JavaScript
/**
|
|
* @preserve Copyright (c) 2014-2015 IONU Security, Inc. All rights reserved.
|
|
*
|
|
* @file Permissions class for management and signature generation
|
|
*/
|
|
|
|
|
|
PERMISSION_KEY_OWNER = 'owner';
|
|
PERMISSION_KEY_TOPIC = 'topic';
|
|
|
|
PERMISSION_READ = 'read';
|
|
PERMISSION_WRITE = 'write';
|
|
PERMISSION_ADMIN = 'admin';
|
|
/*
|
|
PERMISSION_DOORWAY = 'doorway';
|
|
PERMISSION_STREAM = 'stream';
|
|
PERMISSION_HIDE = 'hide';
|
|
*/
|
|
PERMISSION_ASSIGNMENT_SUFFIX = 'Assign';
|
|
|
|
PERMISSION_ROOT_KEY = 'perms';
|
|
PERMISSION_TYPE_KEY = 'type'; // unset/empty 'file'; 'group'
|
|
PERMISSION_MEMBERS_KEY = "mbrs";
|
|
PERMISSION_SIGNATURE_KEY = "signature";
|
|
PERMISSION_DIGEST_KEY = "digest";
|
|
|
|
/**
|
|
* Permissions object
|
|
* @constructor
|
|
* @param {string|object} perms - JSON string or object
|
|
*/
|
|
function Permissions (perms) {
|
|
if (!(this instanceof Permissions)){
|
|
return new Permissions (perms);
|
|
}
|
|
if (typeof perms === 'string') {
|
|
this.perms = JSON.parse (perms);
|
|
}
|
|
else if (typeof perms === 'object') {
|
|
this.perms = perms;
|
|
}
|
|
else {
|
|
var error = new Error ('Invalid permissions');
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
function createPermissionsFromOffice(officeId){
|
|
return createPermissionsFromCollaborators(officeId, [officeId]);
|
|
}
|
|
|
|
function createPermissionsFromCollaborators(owner, offices, noSub){
|
|
var p = {read:[], write:[], admin:[], readAssign:[], writeAssign:[], adminAssign:[]};
|
|
for (var i = 0; i < offices.length; ++i) {
|
|
var officeId = offices[i];
|
|
if (officeId.match(/^urn:sl/) && !noSub) {
|
|
officeId = officeId.replace(/^urn:sl:.{6}:/,'').replace(/:.*/,'');
|
|
}
|
|
p.read.push(officeId);
|
|
p.write.push(officeId);
|
|
p.admin.push(officeId);
|
|
p.readAssign.push(officeId);
|
|
p.writeAssign.push(officeId);
|
|
p.adminAssign.push(officeId);
|
|
//p.hideAssign.push(officeId);
|
|
}
|
|
p.owner = owner||'';
|
|
if (typeof p.owner === 'object'){
|
|
p.owner = p.owner._id.replace(/^urn:sl:.{6}:/,'').replace(/:.*/,'');
|
|
}
|
|
p = new Permissions(p);
|
|
return p;
|
|
}
|
|
|
|
function createPermissionsFromTeam(owner, teamUrn){
|
|
return createPermissionsFromCollaborators(owner, [teamUrn], true);
|
|
}
|
|
|
|
// Define the prototype methods for Permissions object
|
|
Permissions.prototype = {
|
|
constructor: Permissions,
|
|
|
|
/**
|
|
* Add all unique references from the current permission key
|
|
*
|
|
* @param {array} set of all unique references
|
|
* @param {string} perms for key, e.g. read/readAssign...
|
|
* @return {array} set of all unique references
|
|
*/
|
|
addUniqueReferences: function (refs, perms) {
|
|
if (perms !== undefined) {
|
|
var numPerms = perms.length;
|
|
for (var j = 0; j < numPerms; ++j) {
|
|
var permVal = perms[j];
|
|
if (permVal === PERMISSION_KEY_OWNER) {
|
|
permVal = this.perms.owner;
|
|
}
|
|
var urn = permVal;
|
|
if (urn.slice (0, 3) !== 'urn') {
|
|
urn = this.urnPrefix + permVal + '::';
|
|
}
|
|
var len = refs.length;
|
|
var found = false;
|
|
for (var i = 0; i < len; ++i) {
|
|
if (refs[i] == urn) {
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
if (found === false) {
|
|
refs.push (urn);
|
|
}
|
|
}
|
|
}
|
|
return refs;
|
|
},
|
|
|
|
/**
|
|
* Get all the unique references in urn format, sorted with '|' delimiter and optional topic id
|
|
*
|
|
* @param {string} van - urn string urn:sl:000000:::
|
|
* @return {string} ordered set of all references
|
|
*/
|
|
getOrderedReferences: function (van) {
|
|
var refs = [];
|
|
var owner = this.perms.owner;
|
|
var permissionKeys = [PERMISSION_READ,PERMISSION_WRITE,PERMISSION_ADMIN/*,PERMISSION_DOORWAY,PERMISSION_STREAM,PERMISSION_HIDE*/];
|
|
var numKeys = permissionKeys.length, key = null;
|
|
this.urnPrefix = '';
|
|
if (van !== undefined && van !== null) {
|
|
var urnFields = van.split (':');
|
|
if (urnFields.length > 4) {
|
|
this.urnPrefix = urnFields[0] + ':' + urnFields[1] + ':' + urnFields[2] + ':';
|
|
}
|
|
}
|
|
for (var i = 0; i < numKeys; ++i) {
|
|
key = permissionKeys[i];
|
|
var perms = this.perms[key];
|
|
refs = this.addUniqueReferences (refs, perms);
|
|
key = permissionKeys[i] + PERMISSION_ASSIGNMENT_SUFFIX;
|
|
perms = this.perms[key];
|
|
refs = this.addUniqueReferences (refs, perms);
|
|
}
|
|
refs.sort();
|
|
var delim = '';
|
|
var str = '';
|
|
refs.forEach(function(value) {
|
|
str += delim + value;
|
|
delim = '|';
|
|
});
|
|
// Append "topic"...
|
|
var topic = this.perms[PERMISSION_KEY_TOPIC];
|
|
if (topic !== undefined && topic.length > 0) {
|
|
str += delim + topic;
|
|
}
|
|
return str;
|
|
},
|
|
|
|
/**
|
|
* Convert permissions to ordered JSON string for path hash computation
|
|
* removes "owner" property, replaces "owner" in perms arrays with urn
|
|
*
|
|
* @param {string} van - urn string urn:sl:000000:::
|
|
* @return {string} ordered set of all references and optional topic
|
|
*/
|
|
getSignature: function (van) {
|
|
var perms = this.getOrderedReferences (van);
|
|
var md = forge.md.md5.create();
|
|
md.update (perms);
|
|
var sig = md.digest().toHex();
|
|
return sig.substring (0, 12);
|
|
},
|
|
|
|
/**
|
|
* Convert permissions to ordered JSON string for path hash computation
|
|
* removes "owner" property, replaces "owner" in perms arrays with urn
|
|
*
|
|
* @return {string} JSON string
|
|
*/
|
|
toOrderedString: function() {
|
|
var permissionKeys = [PERMISSION_READ,PERMISSION_WRITE,PERMISSION_ADMIN/*,PERMISSION_DOORWAY,PERMISSION_STREAM,PERMISSION_HIDE*/];
|
|
var json = '{';
|
|
var numKeys = permissionKeys.length, key = null;
|
|
var comma = '';
|
|
var owner = this.perms.owner;
|
|
for (var i = 0; i < 2; ++i) {
|
|
var suffix = (i == 0) ? '' : PERMISSION_ASSIGNMENT_SUFFIX;
|
|
for (var j = 0; j < numKeys; ++j) {
|
|
key = permissionKeys[j] + suffix;
|
|
var perms = this.perms[key];
|
|
if (perms === undefined) {
|
|
continue;
|
|
}
|
|
perms.sort();
|
|
var numPerms = perms.length;
|
|
json += comma + '"' + key + '":[';
|
|
var bHasOwner = false;
|
|
for (var k = 0; k < numPerms; ++k) {
|
|
var permVal = perms[k];
|
|
if (permVal === owner) {
|
|
bHasOwner = true;
|
|
}
|
|
if (permVal === PERMISSION_KEY_OWNER) {
|
|
if (bHasOwner === true) {
|
|
// we already emitted the UUID for owner so don't do it again
|
|
// note that normal "assign" logic prevents all other duplicate values
|
|
continue;
|
|
}
|
|
else {
|
|
permVal = owner;
|
|
}
|
|
}
|
|
|
|
if (k > 0) {
|
|
json += ',';
|
|
}
|
|
json += '"' + permVal + '"';
|
|
}
|
|
json += ']';
|
|
comma = ",";
|
|
}
|
|
}
|
|
|
|
// Append "topic"...
|
|
var topic = this.perms[PERMISSION_KEY_TOPIC];
|
|
if (topic !== undefined && topic.length > 0) {
|
|
json += ',"' + PERMISSION_KEY_TOPIC + '":"' + topic + '"';
|
|
}
|
|
json += '}';
|
|
return json;
|
|
},
|
|
|
|
/**
|
|
* Generate the path hash, left 12 bytes of hex encoded MD5 hash of the ordered JSON permissions
|
|
*
|
|
* @return {string} path hash
|
|
*/
|
|
getPathHash: function () {
|
|
var perms = this.toOrderedString();
|
|
var md = forge.md.md5.create();
|
|
md.update (perms);
|
|
var sig = md.digest().toHex();
|
|
return sig.substring (0, 12);
|
|
}
|
|
|
|
}
|
|
|
|
|