inquisition 0.2 → 0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,4 +1,4 @@
1
- = inquisition
1
+ = Inquisition
2
2
 
3
3
  == Introduction
4
4
 
@@ -9,14 +9,21 @@ It keeps your strings heresy-free.
9
9
 
10
10
  Inquisition offers you three methods on Object:
11
11
 
12
- cleanse_attr *attributes
13
- cleanse_attr_reader *attributes
14
- cleanse_attr_writer *attributes
12
+ cleanse_attr *attributes, options
13
+ cleanse_attr_reader *attributes, options
14
+ cleanse_attr_writer *attributes, options
15
15
 
16
16
  These methods will wrap your getters and/or setters for an attribute through a
17
17
  HTML5 Sanitizer. This should help to protect against most kinds of cross site
18
18
  scripting attacks.
19
19
 
20
+ For example:
21
+
22
+ cleanse_attr :name, :allow => {:name => /(<strong>)/}
23
+
24
+ The above example will clean all values written to or read from the name
25
+ attribute, but will not remove strong tags.
26
+
20
27
  == Installation
21
28
 
22
29
  sudo gem install thumblemonks-inquisition
@@ -10,6 +10,14 @@ module Inquisition
10
10
  klass.extend(ClassMethods)
11
11
  end
12
12
 
13
+ def self.sanitize(value, allow)
14
+ if allow && match = Regexp.new(allow).match(value)
15
+ [HTML5libSanitize.sanitize_html(match.pre_match), match.to_a.first, self.sanitize(match.post_match, allow)].join
16
+ else
17
+ HTML5libSanitize.sanitize_html(value)
18
+ end
19
+ end
20
+
13
21
  module ClassMethods
14
22
  def sanitize_attribute(*attributes)
15
23
  sanitize_attribute_reader(*attributes)
@@ -17,34 +25,49 @@ module Inquisition
17
25
  end
18
26
 
19
27
  def sanitize_attribute_reader(*attributes)
20
- write_inheritable_attribute(:cleansed_attr_readers, attributes)
21
- class_inheritable_reader(:cleansed_attr_readers)
22
-
23
- define_method(:read_attribute_with_cleansing) do |attribute|
24
- value = read_attribute_without_cleansing(attribute)
25
- if cleansed_attr_readers.include?(attribute.to_sym) && !value.blank?
26
- HTML5libSanitize.sanitize_html(value)
27
- else
28
- value
28
+ options = attributes.last.is_a?(::Hash) ? attributes.pop : {}
29
+ if respond_to?(:cleansed_attr_readers)
30
+ write_inheritable_attribute(:cleansed_attr_readers, cleansed_attr_readers.concat(attributes))
31
+ write_inheritable_attribute(:cleansed_attr_reader_options, cleansed_attr_reader_options.merge(options))
32
+ else
33
+ write_inheritable_attribute(:cleansed_attr_readers, attributes)
34
+ write_inheritable_attribute(:cleansed_attr_reader_options, options)
35
+ class_inheritable_reader(:cleansed_attr_readers)
36
+ class_inheritable_reader(:cleansed_attr_reader_options)
37
+
38
+ define_method(:read_attribute_with_cleansing) do |attribute|
39
+ value = read_attribute_without_cleansing(attribute)
40
+ if cleansed_attr_readers.include?(attribute.to_sym) && !value.blank?
41
+ Inquisition.sanitize(value,cleansed_attr_reader_options[:allow][attribute.to_sym])
42
+ else
43
+ value
44
+ end
29
45
  end
46
+ alias_method_chain :read_attribute, :cleansing
30
47
  end
31
- alias_method_chain :read_attribute, :cleansing
32
48
 
33
49
  attributes.each { |attr| define_method(attr.to_sym) { read_attribute(attr.to_sym) } }
34
50
  end
35
51
 
36
52
  def sanitize_attribute_writer(*attributes)
37
- write_inheritable_attribute(:cleansed_attr_writers, attributes)
38
- class_inheritable_reader(:cleansed_attr_writers)
53
+ options = attributes.last.is_a?(::Hash) ? attributes.pop : {}
54
+ if respond_to?(:cleansed_attr_writers)
55
+ write_inheritable_attribute(:cleansed_attr_writers, cleansed_attr_writers.concat(attributes))
56
+ write_inheritable_attribute(:cleansed_attr_writer_options, cleansed_attr_writer_options.merge(options))
57
+ else
58
+ write_inheritable_attribute(:cleansed_attr_writers, attributes)
59
+ write_inheritable_attribute(:cleansed_attr_writer_options, options)
60
+ class_inheritable_reader(:cleansed_attr_writers)
61
+ class_inheritable_reader(:cleansed_attr_writer_options)
39
62
 
40
- define_method(:write_attribute_with_cleansing) do |attribute, value|
41
- if cleansed_attr_writers.include?(attribute.to_sym) && !value.blank?
42
- value = HTML5libSanitize.sanitize_html(value)
63
+ define_method(:write_attribute_with_cleansing) do |attribute, value|
64
+ if cleansed_attr_writers.include?(attribute.to_sym) && !value.blank?
65
+ Inquisition.sanitize(value,cleansed_attr_writer_options[:allow][attribute.to_sym])
66
+ end
67
+ write_attribute_without_cleansing(attribute, value)
43
68
  end
44
-
45
- write_attribute_without_cleansing(attribute, value)
69
+ alias_method_chain :write_attribute, :cleansing
46
70
  end
47
- alias_method_chain :write_attribute, :cleansing
48
71
  end
49
72
  end #Class Methods
50
73
  end #Inquisition
@@ -47,4 +47,41 @@ class InquisitionTest < Test::Unit::TestCase
47
47
  assert_equal nil, @whisky.name
48
48
  end
49
49
  end
50
+
51
+ context "allowing a single character" do
52
+ setup do
53
+ @dumb_phrase = "Central Time (US & Canada)"
54
+ @clean_dumb = "Central Time (US &amp; Canada)"
55
+ @whisky = Whisky.new(:description => @dumb_phrase, :name => @dumb_phrase)
56
+ end
57
+
58
+ should "allow ampersands in the description" do
59
+ assert_equal @dumb_phrase, @whisky.description
60
+ end
61
+
62
+ should "not allow ampersands in the name" do
63
+ assert_equal @clean_dumb, @whisky.name
64
+ end
65
+ end
66
+
67
+ context "allowing a regexp" do
68
+ setup do
69
+ @dumb_phrase = "<buttes> hey guy, I think <buttes> about <buttes>, because i have no clear opinion on <buttes>"
70
+ @clean_phrase = "&lt;buttes&gt; hey guy, I think &lt;buttes&gt; about &lt;buttes&gt;, because i have no clear opinion on &lt;buttes&gt;"
71
+ @whisky = Whisky.new(:measure => @dumb_phrase, :name => @dumb_phrase)
72
+ end
73
+
74
+ should "allow the regexp'd phrase in the measure" do
75
+ assert_equal @dumb_phrase, @whisky.measure
76
+ end
77
+
78
+ should "not allow the regexp'd phrase in the name" do
79
+ assert_equal @clean_phrase, @whisky.name
80
+ end
81
+
82
+ should "still clean non-matched parts" do
83
+ @whisky.measure = "<script>alert('Cragganmore')</script>"
84
+ assert_equal "&lt;script&gt;alert('Cragganmore')&lt;/script&gt;", @whisky.measure
85
+ end
86
+ end
50
87
  end
@@ -3,7 +3,7 @@ ActiveRecord::Base.establish_connection :adapter => 'sqlite3', :database => File
3
3
  class CreateSchema < ActiveRecord::Migration
4
4
  def self.up
5
5
  create_table :whiskies, :force => true do |t|
6
- t.string :name, :origin, :description
6
+ t.string :name, :origin, :description, :measure
7
7
  t.integer :abv
8
8
  end
9
9
  create_table :animals, :force => true do |t|
@@ -21,7 +21,7 @@ class Animal < ActiveRecord::Base
21
21
  end
22
22
 
23
23
  class Whisky < ActiveRecord::Base
24
- sanitize_attribute :name, :description
24
+ sanitize_attribute :name, :description, :measure, :allow => { :description => "&", :measure => /(<buttes>)/ }
25
25
 
26
26
  def drink
27
27
  "You quaffed #{description}"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: inquisition
3
3
  version: !ruby/object:Gem::Version
4
- version: "0.2"
4
+ version: "0.3"
5
5
  platform: ruby
6
6
  authors:
7
7
  - toothrot
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-07-06 00:00:00 -05:00
12
+ date: 2009-11-11 00:00:00 -06:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -69,7 +69,7 @@ requirements: []
69
69
  rubyforge_project:
70
70
  rubygems_version: 1.3.5
71
71
  signing_key:
72
- specification_version: 2
72
+ specification_version: 3
73
73
  summary: Inquisition is a fancy way to protect your ActiveRecord attributes from XSS
74
74
  test_files: []
75
75