cant_cant_cant 0.1.9 → 0.1.10

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
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