Skip to content

Commit

Permalink
feat(ability): adds validation of 3rd parameter to Ability.can
Browse files Browse the repository at this point in the history
Also adds warning if ability contains only inverted rules

Fixes #192
  • Loading branch information
stalniy committed Jul 1, 2019
1 parent 436392d commit 9df032c
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 0 deletions.
15 changes: 15 additions & 0 deletions packages/casl-ability/spec/ability.spec.js
Expand Up @@ -230,6 +230,15 @@ describe('Ability', () => {
expect(secondSubscription).to.have.been.called()
})

it('warns if ability contains only inverted rules', () => {
spy.on(console, 'warn')
ability.update([{ inverted: true, action: 'read', subject: 'Post' }])

expect(console.warn).to.have.been.called()

spy.restore(console, 'warn')
})

function setupListenerChangesInListener() {
const unsubscribe = spy(ability.on('update', function listen() {
unsubscribe()
Expand Down Expand Up @@ -463,6 +472,12 @@ describe('Ability', () => {
expect(ability).to.allow('read', 'Post', 'description')
})

it('throws exception if 3rd argument is not a string', () => {
ability = AbilityBuilder.define(can => can('read', 'Post', 'title'))

expect(() => ability.can('read', 'Post', { title: 'test'})).to.throw(/expects 3rd parameter to be a string/)
})

describe('when `conditions` defined', () => {
const myPost = new Post({ author: 'me' })

Expand Down
13 changes: 13 additions & 0 deletions packages/casl-ability/src/ability.js
Expand Up @@ -55,13 +55,16 @@ export class Ability {
buildIndexFor(rules) {
const indexedRules = Object.create(null);
const { RuleType } = this[PRIVATE_FIELD];
let isAllInverted = true;

for (let i = 0; i < rules.length; i++) {
const rule = new RuleType(rules[i]);
const actions = this.expandActions(rule.actions);
const subjects = wrapArray(rule.subject);
const priority = rules.length - i - 1;

isAllInverted = !!(isAllInverted && rule.inverted);

for (let k = 0; k < subjects.length; k++) {
const subject = subjects[k];
indexedRules[subject] = indexedRules[subject] || Object.create(null);
Expand All @@ -74,6 +77,11 @@ export class Ability {
}
}

if (process.env.NODE_ENV !== 'production' && isAllInverted && rules.length) {
// eslint-disable-next-line
console.warn('[casl]: Ability contains only inverted rules. That means user will not be able to do any actions. This will be changed to Error throw in the next major version')
}

return indexedRules;
}

Expand All @@ -98,6 +106,11 @@ export class Ability {
}

can(action, subject, field) {
if (field && typeof field !== 'string') {
// eslint-disable-next-line
throw new Error('Ability.can expects 3rd parameter to be a string. See https://stalniy.github.io/casl/abilities/2017/07/21/check-abilities.html#checking-fields for details')
}

const rule = this.relevantRuleFor(action, subject, field);

return !!rule && !rule.inverted;
Expand Down

0 comments on commit 9df032c

Please sign in to comment.