papers_please 0.0.1.beta → 0.0.2.beta

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 6a205acbfa3b9735fe92e5f28fd20d692f95d05f
4
- data.tar.gz: c4811ebdf8979ecdec29dc11b442daf1b053ba89
2
+ SHA256:
3
+ metadata.gz: d12ab3dd8981fb3a6fb74a02b0f34e917438792c2151562c9945a04c79d50d9d
4
+ data.tar.gz: 694b9b96b9057e122392a2382488bfbecc877b881cf681e07dcb066091d2bd8c
5
5
  SHA512:
6
- metadata.gz: 8ba41bdb2ac002fc19ff9166e92a9e6b7da129f9470251ed2e76db24f497fc5c51afa94d8953832527be4ef5267b547e0798bdf0e6a847b682b1fd87896f3b9f
7
- data.tar.gz: 54c2475662d529ad39c63468351f1f8a261471998119983a2249e5cebb82859b320b95f28653450943806dfcd3158adffb3c9e7e135f9bf4ad2e9679e8da34c9
6
+ metadata.gz: 80a53cd2301779d6a332c1c01d495f54035886d64a5d3d23e3434de008b5fac367e9a351eb96ef1a842b9c1ae4207045c28c739a43d0f3e78def7e7836f65680
7
+ data.tar.gz: cc6193a203effc3bff3f3351359550ac71fcf4ca83bd1d1f0cd31ed918f2a083c410638e9c6c2e2e1fd2ea21da3cb7555c57a34f3118bf8c5472a5d35e72abdb
data/.byebug_history ADDED
@@ -0,0 +1,60 @@
1
+ q
2
+ @policy
3
+ q
4
+ permission
5
+ c
6
+ permission
7
+ c
8
+ permission
9
+ c
10
+ permission
11
+ q
12
+ res.include?(obj)
13
+ posts.include?(obj)
14
+ posts.include(obj)
15
+ res
16
+ obj
17
+ c
18
+ obj
19
+ res.include?(obj)
20
+ res.include?
21
+ res
22
+ c
23
+ u.posts
24
+ u
25
+ c
26
+ u
27
+ c
28
+ role
29
+ q
30
+ role
31
+ q
32
+ applicable_roles.count
33
+ applicable_roles
34
+ c
35
+ q
36
+ @user
37
+ role.applies_to?(@user)
38
+ role
39
+ c
40
+ q
41
+ applicable_roles
42
+ c
43
+ q
44
+ klass
45
+ action
46
+ permissions
47
+ permission_exists?(action, klass)
48
+ action
49
+ q
50
+ n
51
+ s
52
+ actions
53
+ c
54
+ n
55
+ role
56
+ c
57
+ n
58
+ roles.key?(:admin)
59
+ roles
60
+ name
data/Gemfile.lock ADDED
@@ -0,0 +1,45 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ papers_please (0.0.1.beta)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ byebug (10.0.2)
10
+ diff-lcs (1.3)
11
+ docile (1.3.1)
12
+ json (2.1.0)
13
+ rake (10.5.0)
14
+ rspec (3.7.0)
15
+ rspec-core (~> 3.7.0)
16
+ rspec-expectations (~> 3.7.0)
17
+ rspec-mocks (~> 3.7.0)
18
+ rspec-core (3.7.1)
19
+ rspec-support (~> 3.7.0)
20
+ rspec-expectations (3.7.0)
21
+ diff-lcs (>= 1.2.0, < 2.0)
22
+ rspec-support (~> 3.7.0)
23
+ rspec-mocks (3.7.0)
24
+ diff-lcs (>= 1.2.0, < 2.0)
25
+ rspec-support (~> 3.7.0)
26
+ rspec-support (3.7.1)
27
+ simplecov (0.16.1)
28
+ docile (~> 1.1)
29
+ json (>= 1.8, < 3)
30
+ simplecov-html (~> 0.10.0)
31
+ simplecov-html (0.10.2)
32
+
33
+ PLATFORMS
34
+ ruby
35
+
36
+ DEPENDENCIES
37
+ bundler (~> 1.16)
38
+ byebug
39
+ papers_please!
40
+ rake (~> 10.0)
41
+ rspec (~> 3.0)
42
+ simplecov
43
+
44
+ BUNDLED WITH
45
+ 1.16.1
data/README.md CHANGED
@@ -2,7 +2,98 @@
2
2
 
3
3
  A roles and permissions gem from Apsis Labs.
4
4
 
5
- **NOTE**: Still under heavy development, definitely not suitable for anything remotely resembling production usage.
5
+ **NOTE**: Still under heavy development, definitely not suitable for anything remotely resembling production usage. Very unlikely to even work.
6
+
7
+ ## Example
8
+
9
+ ```ruby
10
+ # app/policies/access_policy.rb
11
+ class AccessPolicy < PapersPlease::Policy
12
+ config do
13
+ # Define a role in a block
14
+ role :admin, (proc { |u| u.admin? }) do
15
+ grant [:manage, :archive], Post
16
+ end
17
+
18
+ # Define a role in a class
19
+ role :member, MemberRole
20
+
21
+ # Define a role with no predicate
22
+ role :guest do
23
+ grant [:read], Post, predicate: (proc { |u, post| !post.archived? })
24
+ end
25
+ end
26
+ end
27
+
28
+ # app/policies/roles/member_role.rb
29
+ class MemberRole < PapersPlease::Role
30
+ predicate { |user| user.member? }
31
+
32
+ config do
33
+ grant :create, Post
34
+ grant [:read, :update], Post, query: (proc { |u| u.posts })
35
+ grant :archive, Post, query: method(:published_posts)
36
+ end
37
+
38
+ private
39
+
40
+ def published_posts(user, klass)
41
+ user.posts.where(status: :published)
42
+ end
43
+ end
44
+
45
+ # app/controllers/posts_controller.rb
46
+ class PostsController < ApplicationController
47
+ # GET /posts
48
+ def index
49
+ @posts = policy.query(:read, Post)
50
+ render json: @posts
51
+ end
52
+
53
+ # GET /posts/:id
54
+ def show
55
+ @post = Post.find(params[:id])
56
+ policy.authorize! :read, @post
57
+
58
+ render json: @post
59
+ end
60
+
61
+ # POST /posts/:id/archive
62
+ def archive
63
+ @post = Post.find(params[:id])
64
+ policy.authorize! :archive, @post
65
+
66
+ @post.update!(archived: true)
67
+ render json: @post
68
+ end
69
+ end
70
+ ```
71
+
72
+ ## A helpful CLI
73
+
74
+ ```bash
75
+ $ rails papers_please:roles
76
+
77
+ # =>
78
+ # | role | permission | object |
79
+ # | :------ | :--------- | :----- |
80
+ # | :admin | :create | Post |
81
+ # | | :read | Post |
82
+ # | | :update | Post |
83
+ # | | :destroy | Post |
84
+ # | | :archive | Post |
85
+ # | | | |
86
+ # | :member | :create | Post |
87
+ # | | :read | Post |
88
+ # | | :update | Post |
89
+ # | | :archive | Post |
90
+ # | | | |
91
+ # | :guest | :read | Post |
92
+
93
+ $ rails papers_please:annotate [app/policies/access_policy.rb]
94
+
95
+ # => output roles table to top of AccessPolicy file
96
+ ```
6
97
 
7
98
  ## Installation
8
99
 
@@ -24,6 +115,15 @@ Or install it yourself as:
24
115
 
25
116
  TODO: Write usage instructions here
26
117
 
118
+ ## Theory
119
+
120
+ The structure of `papers_please` is very simple. At its core, it is a mechanism for storing and retrieving `Procs`. In an authorization context, these `Procs` answer two questions:
121
+
122
+ 1. Given a specific user and a specific permission, which objects am I allowed to operate on?
123
+ 2. Given a specific user and a specific object, do I have a specific permission?
124
+
125
+ The machinery of `papers_please` tries to simplify the organization and subsequent access to these questions as much as possible.
126
+
27
127
  ## Development
28
128
 
29
129
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -34,6 +134,10 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
34
134
 
35
135
  Bug reports and pull requests are welcome on GitHub at https://github.com/wkirby/papers_please.
36
136
 
137
+ ## Special Thanks
138
+
139
+ This owes its existence to [`AccessGranted`](https://github.com/chaps-io/access-granted). Thanks!
140
+
37
141
  ## License
38
142
 
39
143
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,11 @@
1
+ module PapersPlease
2
+ class Error < StandardError; end
3
+
4
+ class AccessDenied < Error; end
5
+
6
+ class DuplicatePermission < Error; end
7
+ class InvalidPermission < Error; end
8
+
9
+ class DuplicateScope < Error; end
10
+ class InvalidScope < Error; end
11
+ end
@@ -0,0 +1,36 @@
1
+ module PapersPlease
2
+ class Permission
3
+ attr_accessor :key, :subject, :query, :predicate
4
+
5
+ def initialize(key, subject, query: nil, predicate: nil)
6
+ @key = key
7
+ @subject = subject
8
+ @query = query
9
+ @predicate = predicate
10
+ end
11
+
12
+ def matches?(key, subject)
13
+ key_matches?(key) && subject_matches?(subject)
14
+ end
15
+
16
+ def granted?(*args)
17
+ return predicate.call(*args) if predicate.is_a? Proc
18
+ false
19
+ end
20
+
21
+ def fetch(*args)
22
+ return query.call(*args) if query.is_a? Proc
23
+ nil
24
+ end
25
+
26
+ private
27
+
28
+ def key_matches?(key)
29
+ key == @key
30
+ end
31
+
32
+ def subject_matches?(subject)
33
+ subject == @subject || subject.class <= @subject
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,68 @@
1
+ module PapersPlease
2
+ class Policy
3
+ attr_accessor :roles
4
+ attr_reader :user
5
+
6
+ def initialize(user)
7
+ @user = user
8
+ @roles = {}
9
+ @cache = {}
10
+
11
+ configure
12
+ end
13
+
14
+ def configure
15
+ raise NotImplementedError
16
+ end
17
+
18
+ # Add a role to the Policy
19
+ def add_role(name, predicate = nil, &block)
20
+ name = name.to_sym
21
+ raise DuplicateRole if roles.key?(name)
22
+
23
+ role = Role.new(name, predicate: predicate, definition: block)
24
+ roles[name] = role
25
+
26
+ role
27
+ end
28
+ alias role add_role
29
+
30
+ # Look up a stored permission block and call with
31
+ # the current user and subject
32
+ def can?(action, subject = nil)
33
+ applicable_roles.each do |_, role|
34
+ permission = role.find_permission(action, subject)
35
+ return permission.granted?(user, subject, action) unless permission.nil?
36
+ end
37
+
38
+ false
39
+ end
40
+
41
+ def cannot?(*args)
42
+ !can?(*args)
43
+ end
44
+
45
+ def authorize!(action, subject)
46
+ raise AccessDenied.new(action, subject) if cannot?(action, subject)
47
+ subject
48
+ end
49
+
50
+ # Look up a stored scope block and call with the
51
+ # current user and class
52
+ def scope_for(action, klass)
53
+ applicable_roles.each do |_, role|
54
+ permission = role.find_permission(action, klass)
55
+ return permission.fetch(user, klass, action) unless permission.nil?
56
+ end
57
+
58
+ nil
59
+ end
60
+
61
+ # Fetch roles that apply to the current user
62
+ def applicable_roles
63
+ @applicable_roles ||= roles.select do |_, role|
64
+ role.applies_to?(user)
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,82 @@
1
+ module PapersPlease
2
+ class Role
3
+ attr_reader :name, :predicate, :permissions
4
+
5
+ def initialize(name, predicate: nil, definition: nil)
6
+ @name = name
7
+ @predicate = predicate
8
+ @permissions = []
9
+
10
+ instance_eval(&definition) unless definition.nil?
11
+ end
12
+
13
+ def applies_to?(user)
14
+ return @predicate.call(user) if @predicate.is_a? Proc
15
+ true
16
+ end
17
+
18
+ def add_permission(actions, klass, query: nil, predicate: nil)
19
+ prepare_actions(actions).each do |action|
20
+ raise DuplicatePermission if permission_exists?(action, klass)
21
+
22
+ has_query = query.is_a?(Proc)
23
+ has_predicate = predicate.is_a?(Proc)
24
+ permission = Permission.new(action, klass)
25
+
26
+ if has_query && has_predicate
27
+ # Both query & predicate provided
28
+
29
+ permission.query = query
30
+ permission.predicate = predicate
31
+ elsif has_query && !has_predicate
32
+ # Only query provided
33
+
34
+ permission.query = query
35
+
36
+ if action == :create && actions == :manage
37
+ # If the action is :create, expanded from :manage
38
+ # then we set the default all predicate
39
+ permission.predicate = (proc { true })
40
+ else
41
+ # Otherwise the default predicate is to check
42
+ # for inclusion in the returned relationship
43
+ permission.predicate = (proc { |user, obj|
44
+ res = query.call(user, klass, action)
45
+ res.respond_to?(:include?) && res.include?(obj)
46
+ })
47
+ end
48
+ elsif !has_query && has_predicate
49
+ # Only predicate provided
50
+
51
+ permission.predicate = predicate
52
+ else
53
+ # Neither provided
54
+ permission.query = (proc { klass.all })
55
+ permission.predicate = (proc { true })
56
+ end
57
+
58
+ permissions << permission
59
+ end
60
+ end
61
+ alias grant add_permission
62
+
63
+ def find_permission(action, subject)
64
+ permissions.detect do |permission|
65
+ permission.matches? action, subject
66
+ end
67
+ end
68
+
69
+ def permission_exists?(action, subject)
70
+ !find_permission(action, subject).nil?
71
+ end
72
+
73
+ private
74
+
75
+ # Wrap actions, translating :manage into :crud
76
+ def prepare_actions(action)
77
+ Array(*[action]).flat_map do |a|
78
+ a == :manage ? [:create, :read, :update, :destroy] : [a]
79
+ end
80
+ end
81
+ end
82
+ end
@@ -1,3 +1,3 @@
1
1
  module PapersPlease
2
- VERSION = "0.0.1.beta"
2
+ VERSION = "0.0.2.beta"
3
3
  end
data/lib/papers_please.rb CHANGED
@@ -1,4 +1,8 @@
1
- require "papers_please/version"
1
+ require 'papers_please/version'
2
+ require 'papers_please/errors'
3
+ require 'papers_please/policy'
4
+ require 'papers_please/role'
5
+ require 'papers_please/permission'
2
6
 
3
7
  module PapersPlease
4
8
  # Your code goes here...
@@ -24,4 +24,6 @@ Gem::Specification.new do |spec|
24
24
  spec.add_development_dependency "bundler", "~> 1.16"
25
25
  spec.add_development_dependency "rake", "~> 10.0"
26
26
  spec.add_development_dependency "rspec", "~> 3.0"
27
+ spec.add_development_dependency "byebug"
28
+ spec.add_development_dependency 'simplecov'
27
29
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: papers_please
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1.beta
4
+ version: 0.0.2.beta
5
5
  platform: ruby
6
6
  authors:
7
7
  - Apsis Labs
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-07-20 00:00:00.000000000 Z
11
+ date: 2018-10-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -52,6 +52,34 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: byebug
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: simplecov
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
55
83
  description:
56
84
  email:
57
85
  - wyatt@apsis.io
@@ -59,16 +87,22 @@ executables: []
59
87
  extensions: []
60
88
  extra_rdoc_files: []
61
89
  files:
90
+ - ".byebug_history"
62
91
  - ".gitignore"
63
92
  - ".rspec"
64
93
  - ".travis.yml"
65
94
  - Gemfile
95
+ - Gemfile.lock
66
96
  - LICENSE.txt
67
97
  - README.md
68
98
  - Rakefile
69
99
  - bin/console
70
100
  - bin/setup
71
101
  - lib/papers_please.rb
102
+ - lib/papers_please/errors.rb
103
+ - lib/papers_please/permission.rb
104
+ - lib/papers_please/policy.rb
105
+ - lib/papers_please/role.rb
72
106
  - lib/papers_please/version.rb
73
107
  - papers_please.gemspec
74
108
  homepage: http://apsis.io
@@ -91,7 +125,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
91
125
  version: 1.3.1
92
126
  requirements: []
93
127
  rubyforge_project:
94
- rubygems_version: 2.6.13
128
+ rubygems_version: 2.7.6
95
129
  signing_key:
96
130
  specification_version: 4
97
131
  summary: A roles & permissions gem for ruby applications.