cjbottaro-param_protected 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. data/CHANGELOG +19 -0
  2. data/README.rdoc +49 -0
  3. data/Rakefile +36 -0
  4. data/VERSION +1 -0
  5. data/init.rb +2 -0
  6. data/install.rb +1 -0
  7. data/lib/param_protected.rb +6 -0
  8. data/lib/param_protected/constants.rb +4 -0
  9. data/lib/param_protected/controller_modifications.rb +46 -0
  10. data/lib/param_protected/meta_class.rb +13 -0
  11. data/lib/param_protected/protector.rb +120 -0
  12. data/param_protected.gemspec +93 -0
  13. data/tasks/param_protected_tasks.rake +4 -0
  14. data/test/accessible_except_test.rb +13 -0
  15. data/test/accessible_only_test.rb +13 -0
  16. data/test/app_root/app/controllers/accessible_except_controller.rb +7 -0
  17. data/test/app_root/app/controllers/accessible_only_controller.rb +7 -0
  18. data/test/app_root/app/controllers/application_controller.rb +10 -0
  19. data/test/app_root/app/controllers/protected_controller.rb +29 -0
  20. data/test/app_root/app/controllers/users_controller.rb +7 -0
  21. data/test/app_root/config/boot.rb +115 -0
  22. data/test/app_root/config/database.yml +31 -0
  23. data/test/app_root/config/environment.rb +14 -0
  24. data/test/app_root/config/environments/in_memory.rb +0 -0
  25. data/test/app_root/config/environments/mysql.rb +0 -0
  26. data/test/app_root/config/environments/postgresql.rb +0 -0
  27. data/test/app_root/config/environments/sqlite.rb +0 -0
  28. data/test/app_root/config/environments/sqlite3.rb +0 -0
  29. data/test/app_root/config/routes.rb +4 -0
  30. data/test/app_root/lib/console_with_fixtures.rb +4 -0
  31. data/test/protected_controller_test.rb +47 -0
  32. data/test/protector_test.rb +147 -0
  33. data/test/test_helper.rb +51 -0
  34. data/test/users_controller_test.rb +22 -0
  35. data/uninstall.rb +1 -0
  36. metadata +107 -0
data/CHANGELOG ADDED
@@ -0,0 +1,19 @@
1
+ 09/12/2009
2
+ ----------
3
+ * Restructured and reorganized. Now the majority of the work is done in the Protector class. This minimizes the amount of methods / instance variables that clutter the controllers.
4
+ * The filtering is done in ActionController::Base#params now, instead of as a before filter. This eliminates the caveat of before filters declared after param_protected/param_accessible calls having access to the unprotected params.
5
+
6
+ 09/11/2009
7
+ ----------
8
+ * Refactored tests to use plugin_test_helper.
9
+ * gemified
10
+
11
+ 03/17/2009
12
+ ----------
13
+ * more sane way to specify nested parameters (honestly, I don't know what I was thinking before)
14
+ * the old method of specifying nested parameters ("user/first_name", "user/last_name") DOES NOT WORK ANYMORE.
15
+ * changed param_protected/param_accessible's :exclude argument to :except to better fit in with Rails
16
+
17
+ 07/16/2008
18
+ ----------
19
+ * rewrote the entire plugin (it should actually work now)
data/README.rdoc ADDED
@@ -0,0 +1,49 @@
1
+ = Summary
2
+ This plugin provides two class methods on <tt>ActiveController::Base</tt> that filter the <tt>params</tt> hash for that controller's actions. You can think of them as the controller analog of <tt>attr_protected</tt> and <tt>attr_accessible</tt>.
3
+
4
+ = Installation
5
+
6
+ Put in your <tt>environment.rb</tt> file...
7
+
8
+ config.gem "cjbottaro-param_protected", :lib => "param_protected", :source => "http://gems.github.com"
9
+
10
+ Alternatively, just install the gem from the command line and <tt>require "param_protected"</tt> somewhere in your project.
11
+
12
+ = Usage
13
+ class YourController < ActiveController::Base
14
+ param_protected <param_name> <options>
15
+ param_accessible <param_name> <options>
16
+
17
+ ...
18
+ end
19
+ <tt>param_name</tt> can be a String, Symbol, or Array of Strings and/or Symbols.
20
+
21
+ <tt>options</tt> is a Hash that has <em>one</em> of two keys: <tt>:only</tt> or <tt>:except</tt>. The value for these keys is a String, Symbol, or Array of Strings and/or Symbols which denotes to the action(s) for which params to protect.
22
+
23
+ = Examples
24
+
25
+ == Blacklisting
26
+ Any of these combinations should work.
27
+ param_protected :client_id
28
+ param_protected [:client_id, :user_id]
29
+ param_protected :client_id, :only => 'my_action'
30
+ param_protected :client_id, :except => [:your_action, :my_action]
31
+
32
+ == Whitelisting
33
+ Any of these combinations should work.
34
+ param_accessible :client_id
35
+ param_accessible :[:client_id, :user_id]
36
+ param_accessible :client_id, :only => 'my_action'
37
+ param_accessible :client_id, :except => [:your_action, :my_action]
38
+
39
+ == Nested Params
40
+ You can use combinations of arrays and hashes to specify nested params, much the same way <tt>ActiveRecord::Base#find</tt>'s
41
+ <tt>:include</tt> argument works.
42
+ param_accessible [:account_name, { :user => [:first_name, :last_name, :address => [:street, :city, :state]] }]
43
+ param_protected [:id, :password, { :user => [:id, :password] }]
44
+
45
+ = How does it work?
46
+ It does an <tt>alias_method_chain</tt> on <tt>ActionController::Base#params</tt> that filters (and caches) the params. You can get the unfiltered, pristine params by calling <tt>ActionController::Base#params_without_protection</tt>.
47
+
48
+ = Author
49
+ Christopher J. Bottaro
data/Rakefile ADDED
@@ -0,0 +1,36 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ begin
6
+ require 'jeweler'
7
+ Jeweler::Tasks.new do |gemspec|
8
+ gemspec.name = "param_protected"
9
+ gemspec.summary = "Filter unwanted parameters in your controllers and actions."
10
+ gemspec.description = "Provides two class methods on ActiveController::Base that filter the params hash for that controller's actions. You can think of them as the controller analog of attr_protected and attr_accessible."
11
+ gemspec.email = "cjbottaro@alumni.cs.utexas.edu"
12
+ gemspec.homepage = "http://github.com/cjbottaro/param_protected"
13
+ gemspec.authors = ["Christopher J. Bottaro"]
14
+ end
15
+ rescue LoadError
16
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
17
+ end
18
+
19
+ desc 'Default: run unit tests.'
20
+ task :default => :test
21
+
22
+ desc 'Test the param_protected plugin.'
23
+ Rake::TestTask.new(:test) do |t|
24
+ t.libs << 'lib'
25
+ t.pattern = 'test/**/*_test.rb'
26
+ t.verbose = true
27
+ end
28
+
29
+ desc 'Generate documentation for the param_protected plugin.'
30
+ Rake::RDocTask.new(:rdoc) do |rdoc|
31
+ rdoc.rdoc_dir = 'rdoc'
32
+ rdoc.title = 'ParamProtected'
33
+ rdoc.options << '--line-numbers' << '--inline-source'
34
+ rdoc.rdoc_files.include('README.rdoc')
35
+ rdoc.rdoc_files.include('lib/**/*.rb')
36
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.1.0
data/init.rb ADDED
@@ -0,0 +1,2 @@
1
+ # Include hook code here
2
+ require 'param_protected'
data/install.rb ADDED
@@ -0,0 +1 @@
1
+ # Install hook code here
@@ -0,0 +1,6 @@
1
+ require "param_protected/meta_class"
2
+ require "param_protected/constants"
3
+ require "param_protected/protector"
4
+ require "param_protected/controller_modifications"
5
+
6
+ ActionController::Base.extend(ParamProtected::ControllerModifications)
@@ -0,0 +1,4 @@
1
+ module ParamProtected
2
+ BLACKLIST = :blacklist
3
+ WHITELIST = :whitelist
4
+ end
@@ -0,0 +1,46 @@
1
+ module ParamProtected
2
+ module ControllerModifications
3
+
4
+ def self.extended(action_controller)
5
+ action_controller.class_eval do
6
+ extend ClassMethods
7
+ include InstanceMethods
8
+ alias_method_chain :params, :protection
9
+ end
10
+ end
11
+
12
+ module ClassMethods
13
+
14
+ def param_protected(params, actions = nil)
15
+ Protector.instance(self).declare_protection(params, actions, BLACKLIST)
16
+ end
17
+
18
+ def param_accessible(params, actions = nil)
19
+ Protector.instance(self).declare_protection(params, actions, WHITELIST)
20
+ end
21
+
22
+ end
23
+
24
+ module InstanceMethods
25
+
26
+ def params_with_protection
27
+
28
+ # #params is called internally by ActionController::Base a few times before an action is dispatched,
29
+ # thus we can't filter and cache it right off the bat. We have to wait for #action_name to be present
30
+ # to know that we're really in an action and @_params actually contains something. Then we can filter
31
+ # and cache it.
32
+
33
+ if action_name.blank?
34
+ params_without_protection
35
+ elsif @params_protected
36
+ @params_protected
37
+ else
38
+ @params_protected = Protector.instance(self.class).protect(params_without_protection, action_name)
39
+ end
40
+
41
+ end
42
+
43
+ end
44
+
45
+ end
46
+ end
@@ -0,0 +1,13 @@
1
+ class Object
2
+ unless method_defined?(:meta_class)
3
+ def meta_class
4
+ (class << self; self; end)
5
+ end
6
+ end
7
+
8
+ unless method_defined?(:meta_eval)
9
+ def meta_eval(&block)
10
+ meta_class.instance_eval(&block)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,120 @@
1
+ module ParamProtected
2
+ class Protector
3
+
4
+ def self.instance(controller)
5
+ unless controller.respond_to?(:pp_protector)
6
+ controller.class_eval{ @pp_protector = Protector.new }
7
+ controller.meta_eval { attr_reader :pp_protector }
8
+ end
9
+ controller.pp_protector
10
+ end
11
+
12
+ def initialize
13
+ @protections = []
14
+ end
15
+
16
+ def declare_protection(params, actions, exclusivity)
17
+ params = normalize_params(params)
18
+ actions = normalize_actions(actions)
19
+ @protections << [params, actions, exclusivity]
20
+ end
21
+
22
+ def protect(controller_params, action_name)
23
+ returning(deep_copy(controller_params)) do |params|
24
+ @protections.each do |protected_params, actions, exclusivity|
25
+ scope, actions = actions.first, actions[1..-1] # Careful not to modify the actions array in place.
26
+ next unless action_matches?(scope, actions, action_name)
27
+ filter_params(protected_params, params, exclusivity)
28
+ end
29
+ end
30
+ end
31
+
32
+ private
33
+
34
+ # When specifying params to protect, we allow a combination of arrays and hashes much like how
35
+ # ActiveRecord::Base#find's :include options works. This method normalizes that into just nested hashes,
36
+ # stringifying the keys and setting all values to nil. This format is easier/faster to work with when
37
+ # filtering the controller params.
38
+ # Example...
39
+ # [:a, {:b => [:c, :d]}]
40
+ # to
41
+ # {"a"=>nil, "b"=>{"c"=>nil, "d"=>nil}}
42
+ def normalize_params(params, params_out = {})
43
+ if params.instance_of?(Array)
44
+ params.each{ |param| normalize_params(param, params_out) }
45
+ elsif params.instance_of?(Hash)
46
+ params.each do |k, v|
47
+ k = k.to_s
48
+ params_out[k] = {}
49
+ normalize_params(v, params_out[k])
50
+ end
51
+ else
52
+ params_out[params.to_s] = nil
53
+ end
54
+ params_out
55
+ end
56
+
57
+ # When specifying which actions param protection apply to, we allow a format like this...
58
+ # :only => [:action1, :action2]
59
+ # This method normalizes that to...
60
+ # [:only, "action1", "action2"]
61
+ def normalize_actions(actions)
62
+ error_message = "invalid actions, use :only => ..., :except => ..., or nil"
63
+ return [:except, nil] if actions.blank?
64
+ raise ArgumentError, error_message unless actions.instance_of?(Hash)
65
+ raise ArgumentError, error_message unless actions.length == 1
66
+ raise ArgumentError, error_message unless [:only, :except].include?(actions.keys.first)
67
+
68
+ scope, actions = actions.keys.first, actions.values.first
69
+ actions = [actions] unless actions.instance_of?(Array)
70
+ actions = actions.collect{ |action| action.to_s }
71
+ [scope, *actions]
72
+ end
73
+
74
+ # When #dup just isn't enough... :P
75
+ def deep_copy(object)
76
+ returning(try_to_dup(object)) do |new_object|
77
+ case new_object
78
+ when Hash
79
+ new_object.each{ |k, v| new_object[k] = deep_copy(v) }
80
+ when Array
81
+ new_object.replace(new_object.collect{ |item| deep_copy(item) })
82
+ end
83
+ end
84
+ end
85
+
86
+ # Some objects are not dupable... like TrueClass, FalseClass and NilClass.
87
+ def try_to_dup(object)
88
+ object.dup
89
+ rescue TypeError
90
+ object
91
+ end
92
+
93
+ def action_matches?(scope, actions, action_name)
94
+ if action_name.blank?
95
+ false
96
+ elsif scope == :only
97
+ actions.include?(action_name)
98
+ elsif scope == :except
99
+ !actions.include?(action_name)
100
+ else
101
+ raise ArgumentError, "unexpected scope (#{scope}), expected :only or :except"
102
+ end
103
+ end
104
+
105
+ def filter_params(protected_params, params, exclusivity)
106
+ return unless params.kind_of?(Hash)
107
+ return if protected_params.nil?
108
+ if exclusivity == BLACKLIST
109
+ params.delete_if{ |k, v| protected_params.has_key?(k) and protected_params[k].nil? }
110
+ elsif exclusivity == WHITELIST
111
+ params.delete_if{ |k, v| !protected_params.has_key?(k) }
112
+ else
113
+ raise ArgumentError, "unexpected exclusivity: #{exclusivity}"
114
+ end
115
+ params.each{ |k, v| filter_params(protected_params[k], v, exclusivity) }
116
+ params
117
+ end
118
+
119
+ end
120
+ end
@@ -0,0 +1,93 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{param_protected}
8
+ s.version = "1.1.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Christopher J. Bottaro"]
12
+ s.date = %q{2009-09-12}
13
+ s.description = %q{Provides two class methods on ActiveController::Base that filter the params hash for that controller's actions. You can think of them as the controller analog of attr_protected and attr_accessible.}
14
+ s.email = %q{cjbottaro@alumni.cs.utexas.edu}
15
+ s.extra_rdoc_files = [
16
+ "README.rdoc"
17
+ ]
18
+ s.files = [
19
+ "CHANGELOG",
20
+ "README.rdoc",
21
+ "Rakefile",
22
+ "VERSION",
23
+ "init.rb",
24
+ "install.rb",
25
+ "lib/param_protected.rb",
26
+ "lib/param_protected/constants.rb",
27
+ "lib/param_protected/controller_modifications.rb",
28
+ "lib/param_protected/meta_class.rb",
29
+ "lib/param_protected/protector.rb",
30
+ "param_protected.gemspec",
31
+ "tasks/param_protected_tasks.rake",
32
+ "test/accessible_except_test.rb",
33
+ "test/accessible_only_test.rb",
34
+ "test/app_root/app/controllers/accessible_except_controller.rb",
35
+ "test/app_root/app/controllers/accessible_only_controller.rb",
36
+ "test/app_root/app/controllers/application_controller.rb",
37
+ "test/app_root/app/controllers/protected_controller.rb",
38
+ "test/app_root/app/controllers/users_controller.rb",
39
+ "test/app_root/config/boot.rb",
40
+ "test/app_root/config/database.yml",
41
+ "test/app_root/config/environment.rb",
42
+ "test/app_root/config/environments/in_memory.rb",
43
+ "test/app_root/config/environments/mysql.rb",
44
+ "test/app_root/config/environments/postgresql.rb",
45
+ "test/app_root/config/environments/sqlite.rb",
46
+ "test/app_root/config/environments/sqlite3.rb",
47
+ "test/app_root/config/routes.rb",
48
+ "test/app_root/lib/console_with_fixtures.rb",
49
+ "test/protected_controller_test.rb",
50
+ "test/protector_test.rb",
51
+ "test/test_helper.rb",
52
+ "test/users_controller_test.rb",
53
+ "uninstall.rb"
54
+ ]
55
+ s.has_rdoc = true
56
+ s.homepage = %q{http://github.com/cjbottaro/param_protected}
57
+ s.rdoc_options = ["--charset=UTF-8"]
58
+ s.require_paths = ["lib"]
59
+ s.rubygems_version = %q{1.3.2}
60
+ s.summary = %q{Filter unwanted parameters in your controllers and actions.}
61
+ s.test_files = [
62
+ "test/accessible_except_test.rb",
63
+ "test/accessible_only_test.rb",
64
+ "test/app_root/app/controllers/accessible_except_controller.rb",
65
+ "test/app_root/app/controllers/accessible_only_controller.rb",
66
+ "test/app_root/app/controllers/application_controller.rb",
67
+ "test/app_root/app/controllers/protected_controller.rb",
68
+ "test/app_root/app/controllers/users_controller.rb",
69
+ "test/app_root/config/boot.rb",
70
+ "test/app_root/config/environment.rb",
71
+ "test/app_root/config/environments/in_memory.rb",
72
+ "test/app_root/config/environments/mysql.rb",
73
+ "test/app_root/config/environments/postgresql.rb",
74
+ "test/app_root/config/environments/sqlite.rb",
75
+ "test/app_root/config/environments/sqlite3.rb",
76
+ "test/app_root/config/routes.rb",
77
+ "test/app_root/lib/console_with_fixtures.rb",
78
+ "test/protected_controller_test.rb",
79
+ "test/protector_test.rb",
80
+ "test/test_helper.rb",
81
+ "test/users_controller_test.rb"
82
+ ]
83
+
84
+ if s.respond_to? :specification_version then
85
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
86
+ s.specification_version = 3
87
+
88
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
89
+ else
90
+ end
91
+ else
92
+ end
93
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :param_protected do
3
+ # # Task goes here
4
+ # end
@@ -0,0 +1,13 @@
1
+ require "test_helper"
2
+
3
+ class AccessibleExceptControllerTest < ActionController::TestCase
4
+
5
+ test_action :first do
6
+ assert_params %w[a b c d e f g h]
7
+ end
8
+
9
+ test_action :second do
10
+ assert_params %w[a]
11
+ end
12
+
13
+ end
@@ -0,0 +1,13 @@
1
+ require "test_helper"
2
+
3
+ class AccessibleOnlyControllerTest < ActionController::TestCase
4
+
5
+ test_action :first do
6
+ assert_params %w[a]
7
+ end
8
+
9
+ test_action :second do
10
+ assert_params %w[a b c d e f g h]
11
+ end
12
+
13
+ end
@@ -0,0 +1,7 @@
1
+ class AccessibleExceptController < ApplicationController
2
+ param_accessible :a, :except => :first
3
+
4
+ def first; end
5
+
6
+ def second; end
7
+ end
@@ -0,0 +1,7 @@
1
+ class AccessibleOnlyController < ApplicationController
2
+ param_accessible :a, :only => :first
3
+
4
+ def first; end
5
+
6
+ def second; end
7
+ end
@@ -0,0 +1,10 @@
1
+ class ApplicationController < ActionController::Base
2
+ before_filter :render_nothing
3
+
4
+ private
5
+
6
+ def render_nothing
7
+ render :nothing => true
8
+ end
9
+
10
+ end
@@ -0,0 +1,29 @@
1
+ class ProtectedController < ApplicationController
2
+ param_protected :a
3
+
4
+ def an_action; end
5
+
6
+ param_protected :b, :only => :only_one_action
7
+ def only_one_action; end
8
+
9
+ param_protected :c, :except => :except_one_action
10
+ def except_one_action; end
11
+
12
+ param_protected [:d, :e], :only => :params_as_array
13
+ def params_as_array;end
14
+
15
+ param_protected :f, :only => [:only_multiple_actions1, :only_multiple_actions2]
16
+ def only_multiple_actions1; end
17
+ def only_multiple_actions2; end
18
+
19
+ param_protected :g, :except => [:except_multiple_actions1, :except_multiple_actions2]
20
+ def except_multiple_actions1; end
21
+ def except_multiple_actions2; end
22
+
23
+ param_protected( { :h => :a }, :only => :nested_single )
24
+ def nested_single; end
25
+
26
+ param_protected( { :h => [:a, :b] }, :only => :nested_multiple )
27
+ def nested_multiple; end
28
+
29
+ end
@@ -0,0 +1,7 @@
1
+ class UsersController < ApplicationController
2
+ param_accessible( {:user => [ {:name => [:first, :last]}, :email ]} )
3
+
4
+ def create; end
5
+ def update; end
6
+
7
+ end
@@ -0,0 +1,115 @@
1
+ # Allow customization of the rails framework path
2
+ RAILS_FRAMEWORK_ROOT = (ENV['RAILS_FRAMEWORK_ROOT'] || "#{File.dirname(__FILE__)}/../../../../../../vendor/rails") unless defined?(RAILS_FRAMEWORK_ROOT)
3
+
4
+ # Don't change this file!
5
+ # Configure your app in config/environment.rb and config/environments/*.rb
6
+
7
+ RAILS_ROOT = "#{File.dirname(__FILE__)}/.." unless defined?(RAILS_ROOT)
8
+
9
+ module Rails
10
+ class << self
11
+ def boot!
12
+ unless booted?
13
+ preinitialize
14
+ pick_boot.run
15
+ end
16
+ end
17
+
18
+ def booted?
19
+ defined? Rails::Initializer
20
+ end
21
+
22
+ def pick_boot
23
+ (vendor_rails? ? VendorBoot : GemBoot).new
24
+ end
25
+
26
+ def vendor_rails?
27
+ File.exist?(RAILS_FRAMEWORK_ROOT)
28
+ end
29
+
30
+ def preinitialize
31
+ load(preinitializer_path) if File.exist?(preinitializer_path)
32
+ end
33
+
34
+ def preinitializer_path
35
+ "#{RAILS_ROOT}/config/preinitializer.rb"
36
+ end
37
+ end
38
+
39
+ class Boot
40
+ def run
41
+ load_initializer
42
+ Rails::Initializer.run(:set_load_path)
43
+ end
44
+ end
45
+
46
+ class VendorBoot < Boot
47
+ def load_initializer
48
+ require "#{RAILS_FRAMEWORK_ROOT}/railties/lib/initializer"
49
+ Rails::Initializer.run(:install_gem_spec_stubs)
50
+ Rails::GemDependency.add_frozen_gem_path
51
+ end
52
+ end
53
+
54
+ class GemBoot < Boot
55
+ def load_initializer
56
+ self.class.load_rubygems
57
+ load_rails_gem
58
+ require 'initializer'
59
+ end
60
+
61
+ def load_rails_gem
62
+ if version = self.class.gem_version
63
+ gem 'rails', version
64
+ else
65
+ gem 'rails'
66
+ end
67
+ rescue Gem::LoadError => load_error
68
+ $stderr.puts %(Missing the Rails #{version} gem. Please `gem install -v=#{version} rails`, update your RAILS_GEM_VERSION setting in config/environment.rb for the Rails version you do have installed, or comment out RAILS_GEM_VERSION to use the latest version installed.)
69
+ exit 1
70
+ end
71
+
72
+ class << self
73
+ def rubygems_version
74
+ Gem::RubyGemsVersion rescue nil
75
+ end
76
+
77
+ def gem_version
78
+ if defined? RAILS_GEM_VERSION
79
+ RAILS_GEM_VERSION
80
+ elsif ENV.include?('RAILS_GEM_VERSION')
81
+ ENV['RAILS_GEM_VERSION']
82
+ else
83
+ parse_gem_version(read_environment_rb)
84
+ end
85
+ end
86
+
87
+ def load_rubygems
88
+ require 'rubygems'
89
+ min_version = '1.3.1'
90
+ unless rubygems_version >= min_version
91
+ $stderr.puts %Q(Rails requires RubyGems >= #{min_version} (you have #{rubygems_version}). Please `gem update --system` and try again.)
92
+ exit 1
93
+ end
94
+
95
+ rescue LoadError
96
+ $stderr.puts %Q(Rails requires RubyGems >= #{min_version}. Please install RubyGems and try again: http://rubygems.rubyforge.org)
97
+ exit 1
98
+ end
99
+
100
+ def parse_gem_version(text)
101
+ $1 if text =~ /^[^#]*RAILS_GEM_VERSION\s*=\s*["']([!~<>=]*\s*[\d.]+)["']/
102
+ end
103
+
104
+ private
105
+ def read_environment_rb
106
+ environment_rb = "#{RAILS_ROOT}/config/environment.rb"
107
+ environment_rb = "#{HELPER_RAILS_ROOT}/config/environment.rb" unless File.exists?(environment_rb)
108
+ File.read(environment_rb)
109
+ end
110
+ end
111
+ end
112
+ end
113
+
114
+ # All that for this:
115
+ Rails.boot!
@@ -0,0 +1,31 @@
1
+ in_memory:
2
+ adapter: sqlite3
3
+ database: ":memory:"
4
+ verbosity: quiet
5
+ pool: 5
6
+ timeout: 5000
7
+ sqlite:
8
+ adapter: sqlite
9
+ dbfile: plugin_test.sqlite.db
10
+ pool: 5
11
+ timeout: 5000
12
+ sqlite3:
13
+ adapter: sqlite3
14
+ dbfile: plugin_test.sqlite3.db
15
+ pool: 5
16
+ timeout: 5000
17
+ postgresql:
18
+ adapter: postgresql
19
+ username: postgres
20
+ password: postgres
21
+ database: plugin_test
22
+ pool: 5
23
+ timeout: 5000
24
+ mysql:
25
+ adapter: mysql
26
+ host: localhost
27
+ username: root
28
+ password:
29
+ database: plugin_test
30
+ pool: 5
31
+ timeout: 5000
@@ -0,0 +1,14 @@
1
+ require File.join(File.dirname(__FILE__), 'boot')
2
+
3
+ Rails::Initializer.run do |config|
4
+ config.cache_classes = false
5
+ config.whiny_nils = true
6
+ config.action_controller.session = {:key => 'rails_session', :secret => 'd229e4d22437432705ab3985d4d246'}
7
+ config.plugin_locators.unshift(
8
+ Class.new(Rails::Plugin::Locator) do
9
+ def plugins
10
+ [Rails::Plugin.new(File.expand_path('.'))]
11
+ end
12
+ end
13
+ ) unless defined?(PluginTestHelper::PluginLocator)
14
+ end
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -0,0 +1,4 @@
1
+ ActionController::Routing::Routes.draw do |map|
2
+ map.connect ':controller/:action/:id'
3
+ map.connect ':controller/:action/:id.:format'
4
+ end
@@ -0,0 +1,4 @@
1
+ # Loads fixtures into the database when running the test app via the console
2
+ (ENV['FIXTURES'] ? ENV['FIXTURES'].split(/,/) : Dir.glob(File.join(Rails.root, '../fixtures/*.{yml,csv}'))).each do |fixture_file|
3
+ Fixtures.create_fixtures(File.join(Rails.root, '../fixtures'), File.basename(fixture_file, '.*'))
4
+ end
@@ -0,0 +1,47 @@
1
+ require "test_helper"
2
+
3
+ class ProtectedControllerTest < ActionController::TestCase
4
+
5
+ test_action :an_action do
6
+ assert_params %w[b d e f h]
7
+ end
8
+
9
+ test_action :only_one_action do
10
+ assert_params %w[d e f h]
11
+ end
12
+
13
+ test_action :except_one_action do
14
+ assert_params %w[c b d e f h]
15
+ end
16
+
17
+ test_action :params_as_array do
18
+ assert_params %w[b f h]
19
+ end
20
+
21
+ test_action :only_multiple_actions1 do
22
+ assert_params %w[b d e h]
23
+ end
24
+
25
+ test_action :only_multiple_actions2 do
26
+ assert_params %w[b d e h]
27
+ end
28
+
29
+ test_action :except_multiple_actions1 do
30
+ assert_params %w[b d e f g h]
31
+ end
32
+
33
+ test_action :except_multiple_actions2 do
34
+ assert_params %w[b d e f g h]
35
+ end
36
+
37
+ test_action :nested_single do
38
+ assert_params %w[b d e f h]
39
+ assert_equal({"b" => "b", "c" => "c"}, params["h"])
40
+ end
41
+
42
+ test_action :nested_multiple do
43
+ assert_params %w[b d e f h]
44
+ assert_equal({"c" => "c"}, params["h"])
45
+ end
46
+
47
+ end
@@ -0,0 +1,147 @@
1
+ require "test_helper"
2
+
3
+ class HelpersTest < Test::Unit::TestCase
4
+
5
+ def setup
6
+ @protector = ParamProtected::Protector.new
7
+ end
8
+
9
+ def test_normalize_params
10
+ params = @protector.send(:normalize_params, :something)
11
+ assert_equal({"something" => nil}, params)
12
+
13
+ params = @protector.send(:normalize_params, [:something, :else])
14
+ assert_equal({"something" => nil, "else" => nil}, params)
15
+
16
+ params = @protector.send(:normalize_params, :something => [:stuff, :blah])
17
+ assert_equal({"something" => {"stuff" => nil, "blah" => nil}}, params)
18
+
19
+ params = @protector.send(:normalize_params, :something => [:stuff, {:blah => :bleck}])
20
+ assert_equal({"something" => {"stuff" => nil, "blah" => {"bleck" => nil}}}, params)
21
+ end
22
+
23
+ def test_normalize_actions
24
+ actions = @protector.send(:normalize_actions, nil)
25
+ assert_equal [:except, nil], actions
26
+
27
+ actions = @protector.send(:normalize_actions, :only => :blah)
28
+ assert_equal [:only, "blah"], actions
29
+
30
+ actions = @protector.send(:normalize_actions, :only => [:blah, :bleck])
31
+ assert_equal [:only, "blah", "bleck"], actions
32
+
33
+ actions = @protector.send(:normalize_actions, :except => :blah)
34
+ assert_equal [:except, "blah"], actions
35
+
36
+ actions = @protector.send(:normalize_actions, :except => [:blah, :bleck])
37
+ assert_equal [:except, "blah", "bleck"], actions
38
+
39
+ assert_raises(ArgumentError){ @protector.send(:normalize_actions, :onlyy => :blah) }
40
+ assert_raises(ArgumentError){ @protector.send(:normalize_actions, :blah) }
41
+ assert_raises(ArgumentError){ @protector.send(:normalize_actions, :only => :something, :except => :something) }
42
+ end
43
+
44
+ def test_deep_copy
45
+ object_a = [Object.new, {:a => Object.new, :b => [Object.new, Object.new], :c => {:d => Object.new}}, [Object.new, Object.new]]
46
+ object_b = @protector.send(:deep_copy, object_a)
47
+
48
+
49
+ assert_not_equal object_a[0].object_id, object_b[0].object_id
50
+ assert_not_equal object_a[1].object_id, object_b[1].object_id
51
+ assert_not_equal object_a[2].object_id, object_b[2].object_id
52
+
53
+ assert_not_equal object_a[1][:a].object_id, object_b[1][:a].object_id
54
+ assert_not_equal object_a[1][:b].object_id, object_b[1][:b].object_id
55
+ assert_not_equal object_a[1][:b][0].object_id, object_b[1][:b][0].object_id
56
+ assert_not_equal object_a[1][:b][1].object_id, object_b[1][:b][1].object_id
57
+ assert_not_equal object_a[1][:c].object_id, object_b[1][:c].object_id
58
+ assert_not_equal object_a[1][:c][:d].object_id, object_b[1][:c][:d].object_id
59
+
60
+ assert_not_equal object_a[2][0].object_id, object_b[2][0].object_id
61
+ assert_not_equal object_a[2][1].object_id, object_b[2][1].object_id
62
+ end
63
+
64
+ def test_action_matches
65
+ assert @protector.send(:action_matches?, :only, ["blah", "bleck"], "blah")
66
+ assert @protector.send(:action_matches?, :only, ["blah", "bleck"], "bleck")
67
+ assert !@protector.send(:action_matches?, :only, ["blah", "bleck"], "not")
68
+
69
+ assert !@protector.send(:action_matches?, :except, ["blah", "bleck"], "blah")
70
+ assert !@protector.send(:action_matches?, :except, ["blah", "bleck"], "bleck")
71
+ assert @protector.send(:action_matches?, :except, ["blah", "bleck"], "not")
72
+
73
+ assert_raises(ArgumentError){ @protector.send(:action_matches?, :bad_scope, ["blah", "bleck"], "not") }
74
+ end
75
+
76
+ def test_do_param_accessible
77
+
78
+ accessible_params = { :account_id => nil,
79
+ :user_id => nil }
80
+ params = { :account_id => 123,
81
+ :user_id => 456,
82
+ :profile_id => 789 }
83
+ expected_results = { :account_id => 123,
84
+ :user_id => 456 }
85
+ assert_equal expected_results, @protector.send(:filter_params, accessible_params, params, ParamProtected::WHITELIST)
86
+
87
+ accessible_params = { :account_id => nil,
88
+ :user => nil }
89
+ params = { :account_id => 123,
90
+ :user => { :first_name => "christopher", :last_name => "bottaro" },
91
+ :profile_ids => [789, 987] }
92
+ expected_results = { :account_id => 123,
93
+ :user => { :first_name => "christopher", :last_name => "bottaro"} }
94
+ assert_equal expected_results, @protector.send(:filter_params, accessible_params, params, ParamProtected::WHITELIST)
95
+
96
+ accessible_params = { :account_id => nil,
97
+ :user => {:first_name => nil, :last_name => nil} }
98
+ params = { :account_id => 123,
99
+ :user => { :first_name => "christopher", :last_name => "bottaro", :middle_name => "james" },
100
+ :profile_ids => [789, 987] }
101
+ expected_results = { :account_id => 123,
102
+ :user => { :first_name => "christopher", :last_name => "bottaro"} }
103
+ assert_equal expected_results, @protector.send(:filter_params, accessible_params, params, ParamProtected::WHITELIST)
104
+
105
+ accessible_params = { :account_id => nil,
106
+ :user => {:name => {:first => nil, :last => nil}} }
107
+ params = { :account_id => 123,
108
+ :user => { :city => "Austin",
109
+ :name => {:first => "christopher", :last => "bottaro", :middle => "james"} },
110
+ :profile_ids => [789, 987] }
111
+ expected_results = { :account_id => 123,
112
+ :user => { :name => {:first => "christopher", :last => "bottaro"} } }
113
+ assert_equal expected_results, @protector.send(:filter_params, accessible_params, params, ParamProtected::WHITELIST)
114
+ end
115
+
116
+ def test_do_param_protected
117
+
118
+ protected_params = { :account_id => nil,
119
+ :user => nil }
120
+ params = { :account_id => 123,
121
+ :user => { :first_name => "christopher", :last_name => "bottaro" },
122
+ :profile_ids => [789, 987] }
123
+ expected_results = { :profile_ids => [789, 987] }
124
+ assert_equal expected_results, @protector.send(:filter_params, protected_params, params, ParamProtected::BLACKLIST)
125
+
126
+ protected_params = { :account_id => nil,
127
+ :user => {:middle_name => nil} }
128
+ params = { :account_id => 123,
129
+ :user => { :first_name => "christopher", :last_name => "bottaro", :middle_name => "james" },
130
+ :profile_ids => [789, 987] }
131
+ expected_results = { :user => {:first_name => "christopher", :last_name => "bottaro"},
132
+ :profile_ids => [789, 987] }
133
+ assert_equal expected_results, @protector.send(:filter_params, protected_params, params, ParamProtected::BLACKLIST)
134
+
135
+ protected_params = { :account_id => nil,
136
+ :user => {:name => {:middle => nil}} }
137
+ params = { :account_id => 123,
138
+ :user => { :city => "Austin",
139
+ :name => {:first => "christopher", :last => "bottaro", :middle => "james"} },
140
+ :profile_ids => [789, 987] }
141
+ expected_results = { :profile_ids => [789, 987],
142
+ :user => { :city => "Austin",
143
+ :name => {:first => "christopher", :last => "bottaro"} } }
144
+ assert_equal expected_results, @protector.send(:filter_params, protected_params, params, ParamProtected::BLACKLIST)
145
+ end
146
+
147
+ end
@@ -0,0 +1,51 @@
1
+ # Set the default environment to sqlite3's in_memory database
2
+ ENV['RAILS_ENV'] ||= 'in_memory'
3
+
4
+ # Load the Rails environment and testing framework
5
+ require "#{File.dirname(__FILE__)}/app_root/config/environment"
6
+ require 'test_help'
7
+ require "param_protected"
8
+
9
+ # Undo changes to RAILS_ENV
10
+ silence_warnings {RAILS_ENV = ENV['RAILS_ENV']}
11
+
12
+ # Run the migrations
13
+ ActiveRecord::Migrator.migrate("#{Rails.root}/db/migrate")
14
+
15
+ # Set default fixture loading properties
16
+ ActiveSupport::TestCase.class_eval do
17
+ self.use_transactional_fixtures = true
18
+ self.use_instantiated_fixtures = false
19
+ self.fixture_path = "#{File.dirname(__FILE__)}/fixtures"
20
+
21
+ fixtures :all
22
+ end
23
+
24
+ class ActionController::TestCase
25
+ PARAMS = {
26
+ "a" => "a",
27
+ "b" => "b",
28
+ "c" => "c",
29
+ "d" => "d",
30
+ "e" => "e",
31
+ "f" => "f",
32
+ "g" => "g",
33
+ "h" => { "a" => "a", "b" => "b", "c" => "c" },
34
+ }.freeze
35
+
36
+ def assert_params(params)
37
+ controller_params = @controller.params.keys.select{ |k| PARAMS.keys.include?(k.to_s) }
38
+ assert_equal params.sort, controller_params.sort
39
+ end
40
+
41
+ def params
42
+ @controller.params
43
+ end
44
+
45
+ def self.test_action(action_name, &block)
46
+ define_method("test_#{action_name}") do
47
+ get action_name, PARAMS.dup
48
+ instance_eval(&block)
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,22 @@
1
+ require "test_helper"
2
+
3
+ class UsersControllerTest < ActionController::TestCase
4
+ PARAMS = { :user => { :id => 123,
5
+ :name => { :first => "chris", :middle => "james", :last => "bottaro"},
6
+ :email => "cjbottaro@blah.com" },
7
+ :something => "something" }
8
+
9
+ EXPECTED_PARAMS = { "user" => { "name" => {"first" => "chris", "last" => "bottaro"},
10
+ "email" => "cjbottaro@blah.com" } }
11
+
12
+ def test_create
13
+ get :create, PARAMS
14
+ assert_equal EXPECTED_PARAMS, params
15
+ end
16
+
17
+ def test_update
18
+ get :update, PARAMS
19
+ assert_equal EXPECTED_PARAMS, params
20
+ end
21
+
22
+ end
data/uninstall.rb ADDED
@@ -0,0 +1 @@
1
+ # Uninstall hook code here
metadata ADDED
@@ -0,0 +1,107 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cjbottaro-param_protected
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Christopher J. Bottaro
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-09-12 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: Provides two class methods on ActiveController::Base that filter the params hash for that controller's actions. You can think of them as the controller analog of attr_protected and attr_accessible.
17
+ email: cjbottaro@alumni.cs.utexas.edu
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README.rdoc
24
+ files:
25
+ - CHANGELOG
26
+ - README.rdoc
27
+ - Rakefile
28
+ - VERSION
29
+ - init.rb
30
+ - install.rb
31
+ - lib/param_protected.rb
32
+ - lib/param_protected/constants.rb
33
+ - lib/param_protected/controller_modifications.rb
34
+ - lib/param_protected/meta_class.rb
35
+ - lib/param_protected/protector.rb
36
+ - param_protected.gemspec
37
+ - tasks/param_protected_tasks.rake
38
+ - test/accessible_except_test.rb
39
+ - test/accessible_only_test.rb
40
+ - test/app_root/app/controllers/accessible_except_controller.rb
41
+ - test/app_root/app/controllers/accessible_only_controller.rb
42
+ - test/app_root/app/controllers/application_controller.rb
43
+ - test/app_root/app/controllers/protected_controller.rb
44
+ - test/app_root/app/controllers/users_controller.rb
45
+ - test/app_root/config/boot.rb
46
+ - test/app_root/config/database.yml
47
+ - test/app_root/config/environment.rb
48
+ - test/app_root/config/environments/in_memory.rb
49
+ - test/app_root/config/environments/mysql.rb
50
+ - test/app_root/config/environments/postgresql.rb
51
+ - test/app_root/config/environments/sqlite.rb
52
+ - test/app_root/config/environments/sqlite3.rb
53
+ - test/app_root/config/routes.rb
54
+ - test/app_root/lib/console_with_fixtures.rb
55
+ - test/protected_controller_test.rb
56
+ - test/protector_test.rb
57
+ - test/test_helper.rb
58
+ - test/users_controller_test.rb
59
+ - uninstall.rb
60
+ has_rdoc: true
61
+ homepage: http://github.com/cjbottaro/param_protected
62
+ licenses:
63
+ post_install_message:
64
+ rdoc_options:
65
+ - --charset=UTF-8
66
+ require_paths:
67
+ - lib
68
+ required_ruby_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: "0"
73
+ version:
74
+ required_rubygems_version: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: "0"
79
+ version:
80
+ requirements: []
81
+
82
+ rubyforge_project:
83
+ rubygems_version: 1.3.5
84
+ signing_key:
85
+ specification_version: 3
86
+ summary: Filter unwanted parameters in your controllers and actions.
87
+ test_files:
88
+ - test/accessible_except_test.rb
89
+ - test/accessible_only_test.rb
90
+ - test/app_root/app/controllers/accessible_except_controller.rb
91
+ - test/app_root/app/controllers/accessible_only_controller.rb
92
+ - test/app_root/app/controllers/application_controller.rb
93
+ - test/app_root/app/controllers/protected_controller.rb
94
+ - test/app_root/app/controllers/users_controller.rb
95
+ - test/app_root/config/boot.rb
96
+ - test/app_root/config/environment.rb
97
+ - test/app_root/config/environments/in_memory.rb
98
+ - test/app_root/config/environments/mysql.rb
99
+ - test/app_root/config/environments/postgresql.rb
100
+ - test/app_root/config/environments/sqlite.rb
101
+ - test/app_root/config/environments/sqlite3.rb
102
+ - test/app_root/config/routes.rb
103
+ - test/app_root/lib/console_with_fixtures.rb
104
+ - test/protected_controller_test.rb
105
+ - test/protector_test.rb
106
+ - test/test_helper.rb
107
+ - test/users_controller_test.rb