|
2 | 2 |
|
3 | 3 | **WORK IN PROGRESS DOCS**
|
4 | 4 |
|
5 |
| -First as you say to explicitly send stuff to all applicants. Policies work "backwards" to how you might think in a controller. In a controller you might check something like acting_user.chatrooms.include?(message.chatroom) whereas Hyperloop starts from the other end, it'll effectively do something like this message.chatroom.participants.include?(acting_user). Your job in a policy is to start with the actual record, then traverse the relationships to return the user or users it belongs to. Think in terms of "I have a thing, who are all the people who are allowed to see it?". |
6 |
| -Now that may or may not work in your case. If you have anonymous accounts for applicants but they all still have user records and thus IDs then it will work — job_posting.hiring_manager.applicants. But if applicants didn't have any record then you couldn't use this style of "instance channel policy". Instance == ids == non-public. So if something is public you can use a class channel. send_all.to(Applicant). |
7 |
| -Finally you can have many channels or just a few. In our app I've gone with a user instance channel, and a user class channel. That's just what works for my mental model. But you could have other instance and class channels to make dividing things up easier, your scope chains shorter, etc. |
8 |
| -Hopefully you can look at the docs now and see instance, class, channel, broadcast, etc. and come up with a way that works for you. Mitch's snippet looks good, I just tried to give some surrounding color. |
9 |
| - |
10 |
| -The policy send all bit is about once you've got a record/records, are you allowed to see it and what attributes are you allowed to see (in that case all, but you can permit a subset). |
11 |
| -The regulate bit is about what relations are you allowed to access. It may seem redundant as without regulations event if you loaded the relation you still wouldn't be able see any of the record attributes without a policy. So even without regulations there's no risk of exposing private information. BUT what would leak is lists IDs and counts. A count doesn't instantiate any records so there's nothing to run a policy on. Leaking counts and IDs is metadata that may or may not be sensitive, aka you wouldn't want an insurance company to be able to do patient.diseases.count. And if you're using UUIDs so you don't sequentially leak all of your public pages, again you'd want a regulation to protect that. They can also prevent denial of service attacks loading big expensive relations. |
12 |
| -So, broadcast policies are about who can see the attributes of an individual record (or collection but it's still run on each record individually). Regulations are about preventing business data leakage. |
13 |
| - |
14 |
| ------------- |
15 |
| - |
16 |
| -from Mitch... |
17 |
| - |
18 |
| -These work very similar to pundit, and by design you can even mix pundit and hyperloop policies. |
19 |
| -Here is an example pundit policy from the pundit tutorial: |
20 |
| - |
21 |
| -# app/policies/article_policy.rb |
22 |
| -class ArticlePolicy < ApplicationPolicy |
23 |
| - def index? |
24 |
| - true |
25 |
| - end |
26 |
| - |
27 |
| - def create? |
28 |
| - user.present? |
29 |
| - end |
30 |
| - |
31 |
| - def update? |
32 |
| - return true if user.present? && user == article.user |
33 |
| - end |
34 |
| - |
35 |
| - def destroy? |
36 |
| - return true if user.present? && user == article.user |
37 |
| - end |
38 |
| - |
39 |
| - private |
40 |
| - |
41 |
| - def article |
42 |
| - record |
43 |
| - end |
44 |
| -end |
45 |
| - |
46 |
| --------------- |
47 |
| - |
48 |
| -class ArticlePolicy < ApplicationPolicy |
49 |
| - # def index? |
50 |
| - # true |
51 |
| - # end |
52 |
| - |
53 |
| - # read policies are defined as part of broadcast policies. (if you can receive |
54 |
| - # it in a broadcast then you can read it) |
55 |
| - # There is no controller in hyperloop so broadcast/read policies |
56 |
| - # are defined in terms of what data is sent to what channel |
57 |
| - |
58 |
| - regulate_broadcast do |policy| |
59 |
| - policy.send_all.to Application |
60 |
| - end |
61 |
| - |
62 |
| - # def create? |
63 |
| - # user.present? <- create is okay if user is not nil |
64 |
| - # end |
65 |
| - |
66 |
| - allow_create { acting_user } # <- create is okay if acting_user is not nil |
67 |
| - |
68 |
| - # def update? |
69 |
| - # return true if user.present? && user == article.user |
70 |
| - # end |
71 |
| - |
72 |
| - # only difference is hyperloop makes it easier by |
73 |
| - # 1) running the block with self == the the record |
74 |
| - # 2) adding the acting_user method to self |
75 |
| - # 3) treating exceptions as the same as nil |
76 |
| - |
77 |
| - allow_update { acting_user == user } |
78 |
| - |
79 |
| - # def destroy? |
80 |
| - # return true if user.present? && user == article.user |
81 |
| - # end |
82 |
| - |
83 |
| - allow_destroy { acting_user == user } |
84 |
| - |
85 |
| - # the above two regulations are the same and so can be dried up like this: |
86 |
| - |
87 |
| - allow_change(on: [:update, :destroy]) { acting_user == user } |
88 |
| - |
89 |
| - # private |
90 |
| - # |
91 |
| - # def article |
92 |
| - # record |
93 |
| - # end |
94 |
| -end |
95 |
| - |
96 |
| -without comments.... |
97 |
| - |
98 |
| -class ArticlePolicy < ApplicationPolicy |
99 |
| - regulate_broadcast { |policy| policy.send_all.to Application } |
100 |
| - |
101 |
| - allow_create { acting_user } # <- create is okay if acting_user is not nil |
102 |
| - |
103 |
| - allow_change(on: [:update, :destroy]) { acting_user == user } |
104 |
| -end |
105 |
| - |
106 |
| -BTW what if you want to restrict what data is broadcast? In Hyperloop you just update the regulation. In pundit you may have to edit both the index controller method and |
107 |
| -Policy class. |
108 |
| - |
109 |
| - |
110 |
| -**Work in progress - ALPHA (docs and code)** |
111 |
| - |
112 | 5 | ## Authorization
|
113 | 6 |
|
114 | 7 | Access to your Isomorphic Models is controlled by *Policies* that describe how the current *acting_user* and *channels* may access your Models.
|
@@ -596,3 +489,110 @@ class ProductionCenterPolicy < MyPolicyClass
|
596 | 489 | ...
|
597 | 490 | end
|
598 | 491 | ```
|
| 492 | + |
| 493 | +--------------------------- |
| 494 | +TODO: rewrite the following: |
| 495 | + |
| 496 | +First as you say to explicitly send stuff to all applicants. Policies work "backwards" to how you might think in a controller. In a controller you might check something like acting_user.chatrooms.include?(message.chatroom) whereas Hyperloop starts from the other end, it'll effectively do something like this message.chatroom.participants.include?(acting_user). Your job in a policy is to start with the actual record, then traverse the relationships to return the user or users it belongs to. Think in terms of "I have a thing, who are all the people who are allowed to see it?". |
| 497 | +Now that may or may not work in your case. If you have anonymous accounts for applicants but they all still have user records and thus IDs then it will work — job_posting.hiring_manager.applicants. But if applicants didn't have any record then you couldn't use this style of "instance channel policy". Instance == ids == non-public. So if something is public you can use a class channel. send_all.to(Applicant). |
| 498 | +Finally you can have many channels or just a few. In our app I've gone with a user instance channel, and a user class channel. That's just what works for my mental model. But you could have other instance and class channels to make dividing things up easier, your scope chains shorter, etc. |
| 499 | +Hopefully you can look at the docs now and see instance, class, channel, broadcast, etc. and come up with a way that works for you. Mitch's snippet looks good, I just tried to give some surrounding color. |
| 500 | + |
| 501 | +The policy send all bit is about once you've got a record/records, are you allowed to see it and what attributes are you allowed to see (in that case all, but you can permit a subset). |
| 502 | +The regulate bit is about what relations are you allowed to access. It may seem redundant as without regulations event if you loaded the relation you still wouldn't be able see any of the record attributes without a policy. So even without regulations there's no risk of exposing private information. BUT what would leak is lists IDs and counts. A count doesn't instantiate any records so there's nothing to run a policy on. Leaking counts and IDs is metadata that may or may not be sensitive, aka you wouldn't want an insurance company to be able to do patient.diseases.count. And if you're using UUIDs so you don't sequentially leak all of your public pages, again you'd want a regulation to protect that. They can also prevent denial of service attacks loading big expensive relations. |
| 503 | +So, broadcast policies are about who can see the attributes of an individual record (or collection but it's still run on each record individually). Regulations are about preventing business data leakage. |
| 504 | + |
| 505 | +------------ |
| 506 | + |
| 507 | +from Mitch... |
| 508 | + |
| 509 | +These work very similar to pundit, and by design you can even mix pundit and hyperloop policies. |
| 510 | +Here is an example pundit policy from the pundit tutorial: |
| 511 | + |
| 512 | +# app/policies/article_policy.rb |
| 513 | +class ArticlePolicy < ApplicationPolicy |
| 514 | + def index? |
| 515 | + true |
| 516 | + end |
| 517 | + |
| 518 | + def create? |
| 519 | + user.present? |
| 520 | + end |
| 521 | + |
| 522 | + def update? |
| 523 | + return true if user.present? && user == article.user |
| 524 | + end |
| 525 | + |
| 526 | + def destroy? |
| 527 | + return true if user.present? && user == article.user |
| 528 | + end |
| 529 | + |
| 530 | + private |
| 531 | + |
| 532 | + def article |
| 533 | + record |
| 534 | + end |
| 535 | +end |
| 536 | + |
| 537 | +-------------- |
| 538 | + |
| 539 | +class ArticlePolicy < ApplicationPolicy |
| 540 | + # def index? |
| 541 | + # true |
| 542 | + # end |
| 543 | + |
| 544 | + # read policies are defined as part of broadcast policies. (if you can receive |
| 545 | + # it in a broadcast then you can read it) |
| 546 | + # There is no controller in hyperloop so broadcast/read policies |
| 547 | + # are defined in terms of what data is sent to what channel |
| 548 | + |
| 549 | + regulate_broadcast do |policy| |
| 550 | + policy.send_all.to Application |
| 551 | + end |
| 552 | + |
| 553 | + # def create? |
| 554 | + # user.present? <- create is okay if user is not nil |
| 555 | + # end |
| 556 | + |
| 557 | + allow_create { acting_user } # <- create is okay if acting_user is not nil |
| 558 | + |
| 559 | + # def update? |
| 560 | + # return true if user.present? && user == article.user |
| 561 | + # end |
| 562 | + |
| 563 | + # only difference is hyperloop makes it easier by |
| 564 | + # 1) running the block with self == the the record |
| 565 | + # 2) adding the acting_user method to self |
| 566 | + # 3) treating exceptions as the same as nil |
| 567 | + |
| 568 | + allow_update { acting_user == user } |
| 569 | + |
| 570 | + # def destroy? |
| 571 | + # return true if user.present? && user == article.user |
| 572 | + # end |
| 573 | + |
| 574 | + allow_destroy { acting_user == user } |
| 575 | + |
| 576 | + # the above two regulations are the same and so can be dried up like this: |
| 577 | + |
| 578 | + allow_change(on: [:update, :destroy]) { acting_user == user } |
| 579 | + |
| 580 | + # private |
| 581 | + # |
| 582 | + # def article |
| 583 | + # record |
| 584 | + # end |
| 585 | +end |
| 586 | + |
| 587 | +without comments.... |
| 588 | + |
| 589 | +class ArticlePolicy < ApplicationPolicy |
| 590 | + regulate_broadcast { |policy| policy.send_all.to Application } |
| 591 | + |
| 592 | + allow_create { acting_user } # <- create is okay if acting_user is not nil |
| 593 | + |
| 594 | + allow_change(on: [:update, :destroy]) { acting_user == user } |
| 595 | +end |
| 596 | + |
| 597 | +BTW what if you want to restrict what data is broadcast? In Hyperloop you just update the regulation. In pundit you may have to edit both the index controller method and |
| 598 | +Policy class. |
0 commit comments