passpartu 0.6.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f1074ae228e7b5f0cfff3a9a2fc0acd58536a161451cab914b814e8b1bf44470
4
- data.tar.gz: 4ecf5e75ec63192afd3d739b47dd646912de8b594f01e8553fd6f9df0d1dbfb6
3
+ metadata.gz: 982e32959b5022a455e42d2c1de190c0851f358cfd34c699ece8394e6af0d951
4
+ data.tar.gz: 2e81288b0af25837d0d4d97b14562e33f2813ca0b8741adbce66451568a99487
5
5
  SHA512:
6
- metadata.gz: ceeac19430a29384cf70bf5755ed6786e06f76d981d1c42e81a677f8163211f46bc6a4bdb4eca6d9968cc7751d0c234392edfe6227c2dfd2c0c2f1132ab36cb0
7
- data.tar.gz: 5d4aef534482fc686033d67c043e8378dc92c8bfecbb00672d81949fa5a63ccba6c36c3fd492267375a38854085eae4f13af6da8aa20c3df7e1c1c935ee39c40
6
+ metadata.gz: 3cebce1276892e0fd925be52bc3ed817b83b6aeb96d9b056b9d999d288b9cbe891189f36a8d6b904b1dac53bbd90eb10b2d6628e42f727d063bc300abbeb697d
7
+ data.tar.gz: 6caeffe92ffe0f8fe158c0d10c9d4eca18e88ac3acad3c14d7346673ca6740c7335564d53f10a9263f6ae2bcc533077fb18d84cfb25c68cac71717e7b4c01ff7
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Passpartu v0.6.0 - [changelog](https://github.com/coaxsoft/passpartu/blob/master/CHANGELOG.md)
1
+ # Passpartu v1.0.0 - [changelog](https://github.com/coaxsoft/passpartu/blob/master/CHANGELOG.md)
2
2
 
3
3
  Passpartu makes policies great again (works awesome with [Pundit](https://rubygems.org/gems/pundit)).
4
4
 
@@ -132,6 +132,37 @@ Check user roles AND policy rule
132
132
  user_agent.agent_can?(:orders, :edit, except: [:admin, :manager]) { user_agent.orders.include?(order) }
133
133
  ```
134
134
 
135
+ #### Waterfall check
136
+ Allow or restrict absolutely everything for particular role or/and particular domain.
137
+ ```ruby
138
+ # ./config/initializers/passpartu.rb
139
+
140
+ Passpartu.configure do |config|
141
+ config.check_waterfall = true
142
+ end
143
+ ```
144
+
145
+ ```yml
146
+ # ./config/passpartu.yml
147
+
148
+ super_admin: true
149
+ super_looser: false
150
+ medium_looser:
151
+ orders:
152
+ create: true
153
+ delete: false
154
+ products: true
155
+ ```
156
+ ```ruby
157
+ user_super_admin.can?(:do, :whatever, :want) # true
158
+ user_super_loser.can?(:do, :whatever, :want) # false
159
+ user_medium_loser.can?(:orders, :create) # true
160
+ user_medium_loser.can?(:orders, :delete) # false
161
+ user_medium_loser.can?(:products, :create) # true
162
+ user_medium_loser.can?(:products, :create, :and_delete) # true
163
+ ```
164
+
165
+
135
166
  ##### Real life example
136
167
  You need to check custom rule for agent
137
168
  ```yml
@@ -1,13 +1,18 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'passpartu/version'
2
4
  require 'yaml'
3
5
  require_relative 'passpartu/patcher'
4
6
  require_relative 'passpartu/verify'
5
7
  require_relative 'passpartu/block_verify'
6
8
  require_relative 'passpartu/validate_result'
9
+ require_relative 'passpartu/check_waterfall'
7
10
  require_relative 'passpartu/user' # for testing only
8
11
 
9
12
  module Passpartu
10
13
  class Error < StandardError; end
14
+ class PolicyYmlNotFoundError < StandardError; end
15
+ class WaterfallError < StandardError; end
11
16
 
12
17
  def self.included(policy_class)
13
18
  Passpartu::Patcher.call(policy_class)
@@ -27,17 +32,23 @@ module Passpartu
27
32
  end
28
33
 
29
34
  class Config
30
- attr_accessor :policy, :raise_policy_missed_error
35
+ attr_accessor :policy, :raise_policy_missed_error, :check_waterfall
31
36
  attr_reader :policy_file
32
37
 
38
+ DEFAULT_POLICY_FILE = './config/passpartu.yml'
39
+
33
40
  def initialize
34
- @policy_file = './config/passpartu.yml'
35
- @policy = YAML.load_file(policy_file)
41
+ @policy_file = DEFAULT_POLICY_FILE
42
+ @policy = YAML.load_file(policy_file) if File.exist?(policy_file)
36
43
  @raise_policy_missed_error = true
44
+ @check_waterfall = false
37
45
  end
38
46
 
39
47
  def policy_file=(file = nil)
40
- @policy_file = file || './config/passpartu.yml'
48
+ @policy_file = file || DEFAULT_POLICY_FILE
49
+
50
+ raise PolicyYmlNotFoundError unless File.exist?(policy_file)
51
+
41
52
  @policy = YAML.load_file(policy_file)
42
53
  end
43
54
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Passpartu
2
4
  class BlockVerify < ::Passpartu::Verify
3
5
  def call
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Passpartu
4
+ class CheckWaterfall
5
+ attr_reader :waterfall, :policy_hash
6
+ def initialize(role, keys)
7
+ @waterfall = [role] + keys
8
+ @policy_hash = Passpartu.policy
9
+ end
10
+
11
+ def self.call(role, keys)
12
+ new(role, keys).call
13
+ end
14
+
15
+ def call
16
+ patch_boolean_classes
17
+ @result = policy_hash.dig(*waterfall)
18
+ reset_boolean_classes
19
+
20
+ @result
21
+ end
22
+
23
+ def patch_boolean_classes
24
+ TrueClass.define_method(:dig) { |*_keys| true }
25
+ FalseClass.define_method(:dig) { |*_keys| false }
26
+ end
27
+
28
+ def reset_boolean_classes
29
+ TrueClass.undef_method(:dig)
30
+ FalseClass.undef_method(:dig)
31
+ end
32
+ end
33
+ end
@@ -1,7 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Passpartu
2
4
  class Patcher
3
5
  attr_reader :klass
4
6
  def initialize(klass)
7
+ raise PolicyYmlNotFoundError if Passpartu.policy.nil?
8
+
5
9
  @klass = klass
6
10
  end
7
11
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # for testing only
2
4
 
3
5
  module Passpartu
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Passpartu
2
4
  class ValidateResult
3
5
  class PolicyMissedError < StandardError; end
@@ -1,6 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Passpartu
2
4
  class Verify
3
- CRUD_KEY = 'crud'.freeze
5
+ CRUD_KEY = 'crud'
4
6
 
5
7
  attr_reader :role, :keys, :result, :only, :except, :block
6
8
 
@@ -12,6 +14,8 @@ module Passpartu
12
14
  @only = Array(only).map(&:to_s) if present?(only)
13
15
  @except = Array(exclusion).map(&:to_s) if present?(exclusion) && !@only
14
16
  @block = block
17
+
18
+ raise PolicyYmlNotFoundError if Passpartu.policy.nil?
15
19
  end
16
20
 
17
21
  def self.call(role, keys, only: nil, except: nil, skip: nil, &block)
@@ -21,10 +25,17 @@ module Passpartu
21
25
  def call
22
26
  return false if role_ignore?
23
27
 
24
- check_policy
25
- check_crud if policy_missed? && last_key_crud?
28
+ check_waterfall_if
29
+ default_check
30
+ check_crud_if
26
31
 
27
32
  validate_result
33
+ rescue StandardError => e
34
+ if ['TrueClass does not have #dig method', 'FalseClass does not have #dig method'].include?(e.message)
35
+ raise WaterfallError.new "Looks like you want to use check_waterfall feature, but it's set to 'false'. Otherwise check your #{Passpartu.config.policy_file} for validness"
36
+ else
37
+ raise e
38
+ end
28
39
  end
29
40
 
30
41
  private
@@ -36,17 +47,17 @@ module Passpartu
36
47
  false
37
48
  end
38
49
 
39
- def check_policy
50
+ def default_check
51
+ return unless policy_missed?
52
+
40
53
  @result = Passpartu.policy.dig(role, *keys)
41
54
  end
42
55
 
43
- def check_crud
44
- change_crud_key
45
- check_policy
46
- end
56
+ def check_crud_if
57
+ return unless policy_missed? && last_key_crud?
47
58
 
48
- def change_crud_key
49
59
  @keys[-1] = CRUD_KEY
60
+ default_check
50
61
  end
51
62
 
52
63
  def policy_missed?
@@ -61,6 +72,12 @@ module Passpartu
61
72
  %w[create read update delete].include?(keys[-1])
62
73
  end
63
74
 
75
+ def check_waterfall_if
76
+ return unless Passpartu.config.check_waterfall && policy_missed?
77
+
78
+ @result = Passpartu::CheckWaterfall.call(role, keys)
79
+ end
80
+
64
81
  def blank?(item)
65
82
  item.respond_to?(:empty?) ? !!item.empty? : !item
66
83
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Passpartu
2
- VERSION = '0.6.0'.freeze
4
+ VERSION = '1.0.0'
3
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: passpartu
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - OrestF
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-04-01 00:00:00.000000000 Z
11
+ date: 2020-04-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -64,6 +64,7 @@ files:
64
64
  - README.md
65
65
  - lib/passpartu.rb
66
66
  - lib/passpartu/block_verify.rb
67
+ - lib/passpartu/check_waterfall.rb
67
68
  - lib/passpartu/patcher.rb
68
69
  - lib/passpartu/user.rb
69
70
  - lib/passpartu/validate_result.rb
@@ -89,7 +90,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
89
90
  - !ruby/object:Gem::Version
90
91
  version: '0'
91
92
  requirements: []
92
- rubygems_version: 3.0.1
93
+ rubyforge_project:
94
+ rubygems_version: 2.7.7
93
95
  signing_key:
94
96
  specification_version: 4
95
97
  summary: Passpartu makes policies great again