drp-mesh
Version:
321 lines (293 loc) • 10.7 kB
JavaScript
'use strict';
const { DRP_MethodParams, DRP_GetParams } = require("./params");
const { DRP_CmdError, DRP_ErrorCode } = require("./packet");
let IsTrue = function (value) {
if (typeof (value) === 'string') {
value = value.trim().toLowerCase();
}
switch (value) {
case true:
case "true":
case 1:
case "1":
case "on":
case "y":
case "yes":
return true;
default:
return false;
}
}
class DRP_AuthInfo {
/**
*
* @param {string} type
* @param {string} value
* @param {any} userInfo
*/
constructor(type, value, userInfo) {
this.type = type || null;
this.value = value || null;
this.userInfo = userInfo || null;
}
}
class DRP_Permission {
/**
*
* @param {boolean} read
* @param {boolean} write
* @param {boolean} execute
*/
constructor(read, write, execute) {
this.read = IsTrue(read);
this.write = IsTrue(write);
this.execute = IsTrue(execute);
}
}
class DRP_PermissionSet {
/**
*
* @param {Object<string,DRP_Permission>} keys
* @param {Object<string,DRP_Permission>} users
* @param {Object<string,DRP_Permission>} groups
*/
constructor(keys, users, groups) {
this.Keys = keys || {};
this.Users = users || {};
this.Groups = groups || {};
}
}
class DRP_Securable {
/**
*
* @param {DRP_PermissionSet} permissionSet Permission set for accessing object
*/
constructor(permissionSet) {
this.__permissionSet = permissionSet;
}
/**
*
* @param {DRP_AuthInfo} callerAuthInfo
* @param {string} operationType
*/
CheckPermission(callerAuthInfo, operationType) {
try {
// If no permission set is in place, default to allowed
if (!this.__permissionSet) {
return true;
}
if (callerAuthInfo && callerAuthInfo.type) {
// Is it a token or a key?
switch (callerAuthInfo.type) {
case 'key':
// Check API key permissions
return this.#IsOperationAllowed(this.__permissionSet.Keys[callerAuthInfo.value], operationType);
break;
case 'token':
// Check individual permissions
if (this.#IsOperationAllowed(this.__permissionSet.Users[callerAuthInfo.userInfo.UserName], operationType)) return true;
// Check group permissions
for (let i = 0; i < callerAuthInfo.userInfo.Groups.length; i++) {
let userGroupName = callerAuthInfo.userInfo.Groups[i];
if (this.#IsOperationAllowed(this.__permissionSet.Groups[userGroupName], operationType)) return true;
}
break;
default:
}
}
return false;
} catch (ex) {
return false;
}
}
/**
*
* @param {DRP_Permission} thisPermission
* @param {string} operationType
*/
#IsOperationAllowed(thisPermission, operationType) {
if (!thisPermission) return false;
let isAllowed = false;
switch (operationType) {
case 'read':
if (thisPermission.read) isAllowed = true;
break;
case 'write':
if (thisPermission.write) isAllowed = true;
break;
case 'execute':
if (thisPermission.execute) isAllowed = true;
break;
default:
}
return isAllowed;
}
}
class DRP_VirtualDirectory extends DRP_Securable {
#listFunc
#getItemFunc
constructor(listFunc, getItemFunc, permissionSet) {
super(permissionSet);
this.#listFunc = listFunc;
this.#getItemFunc = getItemFunc;
}
/**
* List contents of virtual directory
* @param {DRP_MethodParams} params
*/
async List(params) {
if (!this.CheckPermission(params.__authInfo, "read")) {
throw new DRP_CmdError("Unauthorized", DRP_ErrorCode.UNAUTHORIZED, "VirtualDirectory");
}
return await this.#listFunc(params);
}
/**
* Get item of virtual directory
* @param {DRP_MethodParams} params
*/
async GetItem(params) {
if (!this.CheckPermission(params.__authInfo, "read")) {
throw new DRP_CmdError("Unauthorized", DRP_ErrorCode.UNAUTHORIZED, "VirtualDirectory");
}
return await this.#getItemFunc(params);
}
}
class DRP_VirtualObject extends DRP_Securable {
constructor(securedObject, permissionSet) {
super(permissionSet);
this.securedObject = securedObject;
}
}
class DRP_VirtualFunction_Switch {
constructor(switchName, dataType, description) {
this.switchName = switchName;
this.dataType = dataType;
this.description = description;
}
}
class DRP_VirtualFunction extends DRP_Securable {
/**
* Virtual Functions should translate to Swagger Routes
* @param {string} name Function name
* @param {string} description Description
* @param {string} usage Usage describing how function is to be called
* @param {Object.<string,DRP_VirtualFunction_Switch>} switches Optional switches
* @param {Function} securedFunction Function to execute
* @param {DRP_PermissionSet} permissionSet Permissions assigned to function
*/
constructor(name, description, usage, switches, securedFunction, permissionSet) {
super(permissionSet);
this.name = name;
this.description = description || '';
this.usage = usage || '';
this.switches = switches || {};
this.function = securedFunction;
}
/**
* Execute Virtual Function
* @param {DRP_MethodParams} params
*/
async Execute(params) {
let results = null;
// Check permissions
if (!this.CheckPermission(params.__authInfo, "execute")) {
throw new DRP_CmdError("Unauthorized", DRP_ErrorCode.UNAUTHORIZED, "VirtualFunction");
}
// If the user wants info on the function, return ShowHelp
if (params.__verb === "man") {
return this.ShowHelp();
}
// Verify that the user is making a call to execute
if (params.__verb !== "exec" && params.__verb !== "SetItem") {
throw new DRP_CmdError(`Invalid operation (${params.__verb})`, DRP_ErrorCode.BADREQUEST, "VirtualFunction");
}
// Parse parameters and pass to function
results = await this.function(params);
return results;
}
ShowHelp() {
let output = `Usage: ${this.name} ${this.usage}\r\n`;
output += `${this.description}\r\n\r\n`;
output += "Optional arguments:\r\n";
let switchesKeys = Object.keys(this.switches);
if (switchesKeys.length > 0) {
for (let i = 0; i < switchesKeys.length; i++) {
output += ` -${switchesKeys[i]}\t${this.switches[switchesKeys[i]].description}\r\n`;
}
} else {
output += " (none)\r\n";
}
return output;
}
ParseSwitchesAndData(switchesAndData, skipVarEval) {
let returnObj = {
switches: {},
data: ""
}
if (!switchesAndData) return returnObj;
// Built regex
/**
* 1. Define empty array for switch regex patterns
* 2. Iterate over switches, add switch regex to array
* 3. Join with OR into string
* 4. Add to template
* 5. Evaluate
**/
/** List containing */
let switchDataRegExList = [];
if (this.switches) {
let switchList = Object.keys(this.switches);
for (let i = 0; i < switchList.length; i++) {
let thisSwitchDataRegEx;
let thisParameter = this.switches[switchList[i]];
if (thisParameter.dataType) {
thisSwitchDataRegEx = `(?: ?-(?:${thisParameter.switchName}) (?:(?:".*?")|(?:'.*?')|(?:[^-][^ ?]*)))`
} else {
thisSwitchDataRegEx = `(?: ?-(?:${thisParameter.switchName}))`
}
switchDataRegExList.push(thisSwitchDataRegEx);
}
}
let switchDataRegEx = new RegExp('^((?:' + switchDataRegExList.join('|') + ')*)?(?: ?([^-].*))?$');
try {
let switchRegEx = / ?-(\w)(?: ((?:".*?")|(?:'.*?')|(?:[^-][^ ?]*)))?/g;
let switchDataMatch = switchesAndData.match(switchDataRegEx);
if (switchDataMatch) {
let switchHash = {};
let switchMatch;
while (switchMatch = switchRegEx.exec(switchDataMatch[1])) {
let varName = switchMatch[1];
let varValue = switchMatch[2] || null;
if (skipVarEval) {
switchHash[varName] = varValue;
} else {
switchHash[varName] = this.EvaluateStringForVariables(varValue);
}
}
returnObj.switches = switchHash;
if (skipVarEval) {
returnObj.data = switchDataMatch[2] || "";
} else {
returnObj.data = this.EvaluateStringForVariables(switchDataMatch[2]) || "";
}
}
} catch (ex) {
let ted = 1;
}
return returnObj;
}
// Function will be used as part of a service's Swagger doc. The route will
// be derived by a previous function which scans the service's structure and
// looks for virtual functions. Global ones will be in ClientCmds.
TranslateToSwagger() {
}
}
module.exports = {
DRP_Permission: DRP_Permission,
DRP_PermissionSet: DRP_PermissionSet,
DRP_Securable: DRP_Securable,
DRP_VirtualDirectory: DRP_VirtualDirectory,
DRP_VirtualObject: DRP_VirtualObject,
DRP_VirtualFunction: DRP_VirtualFunction,
DRP_VirtualFunction_Switch: DRP_VirtualFunction_Switch
}