cant_cant_cant 0.1.9 → 0.1.10

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
  SHA1:
3
- metadata.gz: 2b7f960df566535239837a3b10da07249852957b
4
- data.tar.gz: 0177db1f7cbde126092dc4b11d6eee99329a3420
3
+ metadata.gz: a3c41e2930a4a017599c9e543e4c5e1169889117
4
+ data.tar.gz: 86763bee8b49529010526fce57b9f679a24a8bfc
5
5
  SHA512:
6
- metadata.gz: 696a00f8b533dcddfbc0c2b0e69b9880957847c43ce783024c59d3944bde49c7a6eac415c66bc1504c69169b7fc467b84fe806104f2333dfed69d984a902b026
7
- data.tar.gz: 0d8b38ed2c21267889862dc00eb85f62ed110f818e9c7304aa0ed4e63007a06a22bdf047795c88b5f730c43bf901ce5f6b1295e4a37f44ef184c43dc2e2b1723
6
+ metadata.gz: 566fcfca7d3f06465cacf466ab1890161d70901a3754d4c61e3d3f924bcd97cf227bb54e3120cd5e69a7801ee2a32a46adc08fb3e414ec0e86307025550cb5b5
7
+ data.tar.gz: 5c974bc3695058e4b763e9077d10db1b469b5a3613d4475d5fcf9e9e71b90c539ed27be6302fdba0499ec39b1f9087bc184255aaca935d4ef824ff8c04029101
data/README.md CHANGED
@@ -36,7 +36,7 @@ You're done. There is no need to configure more in any of your controllers.
36
36
 
37
37
  Note that live reloading is not supported yet; it means you'll need to restart your server after modifying your actions/controllers/config to take effect.
38
38
 
39
- If you need to acquire a list of actions that given roles have access to, just call `CantCantCant.permissions_for(roles)`.
39
+ If you need to acquire a list of actions that given roles have access to, just call `CantCantCant.allowed_actions_for(roles)`.
40
40
 
41
41
 
42
42
  ## Configuration
@@ -1,43 +1,108 @@
1
1
  require 'yaml'
2
+ require 'ostruct'
3
+ require 'set'
4
+ require_relative 'concern'
2
5
 
3
6
  module CantCantCant
4
7
  PermissionDenied = Class.new(RuntimeError)
5
8
  InvalidConfiguration = Class.new(RuntimeError)
9
+ UnfilledAction = Class.new(RuntimeError)
6
10
 
7
11
  class << self
8
- def initialize(config)
12
+ def initialize(config, &block)
9
13
  @config_file = config
10
- @cache = {}
11
14
 
12
- inject_actions
13
- end
15
+ @config = OpenStruct.new(
16
+ injection_mode: :base_controller,
17
+ base_controller: ActionController::Base,
18
+ default_policy: :allow,
19
+ report_unfilled_actions: :ignore,
20
+ caching: true
21
+ )
22
+ @config.instance_eval(&block) if block_given?
23
+
24
+ @allow_cache = {}
25
+ @deny_cache = {}
14
26
 
15
- def inject_actions
16
27
  validate_config
17
28
 
18
- permission_table.values.map(&:keys).flatten.uniq.each do |param|
19
- inject_action(param)
29
+ case @config.injection_mode
30
+ when :base_controller
31
+ inject_base_controller
32
+ when :individual
33
+ inject_individual_actions
20
34
  end
21
35
  end
22
36
 
23
- def allow?(param, roles)
24
- permissions_for(roles).include? param
37
+ def allow?(action, roles)
38
+ return true if allowed_actions_for(roles).include? action
39
+ return false if denied_actions_for(roles).include?(action)
40
+
41
+ case @config.report_unfilled_actions
42
+ # when :ignore, do nothing
43
+ when :warn
44
+ warn "Please fill in CantCantCant permission #{action}"
45
+ when :raise
46
+ raise UnfilledAction, [action, roles]
47
+ end
48
+
49
+ case @config.default_policy
50
+ when :allow then true
51
+ when :deny then false
52
+ end
25
53
  end
26
54
 
27
- def permissions_for(roles)
55
+ def allowed_actions_for(roles)
28
56
  roles = [roles] unless roles.is_a? Array
29
- @cache[roles.sort.join(',')] ||=
30
- permission_table
31
- .values_at(*roles.map(&:to_s))
32
- .select(&:present?)
33
- .map { |x| x.keep_if { |_, v| v == 'allow' }.keys }
34
- .flatten
35
- .uniq
57
+ key = roles.sort.join(',')
58
+ return @allow_cache[key] if @allow_cache[key] && @config.caching
59
+
60
+ perms = permission_table
61
+ .values_at(*roles.map(&:to_s))
62
+ .select(&:present?)
63
+ allowed_perms = perms
64
+ .map { |x| x.select { |_, v| v == 'allow' }.keys }
65
+ .flatten
66
+ .uniq
67
+ @allow_cache[key] = allowed_perms.to_set
68
+ end
69
+
70
+ def all_actions
71
+ @all_actions = nil unless @config.caching
72
+ @all_actions ||= permission_table
73
+ .values
74
+ .map(&:keys)
75
+ .flatten
76
+ .uniq
77
+ .to_set
78
+ end
79
+
80
+ def denied_actions_for(roles)
81
+ roles = [roles] unless roles.is_a? Array
82
+ key = roles.sort.join(',')
83
+ return @deny_cache[key] if @deny_cache[key] && @config.caching
84
+ @deny_cache[key] = all_actions - allowed_actions_for(roles)
36
85
  end
37
86
 
38
87
  private
39
88
 
89
+ def inject_base_controller
90
+ base_controller_class = @config.base_controller
91
+ base_controller_class.before_action CantCantCantAuth
92
+ end
93
+
94
+ def inject_individual_actions
95
+ controller_actions = all_actions
96
+ .map { |x| extract_controller(x) }
97
+ .group_by(&:first)
98
+ controller_actions.each do |controller, actions|
99
+ actions = actions.map(&:second)
100
+ controller.before_action CantCantCantAuth, only: actions
101
+ end
102
+ end
103
+
40
104
  def permission_table
105
+ @permission_table = nil unless @config.caching
41
106
  @permission_table ||= YAML.load_file(@config_file).freeze
42
107
  end
43
108
 
@@ -51,17 +116,6 @@ module CantCantCant
51
116
  [controller_class, action]
52
117
  end
53
118
 
54
- def inject_action(param)
55
- controller_class, action = extract_controller(param)
56
- controller_class.class_eval do
57
- before_action(only: action) do
58
- roles = current_roles
59
- next true if CantCantCant.allow?(param, roles)
60
- raise PermissionDenied, [param, roles]
61
- end
62
- end
63
- end
64
-
65
119
  def validate_config
66
120
  permission_table.each do |_, perms|
67
121
  perms.each do |param, access|
@@ -0,0 +1,9 @@
1
+ class CantCantCantAuth
2
+ def self.before(controller)
3
+ roles = controller.current_roles
4
+ params = controller.params
5
+ action = "#{params[:controller]}\##{params[:action]}"
6
+ return true if CantCantCant.allow?(action, roles)
7
+ raise CantCantCant::PermissionDenied, [action, roles]
8
+ end
9
+ end
@@ -18,7 +18,7 @@ module CantCantCant::Generators
18
18
 
19
19
  def user_params
20
20
  routes = Rails.application.routes.routes.to_a
21
- routes.reject! {|x| x.defaults[:internal] }
21
+ routes.reject! { |x| x.defaults[:internal] }
22
22
  routes.map(&:defaults).reject(&:empty?).uniq
23
23
  end
24
24
 
@@ -1,6 +1,24 @@
1
1
  Rails.application.config.after_initialize do
2
- config = File.join(Rails.root, 'config/cant_cant_cant.yml')
3
- CantCantCant.initialize(config)
2
+ perm_file = File.join(Rails.root, 'config/cant_cant_cant.yml')
3
+ CantCantCant.initialize(perm_file) do |c|
4
+ # - base_controller: Inject validation to the base controller
5
+ # - individual: Inject validation only to actions specified in config
6
+ # c.injection_mode = :base_controller
7
+
8
+ # This option is ignored unless c.injection_mode == :base_controller
9
+ # c.base_controller = ActionController::Base
10
+
11
+ # Specify what to do for unlisted access
12
+ # c.default_policy = :allow
13
+
14
+ # warn: print a warning for unlisted actions and adopt default_policy
15
+ # raise: raise an exception for unlisted actions
16
+ # ignore: ignore validation on unlisted actions and adopt default_policy
17
+ # c.report_unlisted_actions = :ignore
18
+
19
+ # Cache permission or load them from file for every request
20
+ c.caching = Rails.env.production?
21
+ end
4
22
  end
5
23
 
6
24
  class ActionController::Base
@@ -8,6 +26,10 @@ class ActionController::Base
8
26
  rescue_from CantCantCant::PermissionDenied do
9
27
  render plain: 'permission denied', status: 403
10
28
  end
29
+ # Only useful when report_unlisted_actions is set :raise
30
+ rescue_from CantCantCant::UnfilledAction do
31
+ render plain: 'action unlisted in cantcantcant permission file'
32
+ end
11
33
 
12
34
  # Write your own method to return the roles for current user
13
35
  def current_roles
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cant_cant_cant
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.9
4
+ version: 0.1.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shou Ya
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-10-13 00:00:00.000000000 Z
11
+ date: 2017-03-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -62,6 +62,7 @@ files:
62
62
  - README.md
63
63
  - Rakefile
64
64
  - lib/cant_cant_cant.rb
65
+ - lib/concern.rb
65
66
  - lib/generators/cant_cant_cant/install/install_generator.rb
66
67
  - lib/generators/cant_cant_cant/install/templates/config.yml
67
68
  - lib/generators/cant_cant_cant/install/templates/initializer.rb