github.com/thomasobenaus/nomad@v0.11.1/ui/app/abilities/job.js (about) 1 import { Ability } from 'ember-can'; 2 import { inject as service } from '@ember/service'; 3 import { computed, get } from '@ember/object'; 4 import { equal, or, not } from '@ember/object/computed'; 5 6 export default Ability.extend({ 7 system: service(), 8 token: service(), 9 10 canRun: or('bypassAuthorization', 'selfTokenIsManagement', 'policiesSupportRunning'), 11 12 bypassAuthorization: not('token.aclEnabled'), 13 selfTokenIsManagement: equal('token.selfToken.type', 'management'), 14 15 activeNamespace: computed('system.activeNamespace.name', function() { 16 return this.get('system.activeNamespace.name') || 'default'; 17 }), 18 19 rulesForActiveNamespace: computed('activeNamespace', 'token.selfTokenPolicies.[]', function() { 20 let activeNamespace = this.activeNamespace; 21 22 return (this.get('token.selfTokenPolicies') || []).toArray().reduce((rules, policy) => { 23 let policyNamespaces = get(policy, 'rulesJSON.Namespaces') || []; 24 25 let matchingNamespace = this._findMatchingNamespace(policyNamespaces, activeNamespace); 26 27 if (matchingNamespace) { 28 rules.push(policyNamespaces.find(namespace => namespace.Name === matchingNamespace)); 29 } 30 31 return rules; 32 }, []); 33 }), 34 35 policiesSupportRunning: computed('rulesForActiveNamespace.@each.capabilities', function() { 36 return this.rulesForActiveNamespace.some(rules => { 37 let capabilities = get(rules, 'Capabilities') || []; 38 return capabilities.includes('submit-job'); 39 }); 40 }), 41 42 // Chooses the closest namespace as described at the bottom here: 43 // https://www.nomadproject.io/guides/security/acl.html#namespace-rules 44 _findMatchingNamespace(policyNamespaces, activeNamespace) { 45 let namespaceNames = policyNamespaces.mapBy('Name'); 46 47 if (namespaceNames.includes(activeNamespace)) { 48 return activeNamespace; 49 } 50 51 let globNamespaceNames = namespaceNames.filter(namespaceName => namespaceName.includes('*')); 52 53 let matchingNamespaceName = globNamespaceNames.reduce( 54 (mostMatching, namespaceName) => { 55 // Convert * wildcards to .* for regex matching 56 let namespaceNameRegExp = new RegExp(namespaceName.replace(/\*/g, '.*')); 57 let characterDifference = activeNamespace.length - namespaceName.length; 58 59 if ( 60 characterDifference < mostMatching.mostMatchingCharacterDifference && 61 activeNamespace.match(namespaceNameRegExp) 62 ) { 63 return { 64 mostMatchingNamespaceName: namespaceName, 65 mostMatchingCharacterDifference: characterDifference, 66 }; 67 } else { 68 return mostMatching; 69 } 70 }, 71 { mostMatchingNamespaceName: null, mostMatchingCharacterDifference: Number.MAX_SAFE_INTEGER } 72 ).mostMatchingNamespaceName; 73 74 if (matchingNamespaceName) { 75 return matchingNamespaceName; 76 } else if (namespaceNames.includes('default')) { 77 return 'default'; 78 } 79 }, 80 });