diff --git a/docs/playground.md b/docs/playground.md index fa2980c..4ba75b2 100644 --- a/docs/playground.md +++ b/docs/playground.md @@ -14,7 +14,7 @@ Try out scopes and rules in scopie to determine if the actor would be allowed to -
+
Valid
## Actor Rules @@ -22,7 +22,7 @@ blog/create allow/blog/create|update allow/accounts/read -
+
Valid
## Result
Is Allowed
diff --git a/docs/static/playground.js b/docs/static/playground.js index 9a7aec0..517cba2 100644 --- a/docs/static/playground.js +++ b/docs/static/playground.js @@ -1,7 +1,7 @@ window.addEventListener("load", async function() { console.log("scopie playground initializing") - window.scopie = await import("/static/scopie.browser.min.js"); + window.scopie = await import("/static/scopie.browser.min.v0.3.0.js"); window.actionScopesInput = document.getElementById("action-scopes-input"); window.actionScopesError = document.getElementById("action-scopes-error"); @@ -15,7 +15,7 @@ window.addEventListener("load", async function() { window.updateAllowedState = function() { try { - window.isAllowedDisplay.textContent = scopie.isAllowed( + window.isAllowedDisplay.textContent = window.scopie.isAllowed( window.actionScopesInput.value.trim().split('\n'), window.actorRulesInput.value.trim().split('\n'), ) ? "Is Allowed" : "Is Not Allowed" @@ -24,25 +24,18 @@ window.addEventListener("load", async function() { } } - /* window.actionScopesInput.addEventListener("keyup", function() { - console.log(window.actionScopesInput.value.trim().split('\n')) - const e = scopie.validateScope(window.actionScopesInput.value.trim().split('\n')) - console.log('e', e) + const e = window.scopie.validateScopes(window.actionScopesInput.value.trim().split('\n')) window.actionValid = e === undefined; window.actionScopesError.textContent = window.actionValid ? "Valid" : e.toString() window.updateAllowedState(); }); window.actorRulesInput.addEventListener("keyup", function() { - console.log(window.actorRulesInput.value.trim().split('\n')) - console.log('e', e) - const e = scopie.validateScope(window.actorRulesInput.value.trim().split('\n')) + const e = window.scopie.validateScopes(window.actorRulesInput.value.trim().split('\n')) window.actorValid = e === undefined; window.actorRulesError.textContent = window.actorValid ? "Valid" : e.toString(); window.updateAllowedState(); }); - */ - window.actionScopesInput.addEventListener("keyup", window.updateAllowedState) - window.actorRulesInput.addEventListener("keyup", window.updateAllowedState) + window.updateAllowedState() }) diff --git a/docs/static/scopie.browser.min.js b/docs/static/scopie.browser.min.js deleted file mode 100644 index 0f41bf8..0000000 --- a/docs/static/scopie.browser.min.js +++ /dev/null @@ -1,2 +0,0 @@ -export const arraySeperator="|",blockSeperator="/",wildcard="*",varPrefix="@";export function isAllowed(r,e,n){if(e.length===0)return!1;if(r.length===0)throw new Error("scopie-106: action scopes was empty");let t;n&&(t=new Map(Object.entries(n)));let o=!1;for(let s=0;s="a"&&r<="z"||r>="A"&&r<="Z"||r>="0"&&r<="9"?!0:r==="_"||r==="-"||r===varPrefix||r===wildcard}function d(r,e){for(let n=e+1;n=0){for(;i1&&r[i+1]===wildcard?new Error("scopie-103 in actor: super wildcard found in array block"):new Error("scopie-102 in actor: wildcard found in array block");if(r.substring(i,l)===t.substring(o,s))return!0;i=l+1}return!1}return r.substring(e,n)===t.substring(o,s)}function h(r,e,n){let t=u("actor",r,0)+1,o=0,s=0,f=0;for(;tf)throw new Error("scopie-105 in actor: super wildcard not in the last block");return!0}if(!g(r,t,f,e,o,s,n))return!1;o=s+1,t=f+1}return!0} -//# sourceMappingURL=scopie.browser.min.js.map diff --git a/docs/static/scopie.browser.min.js.map b/docs/static/scopie.browser.min.js.map deleted file mode 100644 index bc83691..0000000 --- a/docs/static/scopie.browser.min.js.map +++ /dev/null @@ -1,7 +0,0 @@ -{ - "version": 3, - "sources": ["../src/scopie.js"], - "sourcesContent": ["export const arraySeperator = '|';\nexport const blockSeperator = '/';\nexport const wildcard = '*';\nexport const varPrefix = '@';\n\n/**\n * Validate if our actor is allowed to perform the action based on the required scope.\n * @param {string[]} actionScopes - Required actor scopes\n * @param {string[]} actorRules - What scopes our actor has\n * @param {object} vars - User variables that are replacable in scopes\n */\nexport function isAllowed(actionScopes, actorRules, vars) {\n if (actorRules.length === 0) {\n return false;\n }\n\n if (actionScopes.length === 0) {\n throw new Error('scopie-106: action scopes was empty');\n }\n\n let varMap;\n if (vars) {\n varMap = new Map(Object.entries(vars));\n }\n\n let hasBeenAllowed = false;\n\n for (let ruleIndex = 0; ruleIndex < actorRules.length; ruleIndex += 1) {\n const actorRule = actorRules[ruleIndex];\n if (actorRule.length === 0) {\n throw new Error('scopie-106: actor rule was empty');\n }\n\n const isAllowBlock = actorRule[0] === 'a';\n if (isAllowBlock && hasBeenAllowed) {\n continue;\n }\n\n for (let actionIndex = 0; actionIndex < actionScopes.length; actionIndex += 1) {\n const actionScope = actionScopes[actionIndex];\n if (actionScope.length === 0) {\n throw new Error('scopie-106: action scope was empty');\n }\n\n const match = compareActorToAction(actorRule, actionScope, varMap);\n if (match && isAllowBlock) {\n hasBeenAllowed = true;\n } else if (match && !isAllowBlock) {\n return false;\n }\n }\n }\n\n return hasBeenAllowed;\n}\n\n/**\n * Determines whether or not the scope is valid according to scopie rules.\n * @param {string} scope - Scope to check\n * @returns {Error|undefined} If the scope is invalid, the validation error is returned,\n * otherwise undefined is returned.\n */\nexport function validateScope(scope) {\n if (scope === '') {\n return new Error('scopie-106: scope was empty');\n }\n\n let inArray = false;\n\n for (let i = 0; i < scope.length; i += 1) {\n if (scope[i] === blockSeperator) {\n inArray = false;\n continue;\n }\n\n if (scope[i] === arraySeperator) {\n inArray = true;\n continue;\n }\n\n if (inArray) {\n if (scope[i] === wildcard && i < scope.length - 1 && scope[i + 1] === wildcard) {\n return new Error('scopie-103: super wildcard found in array block');\n }\n\n if (scope[i] === wildcard) {\n return new Error('scopie-102: wildcard found in array block');\n }\n\n if (scope[i] === varPrefix) {\n const end = endOfArrayElement(scope, i);\n return new Error(`scopie-101: variable '${scope.substring(i + 1, end)}' found in array block`);\n }\n }\n\n if (!isValidCharacter(scope[i])) {\n return new Error(`scopie-100: invalid character '${scope[i]}'`);\n }\n\n if (scope[i] === wildcard && i < scope.length - 1 && scope[i + 1] === wildcard\n && i < scope.length - 2) {\n return new Error('scopie-105: super wildcard not in the last block');\n }\n }\n\n return undefined;\n}\n\n/** Checks character validity\n * @param {character} char - Single character to check\n * @returns {boolean} whether or not the character is valid within a scope.\n */\nfunction isValidCharacter(char) {\n if (char >= 'a' && char <= 'z') {\n return true;\n }\n\n if (char >= 'A' && char <= 'Z') {\n return true;\n }\n\n if (char >= '0' && char <= '9') {\n return true;\n }\n\n return char === '_' || char === '-' || char === varPrefix || char === wildcard;\n}\n\n/** Calculates the end of an array element\n * @param {string} value - Value of our scope we are traversing\n * @param {number} start - Index to start searching from\n * @returns {number} index at the end of the array element\n */\nfunction endOfArrayElement(value, start) {\n for (let i = start + 1; i < value.length; i += 1) {\n if (value[i] === blockSeperator || value[i] === arraySeperator) {\n return i;\n }\n }\n\n return value.length;\n}\n\n/** Calculates the end of a scope block\n * @param {string} category - Value to use when returning an error for our category\n * @param {string} value - Value of our scope we are traversing\n * @param {number} start - Index to start searching from\n * @returns {number} index at the end of the scope block\n */\nfunction endOfBlock(category, value, start) {\n for (let i = start; i < value.length; i += 1) {\n if (value[i] === blockSeperator) {\n return i;\n } if (value[i] === arraySeperator) {\n continue;\n } else if (!isValidCharacter(value[i])) {\n throw new Error(`scopie-100 in ${category}: invalid character '${value[i]}'`);\n }\n }\n\n return value.length;\n}\n\n/** Compares two strings with respect to variables and wildcards.\n * @param {string} aValue\n * @param {int} aLeft\n * @param {int} aSlider\n * @param {string} bValue\n * @param {int} bLeft\n * @param {int} bSlider\n * @param {Map} vars\n * @returns {boolean} Whether or not our actor matches the action block\n */\nfunction compareBlock(aValue, aLeft, aSlider, bValue, bLeft, bSlider, vars) {\n let actorLeft = aLeft;\n\n if (aValue[actorLeft] === varPrefix) {\n const key = aValue.substring(actorLeft + 1, aSlider);\n if (!vars.has(key)) {\n throw new Error(`scopie-104 in actor: variable '${key}' not found`);\n }\n\n const varValue = vars.get(key);\n return varValue === bValue.substring(bLeft, bSlider);\n }\n\n if (aSlider - actorLeft === 1 && aValue[actorLeft] === wildcard) {\n return true;\n }\n\n if (aValue.substring(actorLeft, aSlider).indexOf(arraySeperator) >= 0) {\n for (;actorLeft < aSlider;) {\n const arrayRight = endOfArrayElement(aValue, actorLeft);\n\n if (aValue[actorLeft] === varPrefix) {\n throw new Error(`scopie-101 in actor: variable '${aValue.substring(actorLeft + 1, arrayRight)}' found in array block`);\n }\n\n if (aValue[actorLeft] === wildcard) {\n if (arrayRight - actorLeft > 1 && aValue[actorLeft + 1] === wildcard) {\n throw new Error('scopie-103 in actor: super wildcard found in array block');\n }\n\n throw new Error('scopie-102 in actor: wildcard found in array block');\n }\n\n if (aValue.substring(actorLeft, arrayRight) === bValue.substring(bLeft, bSlider)) {\n return true;\n }\n\n actorLeft = arrayRight + 1;\n }\n\n return false;\n }\n\n return aValue.substring(aLeft, aSlider) === bValue.substring(bLeft, bSlider);\n}\n\n/** Determines if an actor matches an action\n * @param {string} actor - Actor scope\n * @param {string} action - Action rule\n * @param {Map} vars - Variables for translations\n * @returns {boolean} Whether or not the actor matches the rule\n */\nfunction compareActorToAction(actor, action, vars) {\n // Skip the allow and deny prefix for actors\n let actorLeft = endOfBlock('actor', actor, 0) + 1;\n let actionLeft = 0;\n let actionSlider = 0;\n let actorSlider = 0;\n\n for (; actorLeft < actor.length || actionLeft < action.length;) {\n // In case one is longer then the other\n if ((actorLeft < actor.length) !== (actionLeft < action.length)) {\n return false;\n }\n\n actionSlider = endOfBlock('action', action, actionLeft);\n actorSlider = endOfBlock('actor', actor, actorLeft);\n\n // Super wildcards are checked here as it skips the who rest of the checks.\n if (\n actorSlider - actorLeft === 2\n && actor[actorLeft] === wildcard\n && actor[actorLeft + 1] === wildcard\n ) {\n if (actor.length > actorSlider) {\n throw new Error('scopie-105 in actor: super wildcard not in the last block');\n }\n\n return true;\n }\n if (!compareBlock(\n actor,\n actorLeft,\n actorSlider,\n action,\n actionLeft,\n actionSlider,\n vars,\n )) {\n return false;\n }\n\n actionLeft = actionSlider + 1;\n actorLeft = actorSlider + 1;\n }\n\n return true;\n}\n\n"], - "mappings": "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", - "names": ["actionScopes", "actorRules", "vars", "varMap", "hasBeenAllowed", "ruleIndex", "actorRule", "isAllowBlock", "actionIndex", "actionScope", "match", "compareActorToAction", "scope", "inArray", "i", "end", "endOfArrayElement", "isValidCharacter", "char", "value", "start", "endOfBlock", "category", "compareBlock", "aValue", "aLeft", "aSlider", "bValue", "bLeft", "bSlider", "actorLeft", "key", "arrayRight", "actor", "action", "actionLeft", "actionSlider", "actorSlider"] -} diff --git a/docs/static/scopie.browser.min.v0.3.0.js b/docs/static/scopie.browser.min.v0.3.0.js new file mode 100644 index 0000000..506d296 --- /dev/null +++ b/docs/static/scopie.browser.min.v0.3.0.js @@ -0,0 +1,2 @@ +export const arraySeperator="|",blockSeperator="/",wildcard="*",varPrefix="@",allowPermission="allow",denyPermission="deny";function w(r){return r>="a"&&r<="z"||r>="A"&&r<="Z"||r>="0"&&r<="9"?!0:r==="_"||r==="-"||r===varPrefix||r===wildcard}function a(r,o){for(let e=o+1;e=0){for(;i1&&r[i+1]===wildcard?new Error("scopie-103: super wildcard found in array block"):new Error("scopie-102: wildcard found in array block");if(r.substring(i,c)===n.substring(s,t))return!0;i=c+1}return!1}return r.substring(o,e)===n.substring(s,t)}function h(r,o,e){let n=u("actor",r,0)+1,s=0,t=0,f=0;for(;nf)throw new Error("scopie-105: super wildcard not in the last block");return!0}if(!d(r,n,f,o,s,t,e))return!1;s=t+1,n=f+1}return!0}export function isAllowed(r,o,e){if(o.length===0)return!1;if(r.length===0)throw new Error("scopie-106 in action: scopes was empty");let n;e&&(n=new Map(Object.entries(e)));let s=!1;for(let t=0;t= 'a' && char <= 'z') {\n return true;\n }\n\n if (char >= 'A' && char <= 'Z') {\n return true;\n }\n\n if (char >= '0' && char <= '9') {\n return true;\n }\n\n return char === '_' || char === '-' || char === varPrefix || char === wildcard;\n}\n\n/** Calculates the end of an array element\n * @param {string} value - Value of our scope we are traversing\n * @param {number} start - Index to start searching from\n * @returns {number} index at the end of the array element\n */\nfunction endOfArrayElement(value, start) {\n for (let i = start + 1; i < value.length; i += 1) {\n if (value[i] === blockSeperator || value[i] === arraySeperator) {\n return i;\n }\n }\n\n return value.length;\n}\n\n/** Calculates the end of a scope block\n * @param {string} category - Value to use when returning an error for our category\n * @param {string} value - Value of our scope we are traversing\n * @param {number} start - Index to start searching from\n * @returns {number} index at the end of the scope block\n */\nfunction endOfBlock(category, value, start) {\n for (let i = start; i < value.length; i += 1) {\n if (value[i] === blockSeperator) {\n return i;\n } if (value[i] === arraySeperator) {\n continue;\n } else if (!isValidCharacter(value[i])) {\n throw new Error(`scopie-100 in ${category}: invalid character '${value[i]}'`);\n }\n }\n\n return value.length;\n}\n\n/** Compares two strings with respect to variables and wildcards.\n * @param {string} aValue\n * @param {int} aLeft\n * @param {int} aSlider\n * @param {string} bValue\n * @param {int} bLeft\n * @param {int} bSlider\n * @param {Map} vars\n * @returns {boolean} Whether or not our actor matches the action block\n */\nfunction compareBlock(aValue, aLeft, aSlider, bValue, bLeft, bSlider, vars) {\n let actorLeft = aLeft;\n\n if (aValue[actorLeft] === varPrefix) {\n const key = aValue.substring(actorLeft + 1, aSlider);\n if (!vars.has(key)) {\n throw new Error(`scopie-104: variable '${key}' not found`);\n }\n\n const varValue = vars.get(key);\n return varValue === bValue.substring(bLeft, bSlider);\n }\n\n if (aSlider - actorLeft === 1 && aValue[actorLeft] === wildcard) {\n return true;\n }\n\n if (aValue.substring(actorLeft, aSlider).indexOf(arraySeperator) >= 0) {\n for (; actorLeft < aSlider;) {\n const arrayRight = endOfArrayElement(aValue, actorLeft);\n\n if (aValue[actorLeft] === varPrefix) {\n throw new Error(`scopie-101: variable '${aValue.substring(actorLeft + 1, arrayRight)}' found in array block`);\n }\n\n if (aValue[actorLeft] === wildcard) {\n if (arrayRight - actorLeft > 1 && aValue[actorLeft + 1] === wildcard) {\n throw new Error('scopie-103: super wildcard found in array block');\n }\n\n throw new Error('scopie-102: wildcard found in array block');\n }\n\n if (aValue.substring(actorLeft, arrayRight) === bValue.substring(bLeft, bSlider)) {\n return true;\n }\n\n actorLeft = arrayRight + 1;\n }\n\n return false;\n }\n\n return aValue.substring(aLeft, aSlider) === bValue.substring(bLeft, bSlider);\n}\n\n/** Determines if an actor matches an action\n * @param {string} actor - Actor scope\n * @param {string} action - Action rule\n * @param {Map} vars - Variables for translations\n * @returns {boolean} Whether or not the actor matches the rule\n */\nfunction compareActorToAction(actor, action, vars) {\n // Skip the allow and deny prefix for actors\n let actorLeft = endOfBlock('actor', actor, 0) + 1;\n let actionLeft = 0;\n let actionSlider = 0;\n let actorSlider = 0;\n\n for (; actorLeft < actor.length || actionLeft < action.length;) {\n // In case one is longer then the other\n if ((actorLeft < actor.length) !== (actionLeft < action.length)) {\n return false;\n }\n\n actionSlider = endOfBlock('action', action, actionLeft);\n actorSlider = endOfBlock('actor', actor, actorLeft);\n\n // Super wildcards are checked here as it skips the who rest of the checks.\n if (\n actorSlider - actorLeft === 2\n && actor[actorLeft] === wildcard\n && actor[actorLeft + 1] === wildcard\n ) {\n if (actor.length > actorSlider) {\n throw new Error('scopie-105: super wildcard not in the last block');\n }\n\n return true;\n }\n if (!compareBlock(\n actor,\n actorLeft,\n actorSlider,\n action,\n actionLeft,\n actionSlider,\n vars,\n )) {\n return false;\n }\n\n actionLeft = actionSlider + 1;\n actorLeft = actorSlider + 1;\n }\n\n return true;\n}\n\n/**\n * Validate if our actor is allowed to perform the action based on the required scope.\n * @param {string[]} actionScopes - Required actor scopes\n * @param {string[]} actorRules - What scopes our actor has\n * @param {object} vars - User variables that are replacable in scopes\n */\nexport function isAllowed(actionScopes, actorRules, vars) {\n if (actorRules.length === 0) {\n return false;\n }\n\n if (actionScopes.length === 0) {\n throw new Error('scopie-106 in action: scopes was empty');\n }\n\n let varMap;\n if (vars) {\n varMap = new Map(Object.entries(vars));\n }\n\n let hasBeenAllowed = false;\n\n for (let ruleIndex = 0; ruleIndex < actorRules.length; ruleIndex += 1) {\n const actorRule = actorRules[ruleIndex];\n if (actorRule.length === 0) {\n throw new Error('scopie-106 in actor: rule was empty');\n }\n\n const isAllowBlock = actorRule[0] === 'a';\n if (isAllowBlock && hasBeenAllowed) {\n continue;\n }\n\n for (let actionIndex = 0; actionIndex < actionScopes.length; actionIndex += 1) {\n const actionScope = actionScopes[actionIndex];\n if (actionScope.length === 0) {\n throw new Error('scopie-106 in action: scope was empty');\n }\n\n const match = compareActorToAction(actorRule, actionScope, varMap);\n if (match && isAllowBlock) {\n hasBeenAllowed = true;\n } else if (match && !isAllowBlock) {\n return false;\n }\n }\n }\n\n return hasBeenAllowed;\n}\n\n/**\n * Determines whether or not the scopes or rules are valid according to scopie rules.\n * @param {string[]} scopeOrRules - Scope or rules to check\n * @returns {Error|undefined} If the scope is invalid, the validation error is returned,\n * otherwise undefined is returned.\n */\nexport function validateScopes(scopeOrRules) {\n if (scopeOrRules.length === 0) {\n return new Error('scopie-106: scopes are empty');\n }\n\n const isRules = scopeOrRules[0].startsWith(allowPermission) ||\n scopeOrRules[0].startsWith(denyPermission)\n\n for (let scope of scopeOrRules) {\n if (scope.length === 0) {\n return new Error('scopie-106: scope or rule was empty');\n }\n\n const isScopeRules = scope.startsWith(allowPermission) ||\n scope.startsWith(denyPermission)\n if (isRules != isScopeRules) {\n return new Error('scopie-107: inconsistent array of scopes and rules');\n }\n\n let inArray = false;\n\n for (let i = 0; i < scope.length; i += 1) {\n if (scope[i] === blockSeperator) {\n inArray = false;\n continue;\n }\n\n if (scope[i] === arraySeperator) {\n inArray = true;\n continue;\n }\n\n if (inArray) {\n if (scope[i] === wildcard && i < scope.length - 1 && scope[i + 1] === wildcard) {\n return new Error('scopie-103: super wildcard found in array block');\n }\n\n if (scope[i] === wildcard) {\n return new Error('scopie-102: wildcard found in array block');\n }\n\n if (scope[i] === varPrefix) {\n const end = endOfArrayElement(scope, i);\n return new Error(`scopie-101: variable '${scope.substring(i + 1, end)}' found in array block`);\n }\n }\n\n if (!isValidCharacter(scope[i])) {\n return new Error(`scopie-100: invalid character '${scope[i]}'`);\n }\n\n if (scope[i] === wildcard && i < scope.length - 1 && scope[i + 1] === wildcard\n && i < scope.length - 2) {\n return new Error('scopie-105: super wildcard not in the last block');\n }\n }\n }\n\n return undefined;\n}\n"], + "mappings": "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", + "names": ["isValidCharacter", "char", "endOfArrayElement", "value", "start", "i", "endOfBlock", "category", "compareBlock", "aValue", "aLeft", "aSlider", "bValue", "bLeft", "bSlider", "vars", "actorLeft", "key", "arrayRight", "compareActorToAction", "actor", "action", "actionLeft", "actionSlider", "actorSlider", "actionScopes", "actorRules", "varMap", "hasBeenAllowed", "ruleIndex", "actorRule", "isAllowBlock", "actionIndex", "actionScope", "match", "scopeOrRules", "isRules", "scope", "isScopeRules", "inArray", "end"] +}