open-nomad/ui/app/abilities/variable.js

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

185 lines
5.1 KiB
JavaScript
Raw Normal View History

import { computed, get } from '@ember/object';
import { or } from '@ember/object/computed';
ui: create variable permission logic (#13447) * ui: inject router service into Variable ability to compute path * ui: test create secure variable ability * refact: update templates to properly check create ability * chore: update token factory to enable 1 path to have create ability * refact: remove router service injection for path variable * refact: update mirage factory for edit and delete perms on path for testing * ui: handle path matching (#13474) * test: write specifications for nearestPath computation * ui: write logic for getting all paths * ui: nearestPathMatching algorithm * test: nearestPathMatching algorithm test * ui: handle namespace filtering for capabilities check (#13475) * ui: add namespace handling * refact: add logical OR operator to handle unstructured object. * ui: acceptance test for create flow in secure variables (#13500) * test: write happy path test for creating variable * refact: add missing data-test attributes * test: sad path for disabled button * fix: move comment in file * test: acceptance test for editing a variable (#13529) * refact: add data-test variable * test: happy path and sad path for edit flow * refact: update test language to say disabled * ui: glob matching algorithm (#13533) * ui: compute length difference (#13542) * ui: compute length difference * refact: use glob matching and sorting algos in `nearestMatchingPath` (#13544) * refact: use const in compute * ui: smallest difference logic * refact: use glob matching and sorting algo in _nearestPathPath helper * ui: add can edit to variable capabilities (#13545) * ui: create edit capabilities getter * ui: add ember-can check for edit button * refact: update test to mock edit capabilities in policy * fix: remove unused var * Edit capabilities for variables depend on Create Co-authored-by: Phil Renaud <phil@riotindustries.com> Co-authored-by: Phil Renaud <phil@riotindustries.com> Co-authored-by: Phil Renaud <phil@riotindustries.com> * refact: update token factory (#13596) * refact: update rulesJSON in token factory to reflect schema update * refact: update capability names (#13597) * refact: update rules to match rulesJSON * refact: update create to write * ui: add `canDestroy` permissions (#13598) * refact: update rulesJSON in token factory to reflect schema update * refact: update rules to match rulesJSON * refact: update create to write * ui: add canDestroy capability * test: unit test for canDestroy * ui: add permission check to template * test: acceptance test for delete flow * refact: update test to use correct capability name * refact: update tests to reflect rulesJSON schema change * ui: update path matching logic to account for schema change (#13605) * refact: update path matching logic * refact: update tests to reflect rulesJSON change Co-authored-by: Phil Renaud <phil@riotindustries.com> Co-authored-by: Phil Renaud <phil@riotindustries.com>
2022-07-06 14:48:22 +00:00
import AbstractAbility from './abstract';
const WILDCARD_GLOB = '*';
const WILDCARD_PATTERN = '/';
const GLOBAL_FLAG = 'g';
const WILDCARD_PATTERN_REGEX = new RegExp(WILDCARD_PATTERN, GLOBAL_FLAG);
export default class Variable extends AbstractAbility {
// Pass in a namespace to `can` or `cannot` calls to override
// https://github.com/minutebase/ember-can#additional-attributes
path = '*';
get _path() {
if (!this.path) return '*';
return this.path;
}
@or(
'bypassAuthorization',
'selfTokenIsManagement',
'policiesSupportVariableView'
)
canList;
@or(
'bypassAuthorization',
'selfTokenIsManagement',
ui: create variable permission logic (#13447) * ui: inject router service into Variable ability to compute path * ui: test create secure variable ability * refact: update templates to properly check create ability * chore: update token factory to enable 1 path to have create ability * refact: remove router service injection for path variable * refact: update mirage factory for edit and delete perms on path for testing * ui: handle path matching (#13474) * test: write specifications for nearestPath computation * ui: write logic for getting all paths * ui: nearestPathMatching algorithm * test: nearestPathMatching algorithm test * ui: handle namespace filtering for capabilities check (#13475) * ui: add namespace handling * refact: add logical OR operator to handle unstructured object. * ui: acceptance test for create flow in secure variables (#13500) * test: write happy path test for creating variable * refact: add missing data-test attributes * test: sad path for disabled button * fix: move comment in file * test: acceptance test for editing a variable (#13529) * refact: add data-test variable * test: happy path and sad path for edit flow * refact: update test language to say disabled * ui: glob matching algorithm (#13533) * ui: compute length difference (#13542) * ui: compute length difference * refact: use glob matching and sorting algos in `nearestMatchingPath` (#13544) * refact: use const in compute * ui: smallest difference logic * refact: use glob matching and sorting algo in _nearestPathPath helper * ui: add can edit to variable capabilities (#13545) * ui: create edit capabilities getter * ui: add ember-can check for edit button * refact: update test to mock edit capabilities in policy * fix: remove unused var * Edit capabilities for variables depend on Create Co-authored-by: Phil Renaud <phil@riotindustries.com> Co-authored-by: Phil Renaud <phil@riotindustries.com> Co-authored-by: Phil Renaud <phil@riotindustries.com> * refact: update token factory (#13596) * refact: update rulesJSON in token factory to reflect schema update * refact: update capability names (#13597) * refact: update rules to match rulesJSON * refact: update create to write * ui: add `canDestroy` permissions (#13598) * refact: update rulesJSON in token factory to reflect schema update * refact: update rules to match rulesJSON * refact: update create to write * ui: add canDestroy capability * test: unit test for canDestroy * ui: add permission check to template * test: acceptance test for delete flow * refact: update test to use correct capability name * refact: update tests to reflect rulesJSON schema change * ui: update path matching logic to account for schema change (#13605) * refact: update path matching logic * refact: update tests to reflect rulesJSON change Co-authored-by: Phil Renaud <phil@riotindustries.com> Co-authored-by: Phil Renaud <phil@riotindustries.com>
2022-07-06 14:48:22 +00:00
'policiesSupportVariableWriting'
)
ui: create variable permission logic (#13447) * ui: inject router service into Variable ability to compute path * ui: test create secure variable ability * refact: update templates to properly check create ability * chore: update token factory to enable 1 path to have create ability * refact: remove router service injection for path variable * refact: update mirage factory for edit and delete perms on path for testing * ui: handle path matching (#13474) * test: write specifications for nearestPath computation * ui: write logic for getting all paths * ui: nearestPathMatching algorithm * test: nearestPathMatching algorithm test * ui: handle namespace filtering for capabilities check (#13475) * ui: add namespace handling * refact: add logical OR operator to handle unstructured object. * ui: acceptance test for create flow in secure variables (#13500) * test: write happy path test for creating variable * refact: add missing data-test attributes * test: sad path for disabled button * fix: move comment in file * test: acceptance test for editing a variable (#13529) * refact: add data-test variable * test: happy path and sad path for edit flow * refact: update test language to say disabled * ui: glob matching algorithm (#13533) * ui: compute length difference (#13542) * ui: compute length difference * refact: use glob matching and sorting algos in `nearestMatchingPath` (#13544) * refact: use const in compute * ui: smallest difference logic * refact: use glob matching and sorting algo in _nearestPathPath helper * ui: add can edit to variable capabilities (#13545) * ui: create edit capabilities getter * ui: add ember-can check for edit button * refact: update test to mock edit capabilities in policy * fix: remove unused var * Edit capabilities for variables depend on Create Co-authored-by: Phil Renaud <phil@riotindustries.com> Co-authored-by: Phil Renaud <phil@riotindustries.com> Co-authored-by: Phil Renaud <phil@riotindustries.com> * refact: update token factory (#13596) * refact: update rulesJSON in token factory to reflect schema update * refact: update capability names (#13597) * refact: update rules to match rulesJSON * refact: update create to write * ui: add `canDestroy` permissions (#13598) * refact: update rulesJSON in token factory to reflect schema update * refact: update rules to match rulesJSON * refact: update create to write * ui: add canDestroy capability * test: unit test for canDestroy * ui: add permission check to template * test: acceptance test for delete flow * refact: update test to use correct capability name * refact: update tests to reflect rulesJSON schema change * ui: update path matching logic to account for schema change (#13605) * refact: update path matching logic * refact: update tests to reflect rulesJSON change Co-authored-by: Phil Renaud <phil@riotindustries.com> Co-authored-by: Phil Renaud <phil@riotindustries.com>
2022-07-06 14:48:22 +00:00
canWrite;
@or(
'bypassAuthorization',
'selfTokenIsManagement',
'policiesSupportVariableDestroy'
)
canDestroy;
@computed('rulesForNamespace.@each.capabilities')
get policiesSupportVariableView() {
return this.rulesForNamespace.some((rules) => {
return get(rules, 'SecureVariables');
});
}
ui: create variable permission logic (#13447) * ui: inject router service into Variable ability to compute path * ui: test create secure variable ability * refact: update templates to properly check create ability * chore: update token factory to enable 1 path to have create ability * refact: remove router service injection for path variable * refact: update mirage factory for edit and delete perms on path for testing * ui: handle path matching (#13474) * test: write specifications for nearestPath computation * ui: write logic for getting all paths * ui: nearestPathMatching algorithm * test: nearestPathMatching algorithm test * ui: handle namespace filtering for capabilities check (#13475) * ui: add namespace handling * refact: add logical OR operator to handle unstructured object. * ui: acceptance test for create flow in secure variables (#13500) * test: write happy path test for creating variable * refact: add missing data-test attributes * test: sad path for disabled button * fix: move comment in file * test: acceptance test for editing a variable (#13529) * refact: add data-test variable * test: happy path and sad path for edit flow * refact: update test language to say disabled * ui: glob matching algorithm (#13533) * ui: compute length difference (#13542) * ui: compute length difference * refact: use glob matching and sorting algos in `nearestMatchingPath` (#13544) * refact: use const in compute * ui: smallest difference logic * refact: use glob matching and sorting algo in _nearestPathPath helper * ui: add can edit to variable capabilities (#13545) * ui: create edit capabilities getter * ui: add ember-can check for edit button * refact: update test to mock edit capabilities in policy * fix: remove unused var * Edit capabilities for variables depend on Create Co-authored-by: Phil Renaud <phil@riotindustries.com> Co-authored-by: Phil Renaud <phil@riotindustries.com> Co-authored-by: Phil Renaud <phil@riotindustries.com> * refact: update token factory (#13596) * refact: update rulesJSON in token factory to reflect schema update * refact: update capability names (#13597) * refact: update rules to match rulesJSON * refact: update create to write * ui: add `canDestroy` permissions (#13598) * refact: update rulesJSON in token factory to reflect schema update * refact: update rules to match rulesJSON * refact: update create to write * ui: add canDestroy capability * test: unit test for canDestroy * ui: add permission check to template * test: acceptance test for delete flow * refact: update test to use correct capability name * refact: update tests to reflect rulesJSON schema change * ui: update path matching logic to account for schema change (#13605) * refact: update path matching logic * refact: update tests to reflect rulesJSON change Co-authored-by: Phil Renaud <phil@riotindustries.com> Co-authored-by: Phil Renaud <phil@riotindustries.com>
2022-07-06 14:48:22 +00:00
@computed('path', 'allPaths')
get policiesSupportVariableWriting() {
const matchingPath = this._nearestMatchingPath(this.path);
return this.allPaths
.find((path) => path.name === matchingPath)
?.capabilities?.includes('write');
}
@computed('path', 'allPaths')
get policiesSupportVariableDestroy() {
const matchingPath = this._nearestMatchingPath(this.path);
return this.allPaths
.find((path) => path.name === matchingPath)
?.capabilities?.includes('destroy');
}
@computed('token.selfTokenPolicies.[]', 'namespace')
ui: create variable permission logic (#13447) * ui: inject router service into Variable ability to compute path * ui: test create secure variable ability * refact: update templates to properly check create ability * chore: update token factory to enable 1 path to have create ability * refact: remove router service injection for path variable * refact: update mirage factory for edit and delete perms on path for testing * ui: handle path matching (#13474) * test: write specifications for nearestPath computation * ui: write logic for getting all paths * ui: nearestPathMatching algorithm * test: nearestPathMatching algorithm test * ui: handle namespace filtering for capabilities check (#13475) * ui: add namespace handling * refact: add logical OR operator to handle unstructured object. * ui: acceptance test for create flow in secure variables (#13500) * test: write happy path test for creating variable * refact: add missing data-test attributes * test: sad path for disabled button * fix: move comment in file * test: acceptance test for editing a variable (#13529) * refact: add data-test variable * test: happy path and sad path for edit flow * refact: update test language to say disabled * ui: glob matching algorithm (#13533) * ui: compute length difference (#13542) * ui: compute length difference * refact: use glob matching and sorting algos in `nearestMatchingPath` (#13544) * refact: use const in compute * ui: smallest difference logic * refact: use glob matching and sorting algo in _nearestPathPath helper * ui: add can edit to variable capabilities (#13545) * ui: create edit capabilities getter * ui: add ember-can check for edit button * refact: update test to mock edit capabilities in policy * fix: remove unused var * Edit capabilities for variables depend on Create Co-authored-by: Phil Renaud <phil@riotindustries.com> Co-authored-by: Phil Renaud <phil@riotindustries.com> Co-authored-by: Phil Renaud <phil@riotindustries.com> * refact: update token factory (#13596) * refact: update rulesJSON in token factory to reflect schema update * refact: update capability names (#13597) * refact: update rules to match rulesJSON * refact: update create to write * ui: add `canDestroy` permissions (#13598) * refact: update rulesJSON in token factory to reflect schema update * refact: update rules to match rulesJSON * refact: update create to write * ui: add canDestroy capability * test: unit test for canDestroy * ui: add permission check to template * test: acceptance test for delete flow * refact: update test to use correct capability name * refact: update tests to reflect rulesJSON schema change * ui: update path matching logic to account for schema change (#13605) * refact: update path matching logic * refact: update tests to reflect rulesJSON change Co-authored-by: Phil Renaud <phil@riotindustries.com> Co-authored-by: Phil Renaud <phil@riotindustries.com>
2022-07-06 14:48:22 +00:00
get allPaths() {
return (get(this, 'token.selfTokenPolicies') || [])
.toArray()
.reduce((paths, policy) => {
const matchingNamespace = this.namespace ?? 'default';
ui: create variable permission logic (#13447) * ui: inject router service into Variable ability to compute path * ui: test create secure variable ability * refact: update templates to properly check create ability * chore: update token factory to enable 1 path to have create ability * refact: remove router service injection for path variable * refact: update mirage factory for edit and delete perms on path for testing * ui: handle path matching (#13474) * test: write specifications for nearestPath computation * ui: write logic for getting all paths * ui: nearestPathMatching algorithm * test: nearestPathMatching algorithm test * ui: handle namespace filtering for capabilities check (#13475) * ui: add namespace handling * refact: add logical OR operator to handle unstructured object. * ui: acceptance test for create flow in secure variables (#13500) * test: write happy path test for creating variable * refact: add missing data-test attributes * test: sad path for disabled button * fix: move comment in file * test: acceptance test for editing a variable (#13529) * refact: add data-test variable * test: happy path and sad path for edit flow * refact: update test language to say disabled * ui: glob matching algorithm (#13533) * ui: compute length difference (#13542) * ui: compute length difference * refact: use glob matching and sorting algos in `nearestMatchingPath` (#13544) * refact: use const in compute * ui: smallest difference logic * refact: use glob matching and sorting algo in _nearestPathPath helper * ui: add can edit to variable capabilities (#13545) * ui: create edit capabilities getter * ui: add ember-can check for edit button * refact: update test to mock edit capabilities in policy * fix: remove unused var * Edit capabilities for variables depend on Create Co-authored-by: Phil Renaud <phil@riotindustries.com> Co-authored-by: Phil Renaud <phil@riotindustries.com> Co-authored-by: Phil Renaud <phil@riotindustries.com> * refact: update token factory (#13596) * refact: update rulesJSON in token factory to reflect schema update * refact: update capability names (#13597) * refact: update rules to match rulesJSON * refact: update create to write * ui: add `canDestroy` permissions (#13598) * refact: update rulesJSON in token factory to reflect schema update * refact: update rules to match rulesJSON * refact: update create to write * ui: add canDestroy capability * test: unit test for canDestroy * ui: add permission check to template * test: acceptance test for delete flow * refact: update test to use correct capability name * refact: update tests to reflect rulesJSON schema change * ui: update path matching logic to account for schema change (#13605) * refact: update path matching logic * refact: update tests to reflect rulesJSON change Co-authored-by: Phil Renaud <phil@riotindustries.com> Co-authored-by: Phil Renaud <phil@riotindustries.com>
2022-07-06 14:48:22 +00:00
const variables = (get(policy, 'rulesJSON.Namespaces') || []).find(
(namespace) => namespace.Name === matchingNamespace
)?.SecureVariables;
const pathNames = variables?.Paths?.map((path) => ({
name: path.PathSpec,
capabilities: path.Capabilities,
}));
if (pathNames) {
paths = [...paths, ...pathNames];
}
return paths;
}, []);
}
_formatMatchingPathRegEx(path, wildCardPlacement = 'end') {
const replacer = () => '\\/';
if (wildCardPlacement === 'end') {
const trimmedPath = path.slice(0, path.length - 1);
const pattern = trimmedPath.replace(WILDCARD_PATTERN_REGEX, replacer);
return pattern;
} else {
const trimmedPath = path.slice(1, path.length);
const pattern = trimmedPath.replace(WILDCARD_PATTERN_REGEX, replacer);
return pattern;
}
}
_computeAllMatchingPaths(pathNames, path) {
const matches = [];
for (const pathName of pathNames) {
if (this._doesMatchPattern(pathName, path)) matches.push(pathName);
}
return matches;
}
_nearestMatchingPath(path) {
const pathNames = this.allPaths.map((path) => path.name);
if (pathNames.includes(path)) {
return path;
}
const allMatchingPaths = this._computeAllMatchingPaths(pathNames, path);
if (!allMatchingPaths.length) return WILDCARD_GLOB;
return this._smallestDifference(allMatchingPaths, path);
}
_doesMatchPattern(pattern, path) {
const parts = pattern?.split(WILDCARD_GLOB);
const hasLeadingGlob = pattern?.startsWith(WILDCARD_GLOB);
const hasTrailingGlob = pattern?.endsWith(WILDCARD_GLOB);
const lastPartOfPattern = parts[parts.length - 1];
const isPatternWithoutGlob = parts.length === 1 && !hasLeadingGlob;
if (!pattern || !path || isPatternWithoutGlob) {
return pattern === path;
}
if (pattern === WILDCARD_GLOB) {
return true;
}
let subPathToMatchOn = path;
for (let i = 0; i < parts.length; i++) {
const part = parts[i];
const idx = subPathToMatchOn?.indexOf(part);
const doesPathIncludeSubPattern = idx > -1;
const doesMatchOnFirstSubpattern = idx === 0;
if (i === 0 && !hasLeadingGlob && !doesMatchOnFirstSubpattern) {
return false;
}
if (!doesPathIncludeSubPattern) {
return false;
}
subPathToMatchOn = subPathToMatchOn.slice(0, idx + path.length);
}
return hasTrailingGlob || path.endsWith(lastPartOfPattern);
}
_computeLengthDiff(pattern, path) {
const countGlobsInPattern = pattern
?.split('')
.filter((el) => el === WILDCARD_GLOB).length;
return path?.length - pattern?.length + countGlobsInPattern;
}
_smallestDifference(matches, path) {
const sortingCallBack = (patternA, patternB) =>
this._computeLengthDiff(patternA, path) -
this._computeLengthDiff(patternB, path);
const sortedMatches = matches?.sort(sortingCallBack);
const isTie =
this._computeLengthDiff(sortedMatches[0], path) ===
this._computeLengthDiff(sortedMatches[1], path);
const doesFirstMatchHaveLeadingGlob = sortedMatches[0][0] === WILDCARD_GLOB;
return isTie && doesFirstMatchHaveLeadingGlob
? sortedMatches[1]
: sortedMatches[0];
}
}