Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Activity
  • Jan 31 22:44
    renovate[bot] edited #154
  • Jan 31 22:17
    riyadshauk starred stalniy/casl
  • Jan 31 21:49
    renovate[bot] commented #154
  • Jan 31 21:49
    renovate[bot] opened #154
  • Jan 31 20:16

    renovate[bot] on typescript-3.x

    chore(deps): update dependency … (compare)

  • Jan 31 17:15
    iamvanja starred stalniy/casl
  • Jan 31 17:13
    RedShift1 commented #153
  • Jan 31 16:35
    stalniy commented #152
  • Jan 31 16:33
    stalniy commented #153
  • Jan 31 15:45
    RedShift1 opened #153
  • Jan 31 11:11
    chrisblakely01 starred stalniy/casl
  • Jan 31 04:58
    l02162010 starred stalniy/casl
  • Jan 31 03:22
    l02162010 commented #150
  • Jan 30 22:58
    ifatihyildirim starred stalniy/casl
  • Jan 30 20:56
    scytherswings starred stalniy/casl
  • Jan 30 19:38
    jmwohl starred stalniy/casl
  • Jan 30 18:55
    mdaronco starred stalniy/casl
  • Jan 30 10:57
    AlexGoranov edited #152
  • Jan 30 10:57
    AlexGoranov edited #152
  • Jan 30 10:57
    AlexGoranov edited #152
tmikaeld
@tmikaeld
@stalniy Sweet, thanks for looking into it! :)
tmikaeld
@tmikaeld

@stalniy I've been away from CASL too long and and am now dumbstruck again..
I load a user template like this:

// Load the users template
function findAbilityTemplateFor(user) {
    return JSON.stringify([
        {
            "actions": ["create", "read", "update", "delete"],
            "subject": "Project",
            "conditions": {
              "active": "${user.active}",
              "author": "${user.id}",
              "role": "${user.role}"
            }
        }
    ]);
}

Then I parse the JSON using a helper function and apply the template rules to the ability variable.

Now, how do i use it in my code, let's say the user have to be active to be allowed?

tmikaeld
@tmikaeld
Like, how do I check if a condition matches in my code?
tmikaeld
@tmikaeld
@stalniy I'm basically trying to use this: https://stalniy.github.io/casl/abilities/storage/2017/07/22/storing-abilities.html#store-ability-templates could you show a full example?
tmikaeld
@tmikaeld
I guess it's supposed to work like this:
  • Load user data and tags. ( findAbilityTemplateFor() )
  • Check action & subject on each function restriction. ( ability.can('something') )
  • Retrieve and compare the CASL condition values inside the codebase? (if ( !ability.rules[0].conditions.active) { etc } )
tmikaeld
@tmikaeld
I expected that i could check conditions like this: ability.can('read', 'Project', { active: false }) but that doesn't seem to be the case since 3rd param expects a string. Then I found this: https://github.com/stalniy/casl/issues/59#issuecomment-387288324 but ability.can('read', new Project({ active: true }))doesn't work either..
tmikaeld
@tmikaeld
Spelling mistake, ability.can('read', new Project({ active: true }))does work. The docs assume a lot and don't include the class declaration... Please explain this better and include the FULL examples in the docs.
It's frustrating that ability.can('read', 'Project', { active: false }) doesn't work because that's how it's constructed.
It becomes even more confusing when the third parameter is suddenly a field comparison.
tmikaeld
@tmikaeld

"Think of it as asking “can the current user read at least one post?”. The user can read a post which has published set to true, so this returns true. If you are doing a class name check, it is important you do another check once an instance becomes available so the object of conditions can be used."

Maybe explain it as: "The subject conditions are not compared by default since it's defaults to true. If you want to compare a condition, you need to supply the class object and comparison values" and add an example that declares the class and uses it to compare the values.

Sergii Stotskyi
@stalniy

@tmikaeld it's constructed similarly but not the same. For example in conditions you can use mongo query conditions like $in, $regex:

const { can } = AbilityBuilder.extract()

can('read', 'Post', { status: { $in: ['published', 'draft'] } })

// then you cannot do a check like this, because it has no sense. Your model will never have status  draft and published at the same time. Also `$in` condition looks weird in context of model check.
ability.can('read', 'Post', { status: { $in: ['published', 'draft'] })

I know that some people mix these things up, that's why I added validation check. Also I'd recommend to use destructuring and aliases for AbilityBuilder to keep them separate. For example:

const { can: allow } = AbilityBuilder.extract()

allow('read', 'Post', { status: { $in: ['published', 'draft'] } })

@tmikaeld conditions in single rule combined with AND logic, so:

{
            "actions": ["create", "read", "update", "delete"],
            "subject": "Project",
            "conditions": {
              "active": "${user.active}",
              "author": "${user.id}",
              "role": "${user.role}"
            }
        }

Here you say can CRUD Project only if project.active === user.active && user.id === project.author && project.role === user.role

I think you wanted to do something different :)
@tmikaeld I plan to reformat docs, unfortunately don't have enough free time right now
qvan-der
@qvdp
Hi, I have a question, i'm building on a Nuxt js app my user abilities with CASL such as :
{ actions: decodedPermission, subject: decodedModel, conditions: { brands: decoded.brands } }.
All goes well, since i tried to use the brands filter. My condition brands has to be an array, and I would like to check with $can for example if the brand of a record is included in my conditions brands at the same time of ability check. I tried with $can('update', 'product', { brands: product.brand }) but it doesn't work and I didn't find how to handle my condition. So how could I achieve this ? Thank you.
Sergii Stotskyi
@stalniy
@qvdp you should get an exception in browser console. $can accepts the same arguments as Ability.prototype.can. I mean action: string, subject: any, field: string. The list of arguments that is passed to $can is wrong
Please check one of the example repos for Vue. You will find there subjectName. Also please take a look a this paragraph https://stalniy.github.io/casl/abilities/2017/07/20/define-abilities.html#ability-subject-name
Sergii Stotskyi
@stalniy

@tmikaeld I looked into ESM support. Some articles say that nodejs dynamically detects whether there is index.mjs or index.js files depending on the --experimental-modules flag. I tested and this does not work :)

Nodejs in mjs files loads @casl/ability as a regular CJS module (so, all the exports in default export)

I personally don't think that ESM in Nodejs is mature enough for this. As I understood they haven't solved compatibility issues for library authors.
This is what Nodejs Foundation said in April this year ^
and the article about dual export approach which doesn't work in the latest Nodejs - https://medium.com/@iamstan/tips-for-writing-es-modules-in-node-js-96ec688615a4
tmikaeld
@tmikaeld
@stalniy Thanks for looking into module loading, and thanks for the reply on construction. It's still confusing to wrap my head around it, I like to keep things as simple as possible. But I think with better docs in the future, it should be fine as is. No need to break compatibility.
Manuk
@ManukMinasyan
Hi guys, I have a problem with vuejs and laravel. I make a login with laravel, I create a passport access token, and after that I insert it into the meta tag, inside vue js I get this token and make requests to the laravel application using api. My component is created before updating the rules, what can I do to solve this problem? thanks
Sergii Stotskyi
@stalniy
Hi, what do you mean by saying that component is created before updating rules?
rules are reactive in terms of Vue so your component will be updated when you update ability
Check this repo https://github.com/stalniy/casl-vue-api-example for a reference
Numan Ashiq
@numanash
Hi! New Here...
I have question how we can check multiple permissions on in "I" attribute in react
this.context.can(route.can + isAdmin ? ',all' : '', "app")
<Can I={this.props.can} an="app">
if this.props.can = "all, check_perm,check_role,etc..."
Numan Ashiq
@numanash
@stalniy @ManukMinasyan @tmikaeld
Numan Ashiq
@numanash
In simple words how i can pass multiple actions
Jeffrey Meesters
@Jeffrey-Meesters

Hi @stalniy ,
Thanks for CASL it's awesome.
I manage to get it working (in Vue) up until the point I actually need to start using conditions.
I'm using a rules list to update on Ability.
This rules list is based by remapping rules provided by the back-end.
Now my logged in User should be able to read all Users, but may only Update itself.
The rule I created is this:

[{
    actions: ["read", "update"],
    conditions: {id: "thisisanid"},
    subject: ["Users"]
}]

(1) So doing this $can("update", "Users") works because it is defined but of course will return true for every user, so goal not achieved.
(2) I want to do this $can("update", new Users(this.userInfo)) where Users is a class with the id of the userInfo object being worked on.
Now 2 works as I want it to work.. it returns only true if the user is going to update its own info.
(3) But writing 1 as I've done in 2 for READING users of course results in the same behaviour $can("read", new Users(this.userInfo))
results in only being able to read my own user data.
Now my question is: How can I use this condition only for "update" but still being able to pass Users as a class object to "read".
This because I actually don't want to use 2 different syntax: ("read", "Users") or ("update", new Users(this.userInfo)) as in this maner another developer has to think about when he/she should check for conditions and I'm afraid this will cause problems in the future.

I hope you can help me out.
Thanks in advance.

Jeffrey Meesters
@Jeffrey-Meesters

I found out how to do it:

[
    {
        actions: ["read"],
        subject: ["Users"]
    },
    {
        actions: ["update"],
        conditions: {id: "thisisanid"},
        subject: ["Users"]
    }
]

So basically separating a rule on a subject with conditions from a rule on the same subject without conditions :)

Sonit90
@Sonit90

Hi, i encountered problem with subjectName function. I am using VueJS (Quasar)
I tried an extreme scenario of returning a specific subjectName, but it still doesn't apply to rule. My rules are like this:

function subjectName (item) {
  return 'Flat'
}
export default function defineAbilitiesFor (user) {
  const { rules, can } = AbilityBuilder.extract()

  if (user) {
    can('edit', 'Flat', { seller_id: user.user_id })
    can('create', 'Flat')
    can('delete', 'Flat')
  }
  return new Ability(rules, { subjectName })
}

(i tried different options, but it still gives me this error: ForbiddenError: Cannot execute "edit" on "Object"
and the check is like this:

try {
        console.log(this.$ability)
        this.$ability.throwUnlessCan('edit', { modelName: 'Flat', ...row })
      } catch (error) {
        console.log(error)
      }

$actions equals to this, when i output them to html:
[
{ "actions": "edit", "subject": [ "Flat" ], "conditions": { "seller_id": 6 } },
{ "actions": "create", "subject": [ "Flat" ] },
{ "actions": "delete", "subject": [ "Flat" ] }]

Simple rules like $can('create', 'Flat') works perfectly, but more complex ones doesn't
I am using plain objects when i check type of object, that's why i try to rewrite subjectName function

And i update rules after user logins like this:

this._vm.$ability.update(defineAbilitiesFor(data.profile).rules)
Sergii Stotskyi
@stalniy

Hi @Jeffrey-Meesters

just split rules into 2 :)

[
  { actions: ["read"], subject: "Users" },
  { actions: ["update"], subject: ["Users"], conditions: { id: "here is id" } }
]

I found out how to do it:

[
    {
        actions: ["read"],
        subject: ["Users"]
    },
    {
        actions: ["update"],
        conditions: {id: "thisisanid"},
        subject: ["Users"]
    }
]

So basically separating a rule on a subject with conditions from a rule on the same subject without conditions :)

right!

Hi @Sonit90

I think the issue is that this.$ability is created by @casl/vue plugin. This Ability instance is created without subjectName.

So, what you need to do is to create a separate Ability instance with empty rules, and specified subjectName. Then pass it to @casl/vue plugin:

Sergii Stotskyi
@stalniy
import { abilitiesPlugin } from '@casl/vue'
import Vue from 'vue'

const ability = new Ability([], { subjectName: () => 'Flat' })

Vue.use(abilitiesPlugin, ability)
everything else should work as expected
Sonit90
@Sonit90
@stalniy yepp, it worked thanks you! I guess this shoud be added to the docs, because i wasn't able to found the solution in topics or in docs.
unconqueredsun
@unconqueredsun
Hi @stalniy,
Loving casl so far.
I'd like to get your advice about how to use conditions of abilities as where conditions in sequelize queries so that I can simply query for the objects I have the ability to perform an action on.
Sergii Stotskyi
@stalniy

Hi @unconqueredsun

Take a look at this issue stalniy/casl#8 it will give some context. In order to create rules to query convertor take a look how @casl/mongoose does this.

General rule convertor for sequelize will be a bit more complicated especially if you use the latest version which does not support operator aliases

Weilies Chok
@weilies
Anyone like me? Looking for Angular Firebase cum #CASL integration? 😀
Gaurav Agarwal
@0nlogn_twitter

Hi @stalniy. Is there a way to build an Ability with can with nested objected.

Say:

class A {
    a1: string;
    a2: string;
}

class B {
    b1: A[];
}

class C {
    c1: B;
}

Now I want to write something like:
can('edit', 'C', ...)
where I need to check that instance of C can be edited only when cObject.c1.b1 has A that matches certain a1 and a2?

Please let me know if something is not clear.

Sergii Stotskyi
@stalniy
it’s possible to do this. Currently it will work only for in memory checks. You can use dot notation. Also it will work if the row in db contains the whole aggregate
can(“edit”, “C”, { “c1.b1”: { $in: [“test1”, “test2”] } })
Jordy van Eijk
@jordyvaneijk
I have a question about ability.update()
In the documentation is see that it is possible to create the abilities as an json object like [{subject: 'myitem', actions: ['this', 'or that']}] and that you can use that to create the abilities but it is also talking about an template you need to use. but it dont understand what you mean by that. If i just give the update method the array of abilities/ rules it looks like it's not working.