question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Feature Request: Checking fields for complex types

See original GitHub issue

Hi! I’m curious if anyone has dealt with restricting access to complex fields, or would be interested in a PR that solves for that. I have a schema that looks like:

new mongoose.Schema({
  children: [{
    childField1: String,
    childField2: String,
  }]
});

and I want to be able to restrict access to only childField1:

// definition
can('update', Model, ['children.childField1'])

// check
abilities.can('update', instance, 'children.0.childField1')

This would let me loop through instance.modifiedPaths and check that each path is updatable.

instance.modifiedPaths().forEach(path => {
  this._abilities.throwUnlessCan('update', instance, path);
});

Is this something others have dealt with?

I was thinking about writing a PR that does something like this:

import mongoose from 'mongoose';
import casl from '@casl/ability';
const { AbilityBuilder, Ability } = casl;

export const testSchema = new mongoose.Schema({
  objectField: {
    childField1: String,
    childField2: String,
  },
  arrayField: [
    {
      basicField: String,
      objectField: {
        childField1: String,
        childField2: String,
      },
    },
  ],
});

const Model = mongoose.model('Test', testSchema);

const test = new Model({
  objectField: {
    childField1: 'value',
    childField2: 'value',
  },
  arrayField: [String],
  complexField: [
    {
      basicField: 'value',
      otherBasicField: 'value',
      objectField: {
        childField1: 'value',
        childField2: 'value',
      },
      arrayField: [String],
    },
  ],
});

let abilities;

// If you can access an object, you can access all its children.
abilities = AbilityBuilder.define((can, cannot) => {
  can('read', Model, ['objectField']);
});
console.info(abilities.can('read', test, 'objectField')); // true
console.info(abilities.can('read', test, 'objectField.childField1')); // true
console.info(abilities.can('read', test, 'objectField.childField2')); // true

// If you can access a child, you can access the parent, but not siblings.
abilities = AbilityBuilder.define((can, cannot) => {
  can('read', Model, ['objectField.childField1']);
});
console.info(abilities.can('read', test, 'objectField')); // true
console.info(abilities.can('read', test, 'objectField.childField1')); // true
console.info(abilities.can('read', test, 'objectField.childField2')); // false

// If you can access an array, you can access any member of the array.
abilities = AbilityBuilder.define((can, cannot) => {
  can('read', Model, ['arrayField']);
});
console.info(abilities.can('read', test, 'arrayField')); // true
console.info(abilities.can('read', test, 'arrayField.0')); // true
console.info(abilities.can('read', test, 'arrayField.1')); // true

// If you can access a child of an array, you can access the array or any member of the array,
// but only the specified children.
abilities = AbilityBuilder.define((can, cannot) => {
  can('read', Model, [
    'complexField.basicField',
    'complexField.objectField.childField2'
    'complexField.objectField.arrayField'
    ]);
});
console.info(abilities.can('read', test, 'complexField')); // true
console.info(abilities.can('read', test, 'complexField.0')); // true
console.info(abilities.can('read', test, 'complexField.0.basicField')); // true
console.info(abilities.can('read', test, 'complexField.0.otherBasicField')); // false
console.info(abilities.can('read', test, 'complexField.0.objectField')); // true
console.info(abilities.can('read', test, 'complexField.0.objectField.childField1')); // false
console.info(abilities.can('read', test, 'complexField.0.objectField.childField2')); // true
console.info(abilities.can('read', test, 'complexField.0.arrayField')); // true
console.info(abilities.can('read', test, 'complexField.0.arrayField.0')); // true

Any interest, or does it just add too much complexity for an uncommon requirement?

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Comments:18 (9 by maintainers)

github_iconTop GitHub Comments

1reaction
stalniycommented, Jan 16, 2019

By the way, you can also try to implement custom RuleType class and pass it in Ability. This is currently undocumented feature but I planned to expose this to public.

So, you can write a custom Rule class which overrides default isRelevantFor(object, field) method which actually does the check.

import { Rule, Ability } from '@casl/ability'

class CustomRule extends Rule {
  isRelevantFor(object, field) {
     // default implementation can be found in https://github.com/stalniy/casl/blob/master/packages/casl-ability/src/rule.js#L29
  } 
}

const ability = new Ability([], { RuleType: CustomRule })
1reaction
stalniycommented, Jan 16, 2019

Correct.

You can take a look at this gist which implements custom pick functionality with asterisk support.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Feature request tracking: Guide, tools & best practices - Beamer
Feature requests are feedback forms that customers can fill out to ask for new features or suggest improvements to existing ones.
Read more >
How To Manage Feature Requests [Template included]
This guide will teach you everything about feature requests – how to process them, manage them, respond to them, prioritize them – so...
Read more >
Feature Request Template: How to Manage Suggestions at ...
Streamline and organize user feedback with this free feature request template. Available in Google Docs and Sheets (no email required).
Read more >
Feature Requests: How to Collect Them and Engage Users in ...
3 main types of feature requests · 1. Bugs and issues · 2. Product or feature improvements · 3. New products or features....
Read more >
How to handle "can you add just a few more fields" type of ...
Very commonly we have feature requests for fields that only one customer wants. This, at best, clutters the application's code. Often when we...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found