clean_room 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,4 @@
1
1
  require "clean_room/air_lock"
2
- require "clean_room/dsl"
3
2
  require "clean_room/exceptions"
4
3
  require "clean_room/filter"
5
4
  require "clean_room/version"
@@ -1,29 +1,61 @@
1
1
  module CleanRoom
2
2
  module AirLock
3
- class Parameters
3
+ module Parameters
4
+ def self.included(base)
5
+ base.extend ClassMethods
6
+ base.clean_room_rules = {}
7
+ end
8
+
9
+ def params
10
+ @_params ||= HashWithIndifferentAccess.new(CleanRoom::Filter.clean(request.parameters, nested_rules: self.class.clean_room_rules))
11
+ end
12
+
13
+ def params=(val)
14
+ @_params = val.is_a?(Hash) ? HashWithIndifferentAccess.new(CleanRoom::Filter.clean(val, nested_rules: self.class.clean_room_rules)) : val
15
+ end
16
+
4
17
  class << self
5
- def activate
6
- ActionController::Base.send :include, CleanParameters
18
+ def clean_room_rules(rules = {})
19
+ clean_room_rules = rules
7
20
  end
8
21
  end
9
22
  end
10
23
 
11
- class ModelBasedFilter
12
- class << self
13
- def filter(parameters)
14
- # TODO: check the parameter names against the model sanitization rules, when no rules found do a 'normal' sanitization
15
- HashWithIndifferentAccess.new(CleanRoom::Filter.clean(parameters))
24
+ module Model
25
+ def self.included(base)
26
+ base.extend ClassMethods
27
+ base.sanitizable_attributes = {}
28
+
29
+ if base.respond_to? :before_validate
30
+ base.before_validate :sanitize_attributes
16
31
  end
17
32
  end
18
- end
19
33
 
20
- module CleanParameters
21
- def params
22
- @_params ||= ModelBasedFilter.filter(request.parameters)
34
+ def sanitize_attributes
35
+ self.class.sanitizable_attributes.each do |name, rules|
36
+ sanitize_attribute name, rules
37
+ end
23
38
  end
24
39
 
25
- def params=(val)
26
- @_params = val.is_a?(Hash) ? ModelBasedFilter.filter(val) : val
40
+ def sanitize_attribute(name, rules = {})
41
+ current_value = self.send(name)
42
+ cleaned_value = Filter.clean(current_value, rules)
43
+
44
+ raise Exceptions::Contaminated.new("#{name} contained unacceptable data") if rules[:raise] && (current_value != cleaned_value)
45
+ self.send("#{name}=".to_sym, cleaned_value)
46
+ end
47
+
48
+ module ClassMethods
49
+ attr_accessor :sanitizable_attributes
50
+
51
+ def sanitize_attribute(name, rules = {})
52
+ name = name.to_sym
53
+ if instance_methods.include?(name) && instance_methods.include?("#{name}=".to_sym)
54
+ sanitizable_attributes[name] = rules
55
+ else
56
+ raise Exceptions::InvalidAttribute.new("#{self.class} does not respond to '#{name}(=)'")
57
+ end
58
+ end
27
59
  end
28
60
  end
29
61
  end
@@ -7,54 +7,59 @@ module CleanRoom
7
7
  class << self
8
8
  include SanitizeUrl
9
9
 
10
- def clean(dirty_value, options = {})
11
- determine_and_filter(dirty_value, options)
10
+ def clean(dirty_value, rules = {})
11
+ determine_and_filter(dirty_value, rules)
12
12
  end
13
13
 
14
14
  private
15
15
 
16
- def determine_and_filter(dirty_value, options)
16
+ def determine_and_filter(dirty_value, rules)
17
+ nested_rules = rules[:nested_rules] || {}
17
18
 
18
19
  case dirty_value
19
20
  when Array
20
- dirty_value.map{ |dv| determine_and_filter(dv, options) }
21
+ dirty_value.map{ |dv| determine_and_filter(dv, rules) }
21
22
  when Hash
22
- Hash[dirty_value.map {|k,dv| [determine_and_filter(k, allow: (k.is_a?(Symbol) ? :symbol : :string)),determine_and_filter(dv, options)]}]
23
+ Hash[dirty_value.map {|k,dv| [determine_and_filter(k, allow: (k.is_a?(Symbol) ? :symbol : :string)),determine_and_filter(dv, nested_rules[k] ? nested_rules[k] : rules)]}]
23
24
  when Fixnum
24
25
  dirty_value
25
26
  when Symbol
26
- filter(dirty_value, options).to_sym
27
+ filter(dirty_value, rule: :symbol)
27
28
  when FalseClass
28
29
  false
29
30
  when NilClass
30
31
  nil
31
32
  else
32
- filter(dirty_value, options)
33
+ filter(dirty_value, rules)
33
34
  end
34
35
  end
35
36
 
36
- def filter(dirty_value, options)
37
+ def filter(dirty_value, rules)
37
38
  dirty_value = dirty_value.to_s
38
- case (options[:allow] || :plain_text)
39
+ intermediate_value = case (rules[:rule] || :plain_text)
39
40
  when :html
40
- Sanitize.clean(dirty_value, Sanitize::Config::RELAXED)
41
+ sql_injection(Sanitize.clean(dirty_value, Sanitize::Config::RELAXED))
41
42
  when :simple_html
42
- Sanitize.clean(dirty_value, Sanitize::Config::BASIC)
43
+ sql_injection(Sanitize.clean(dirty_value, Sanitize::Config::BASIC))
43
44
  when :strict
44
- regex = /[^#{options[:character_class] || "a-zA-Z0-9 "}]/
45
+ regex = /[^#{rules[:character_class] || "a-zA-Z0-9 "}]/
45
46
  Sanitize.clean(dirty_value).gsub(regex, "")
46
47
  when :url
47
- sanitize_url(dirty_value)
48
+ sql_injection(sanitize_url(dirty_value))
48
49
  when :symbol
49
- Sanitize.clean(dirty_value).gsub(/[^a-zA-Z0-9]/, "").to_sym
50
+ sql_injection(Sanitize.clean(dirty_value)).gsub(/[^a-zA-Z0-9]/, "").to_sym
50
51
  when :fixnum
51
52
  Sanitize.clean(dirty_value).gsub(/[^0-9]\.\,/, "").gsub(",",".").to_i
52
53
  when :float
53
54
  Sanitize.clean(dirty_value).gsub(/[^0-9\.\,]/, "").gsub(",",".").to_f
54
55
  else
55
- Sanitize.clean(dirty_value)
56
+ sql_injection(Sanitize.clean(dirty_value))
56
57
  end
57
58
  end
59
+
60
+ def sql_injection(dirty_value)
61
+ dirty_value.gsub(/(\'|\-\-|\#)[\s;\(\)]*(AND|OR|SELECT|DROP|INSERT|UPDATE|DELETE|UNION).*/, "")
62
+ end
58
63
  end
59
64
  end
60
- end
65
+ end
@@ -1,3 +1,3 @@
1
1
  module CleanRoom
2
- VERSION = "0.2.0"
2
+ VERSION = "0.2.1"
3
3
  end
@@ -4,11 +4,11 @@ class CleanRoomTest < MiniTest::Unit::TestCase
4
4
  def test_can_be_included
5
5
 
6
6
  test_class = Class.new do
7
- include CleanRoom::DSL
7
+ include CleanRoom::AirLock::Model
8
8
  end
9
9
 
10
10
  test_class = Class.new do
11
- include CleanRoom::DSL
11
+ include CleanRoom::AirLock::Model
12
12
  attr_accessor :field1
13
13
 
14
14
  sanitize_attribute :field1
@@ -16,7 +16,7 @@ class CleanRoomTest < MiniTest::Unit::TestCase
16
16
 
17
17
  assert_raises CleanRoom::Exceptions::InvalidAttribute do
18
18
  test_class = Class.new do
19
- include CleanRoom::DSL
19
+ include CleanRoom::AirLock::Model
20
20
 
21
21
  sanitize_attribute :field1
22
22
  end
@@ -38,8 +38,17 @@ class CleanRoomTest < MiniTest::Unit::TestCase
38
38
  assert_equal [{"test1" => "test3"},"test2"], CleanRoom::Filter.clean([{"<b>test1</b>" => "<b>test3</b>"},"<b>test2</b>"])
39
39
  assert_equal [{test1: "test3"},"test2"], CleanRoom::Filter.clean([{:"<b>te * st1</b>" => "<b>test3</b>"},"<b>test2</b>"])
40
40
  assert_equal ["123.", "456.3", "789.8"], CleanRoom::Filter.clean(["<b>123.</b>","456.3", 789.8])
41
- assert_equal [123, 456, 789], CleanRoom::Filter.clean(["<b>123.</b>","456.3", 789.8], allow: :fixnum)
42
- assert_equal [123.0, 456.3, 789.8], CleanRoom::Filter.clean(["<b>123.</b>","456.3", 789.8], allow: :float)
41
+ assert_equal [123, 456, 789], CleanRoom::Filter.clean(["<b>123.</b>","456.3", 789.8], rule: :fixnum)
42
+ assert_equal [123.0, 456.3, 789.8], CleanRoom::Filter.clean(["<b>123.</b>","456.3", 789.8], rule: :float)
43
+
44
+ # SQL injection
45
+ assert_equal "test", CleanRoom::Filter.clean("test' ; DROP TABLE ")
46
+ assert_equal "test", CleanRoom::Filter.clean("test'DROP TABLE `sdfdsf`")
47
+ assert_equal "", CleanRoom::Filter.clean("'DROP TABLE `sdfdsf`")
48
+
49
+ # nested rules
50
+ assert_equal({"test" => {"integer" => "4324.1"}}, CleanRoom::Filter.clean({"test" => {"integer" => "4324.1"}}))
51
+ assert_equal({"test" => {"integer" => 4324}}, CleanRoom::Filter.clean({"test" => {"integer" => "4324.1"}}, nested_rules: {"integer" => {rule: :fixnum}}))
43
52
  end
44
53
 
45
54
  def attribute_test(field, value_in, value_out)
@@ -51,15 +60,15 @@ class CleanRoomTest < MiniTest::Unit::TestCase
51
60
 
52
61
  def object_generator
53
62
  test_class = Class.new do
54
- include CleanRoom::DSL
63
+ include CleanRoom::AirLock::Model
55
64
  attr_accessor :normal, :strict, :very_strict, :simple_html, :html, :url
56
65
 
57
66
  sanitize_attribute :normal
58
- sanitize_attribute :strict, allow: :strict
59
- sanitize_attribute :very_strict, allow: :strict, character_class: "a-z"
60
- sanitize_attribute :simple_html, allow: :simple_html
61
- sanitize_attribute :html, allow: :html
62
- sanitize_attribute :url, allow: :url
67
+ sanitize_attribute :strict, rule: :strict
68
+ sanitize_attribute :very_strict, rule: :strict, character_class: "a-z"
69
+ sanitize_attribute :simple_html, rule: :simple_html
70
+ sanitize_attribute :html, rule: :html
71
+ sanitize_attribute :url, rule: :url
63
72
  end
64
73
 
65
74
  test_class.new
@@ -72,7 +81,7 @@ class CleanRoomTest < MiniTest::Unit::TestCase
72
81
  def self.before_validate(method_name)
73
82
  puts method_name
74
83
  end
75
- include CleanRoom::DSL
84
+ include CleanRoom::AirLock::Model
76
85
  end
77
86
  end
78
87
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: clean_room
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-06-19 00:00:00.000000000 Z
12
+ date: 2012-06-20 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: sanitize
16
- requirement: &70156494356660 !ruby/object:Gem::Requirement
16
+ requirement: &70210935928440 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: 2.0.0
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70156494356660
24
+ version_requirements: *70210935928440
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: sanitize-url
27
- requirement: &70156494356120 !ruby/object:Gem::Requirement
27
+ requirement: &70210935927900 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: 0.1.4
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *70156494356120
35
+ version_requirements: *70210935927900
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: pry
38
- requirement: &70156494355660 !ruby/object:Gem::Requirement
38
+ requirement: &70210935927440 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,7 +43,7 @@ dependencies:
43
43
  version: '0'
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *70156494355660
46
+ version_requirements: *70210935927440
47
47
  description: Work in progress, this will be a generic attribute sanitizer which can
48
48
  be used for sanitizing models and other objects holding data
49
49
  email:
@@ -60,7 +60,6 @@ files:
60
60
  - clean_room.gemspec
61
61
  - lib/clean_room.rb
62
62
  - lib/clean_room/air_lock.rb
63
- - lib/clean_room/dsl.rb
64
63
  - lib/clean_room/exceptions.rb
65
64
  - lib/clean_room/filter.rb
66
65
  - lib/clean_room/version.rb
@@ -1,40 +0,0 @@
1
- module CleanRoom
2
- module DSL
3
-
4
- def self.included(base)
5
- base.extend ClassMethods
6
- base.sanitizable_attributes = {}
7
-
8
- if base.respond_to? :before_validate
9
- base.before_validate :sanitize_attributes
10
- end
11
- end
12
-
13
- def sanitize_attributes
14
- self.class.sanitizable_attributes.each do |name, options|
15
- sanitize_attribute name, options
16
- end
17
- end
18
-
19
- def sanitize_attribute(name, options = {})
20
- current_value = self.send(name)
21
- cleaned_value = Filter.clean(current_value, options)
22
-
23
- raise Exceptions::Contaminated.new("#{name} contained unacceptable data") if options[:raise] && (current_value != cleaned_value)
24
- self.send("#{name}=".to_sym, cleaned_value)
25
- end
26
-
27
- module ClassMethods
28
- attr_accessor :sanitizable_attributes
29
-
30
- def sanitize_attribute(name, options = {})
31
- name = name.to_sym
32
- if instance_methods.include?(name) && instance_methods.include?("#{name}=".to_sym)
33
- sanitizable_attributes[name] = options
34
- else
35
- raise Exceptions::InvalidAttribute.new("#{self.class} does not respond to '#{name}(=)'")
36
- end
37
- end
38
- end
39
- end
40
- end