param_protected 1.1.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.
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 +108 -0
@@ -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)
@@ -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
@@ -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'
@@ -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
@@ -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
@@ -0,0 +1 @@
1
+ # Uninstall hook code here
metadata ADDED
@@ -0,0 +1,108 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: 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-12-04 00:00:00 -06: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
+
64
+ post_install_message:
65
+ rdoc_options:
66
+ - --charset=UTF-8
67
+ require_paths:
68
+ - lib
69
+ required_ruby_version: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: "0"
74
+ version:
75
+ required_rubygems_version: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ version: "0"
80
+ version:
81
+ requirements: []
82
+
83
+ rubyforge_project:
84
+ rubygems_version: 1.3.5
85
+ signing_key:
86
+ specification_version: 3
87
+ summary: Filter unwanted parameters in your controllers and actions.
88
+ test_files:
89
+ - test/accessible_except_test.rb
90
+ - test/accessible_only_test.rb
91
+ - test/app_root/app/controllers/accessible_except_controller.rb
92
+ - test/app_root/app/controllers/accessible_only_controller.rb
93
+ - test/app_root/app/controllers/application_controller.rb
94
+ - test/app_root/app/controllers/protected_controller.rb
95
+ - test/app_root/app/controllers/users_controller.rb
96
+ - test/app_root/config/boot.rb
97
+ - test/app_root/config/environment.rb
98
+ - test/app_root/config/environments/in_memory.rb
99
+ - test/app_root/config/environments/mysql.rb
100
+ - test/app_root/config/environments/postgresql.rb
101
+ - test/app_root/config/environments/sqlite.rb
102
+ - test/app_root/config/environments/sqlite3.rb
103
+ - test/app_root/config/routes.rb
104
+ - test/app_root/lib/console_with_fixtures.rb
105
+ - test/protected_controller_test.rb
106
+ - test/protector_test.rb
107
+ - test/test_helper.rb
108
+ - test/users_controller_test.rb