acts_as_sanitiled 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +2 -0
- data/LICENSE +18 -0
- data/README.rdoc +141 -0
- data/Rakefile +62 -0
- data/VERSION +1 -0
- data/lib/acts_as_sanitiled.rb +111 -0
- data/rails/init.rb +1 -0
- data/spec/sanitiled_spec.rb +119 -0
- data/spec/spec_helper.rb +43 -0
- metadata +114 -0
data/CHANGELOG
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
Copyright (c) 2006,2009 Chris Wanstrath, Gabe da Silveira
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
4
|
+
this software and associated documentation files (the "Software"), to deal in
|
5
|
+
the Software without restriction, including without limitation the rights to
|
6
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
7
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
8
|
+
subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
11
|
+
copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
15
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
16
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
17
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
18
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,141 @@
|
|
1
|
+
= Acts as Sanitiled
|
2
|
+
|
3
|
+
This plugin, based on Chris Wanstrath's venerable acts_as_textiled, extends the automatic textiling functionality to sanitization as well using as its basis Ryan Grove's powerful yet simple Sanitize gem.
|
4
|
+
|
5
|
+
The reasoning behind this approach is simple. Filtering input before it is saved to the database (as xss_terminate and many other popular plugins do) often fails to preserve user intent. On the other hand, filtering output at the template level is error prone, and you are begging to get pwned. Short of some sort of taint mode (which Rails 3 will have!), I believe the method employed by acts_as_textiled is the next best thing: you get safe output by default, but input is never corrupted.
|
6
|
+
|
7
|
+
== Requirements
|
8
|
+
|
9
|
+
* Sanitize >1.1.0 (prior versions had a whitespace issue)
|
10
|
+
* RedCloth (for Textile support)
|
11
|
+
* ActiveRecord (tested on 2.3.4)
|
12
|
+
|
13
|
+
== Changes from acts_as_textiled
|
14
|
+
|
15
|
+
acts_as_sanitiled mostly maintains the API, but one noticeable difference is that it needs to expose the Sanitize config. Therefore acts_as_textiled use of a hash to provide per-column RedCloth configuration had to be replaced with Sanitize config. RedCloth options can still be passed as an array that applies to all fields listed.
|
16
|
+
|
17
|
+
The other big change is that acts_as_sanitiled uses Sanitize which outputs utf8 rather than HTML entities. For my own purposes this is preferable anyway, but it might give someone a few headaches getting encoding issues. My advice: take your lumps now and figure out your encoding pipelines.
|
18
|
+
|
19
|
+
== Usage
|
20
|
+
|
21
|
+
class Story < ActiveRecord::Base
|
22
|
+
acts_as_sanitiled :body_text, :description
|
23
|
+
end
|
24
|
+
|
25
|
+
>> story = Story.find(3)
|
26
|
+
=> #<Story:0x245fed8 ... >
|
27
|
+
|
28
|
+
>> story.description
|
29
|
+
=> "<p>This is <strong>cool</strong>.</p>"
|
30
|
+
|
31
|
+
>> story.description(:source)
|
32
|
+
=> "This is *cool*."
|
33
|
+
|
34
|
+
>> story.description(:plain)
|
35
|
+
=> "This is cool."
|
36
|
+
|
37
|
+
>> story.description = "I _know_!"
|
38
|
+
=> "I _know_!"
|
39
|
+
|
40
|
+
>> story.save
|
41
|
+
=> true
|
42
|
+
|
43
|
+
>> story.description
|
44
|
+
=> "<p>I <em>know</em>!</p>"
|
45
|
+
|
46
|
+
>> story.textiled = false
|
47
|
+
=> false
|
48
|
+
|
49
|
+
>> story.description
|
50
|
+
=> "I _know_!"
|
51
|
+
|
52
|
+
>> story.textiled = true
|
53
|
+
=> true
|
54
|
+
|
55
|
+
>> story.description
|
56
|
+
=> "<p>I <em>know</em>!</p>"
|
57
|
+
|
58
|
+
== Different Modes
|
59
|
+
|
60
|
+
Sanitize supports a detailed configuration hash describing what HTML is allowed (among
|
61
|
+
other things). This can be passed at the end of the declaration. See the Sanitize docs
|
62
|
+
for more information.
|
63
|
+
|
64
|
+
class Story < ActiveRecord::Base
|
65
|
+
acts_as_sanitiled :body_text, :elements => ['em','strong','div'], :attributes => {'div' => ['class','id']}
|
66
|
+
end
|
67
|
+
|
68
|
+
RedCloth supports different modes, such as :lite_mode. To use a mode on
|
69
|
+
a specific attribute simply pass one or more options in an array after the field names. Like so:
|
70
|
+
|
71
|
+
class Story < ActiveRecord::Base
|
72
|
+
acts_as_sanitiled :body_text, :description, [ :lite_mode ]
|
73
|
+
end
|
74
|
+
|
75
|
+
Of course you can combine them as well:
|
76
|
+
|
77
|
+
class Story < ActiveRecord::Base
|
78
|
+
acts_as_sanitiled :body_text, :description, [ :lite_mode ], :elements => ['a'], :add_attributes => {'a' => {'rel' => 'nofollow'}}
|
79
|
+
end
|
80
|
+
|
81
|
+
Suppose you want to sanitize but not textilize:
|
82
|
+
|
83
|
+
class Story < ActiveRecord::Base
|
84
|
+
acts_as_sanitized :body_text, :elements => ['br', 'p']
|
85
|
+
end
|
86
|
+
|
87
|
+
Or vice-versa:
|
88
|
+
|
89
|
+
class Story < ActiveRecord::Base
|
90
|
+
acts_as_textilized :body_text, [ :lite_mode ]
|
91
|
+
end
|
92
|
+
|
93
|
+
Get it? Now let's say you have an admin tool and you want the text to be displayed
|
94
|
+
in the text boxes / fields as plaintext. Do you have to change all your views?
|
95
|
+
|
96
|
+
Hell no.
|
97
|
+
|
98
|
+
== form_for
|
99
|
+
|
100
|
+
Are you using form_for? If you are, you don't have to change any code at all.
|
101
|
+
|
102
|
+
<% form_for :story, @story do |f| %>
|
103
|
+
Description: <br/> <%= f.text_field :description %>
|
104
|
+
<% end %>
|
105
|
+
|
106
|
+
You'll see the Textile plaintext in the text field. It Just Works.
|
107
|
+
|
108
|
+
== form tags
|
109
|
+
|
110
|
+
If you're being a bit unconvential, no worries. You can still get at your
|
111
|
+
raw Textile like so:
|
112
|
+
|
113
|
+
Description: <br/> <%= text_field_tag :description, @story.description(:source) %>
|
114
|
+
|
115
|
+
And there's always object.textiled = false, as demo'd above.
|
116
|
+
|
117
|
+
== Pre-fetching
|
118
|
+
|
119
|
+
acts_as_sanitiled locally caches rendered HTML once the attribute in question has
|
120
|
+
been requested. Obviously this doesn't bode well for marshalling or caching.
|
121
|
+
|
122
|
+
If you need to force your object to build and cache HTML for all textiled attributes,
|
123
|
+
call the +textilize+ method on your object.
|
124
|
+
|
125
|
+
If you're real crazy you can even do something like this:
|
126
|
+
|
127
|
+
class Story < ActiveRecord::Base
|
128
|
+
acts_as_sanitiled :body_text, :description
|
129
|
+
|
130
|
+
def after_find
|
131
|
+
textilize
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
All your Textile will now be ready to go in spiffy HTML format. But you probably
|
136
|
+
won't need to do this.
|
137
|
+
|
138
|
+
Enjoy.
|
139
|
+
|
140
|
+
* By Chris Wanstrath [ chris[at]ozmm[dot]org ]
|
141
|
+
* Butchered and Sanitized by Gabe da Silveira [ gabe[at]websaviour[dot]com ]
|
data/Rakefile
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "acts_as_sanitiled"
|
8
|
+
gem.summary = %Q{Automatically textiles and/or sanitizes ActiveRecord columns}
|
9
|
+
gem.description = %Q{A modernized version of Chris Wansthrath's venerable acts_as_textiled. It automatically textiles and then sanitizes columns to your specification. Ryan Grove's excellent Sanitize gem with nokogiri provides the backend for speedy and robust filtering of your output in order to: restrict Textile to a subset of HTML, guarantee well-formedness, and of course prevent XSS.}
|
10
|
+
gem.email = "gabe@websaviour.com"
|
11
|
+
gem.homepage = "http://github.com/dasil003/acts_as_sanitiled"
|
12
|
+
gem.authors = ["Gabe da Silveira"]
|
13
|
+
|
14
|
+
gem.add_dependency('nokogiri', '~> 1.3.3')
|
15
|
+
gem.add_dependency('sanitize', '~> 1.1.0')
|
16
|
+
gem.add_dependency('RedCloth')
|
17
|
+
|
18
|
+
gem.add_development_dependency "bacon"
|
19
|
+
gem.add_development_dependency "activesupport"
|
20
|
+
end
|
21
|
+
Jeweler::GemcutterTasks.new
|
22
|
+
rescue LoadError
|
23
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
24
|
+
end
|
25
|
+
|
26
|
+
require 'rake/testtask'
|
27
|
+
Rake::TestTask.new(:spec) do |spec|
|
28
|
+
spec.libs << 'lib' << 'spec'
|
29
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
30
|
+
spec.verbose = true
|
31
|
+
end
|
32
|
+
|
33
|
+
begin
|
34
|
+
require 'rcov/rcovtask'
|
35
|
+
Rcov::RcovTask.new do |spec|
|
36
|
+
spec.libs << 'spec'
|
37
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
38
|
+
spec.verbose = true
|
39
|
+
end
|
40
|
+
rescue LoadError
|
41
|
+
task :rcov do
|
42
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
task :spec => :check_dependencies
|
47
|
+
|
48
|
+
task :default => :spec
|
49
|
+
|
50
|
+
require 'rake/rdoctask'
|
51
|
+
Rake::RDocTask.new do |rdoc|
|
52
|
+
if File.exist?('VERSION')
|
53
|
+
version = File.read('VERSION')
|
54
|
+
else
|
55
|
+
version = ""
|
56
|
+
end
|
57
|
+
|
58
|
+
rdoc.rdoc_dir = 'rdoc'
|
59
|
+
rdoc.title = "acts_as_sanitiled #{version}"
|
60
|
+
rdoc.rdoc_files.include('README*')
|
61
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
62
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.0.0
|
@@ -0,0 +1,111 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'sanitize'
|
3
|
+
require 'RedCloth'
|
4
|
+
|
5
|
+
module ActsAsSanitiled #:nodoc: all
|
6
|
+
def self.included(klass)
|
7
|
+
klass.extend ClassMethods
|
8
|
+
end
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
def acts_as_textiled(*attributes)
|
12
|
+
raise "only acts_as_sanitized or acts_as_sanitiled can take an options hash" if attributes.last.is_a?(Hash)
|
13
|
+
|
14
|
+
attributes << {:skip_sanitize => true}
|
15
|
+
acts_as_sanitiled(*attributes)
|
16
|
+
end
|
17
|
+
|
18
|
+
def acts_as_sanitized(*attributes)
|
19
|
+
options = attributes.last.is_a?(Hash) ? attributes.pop : {}
|
20
|
+
options[:skip_textile] = true
|
21
|
+
attributes << options
|
22
|
+
acts_as_sanitiled(*attributes)
|
23
|
+
end
|
24
|
+
|
25
|
+
def acts_as_sanitiled(*attributes)
|
26
|
+
@textiled_attributes ||= []
|
27
|
+
|
28
|
+
@textiled_unicode = String.new.respond_to? :chars
|
29
|
+
|
30
|
+
options = attributes.last.is_a?(Hash) ? attributes.pop : {}
|
31
|
+
skip_textile = options.delete(:skip_textile)
|
32
|
+
skip_sanitize = options.delete(:skip_sanitize)
|
33
|
+
|
34
|
+
raise 'Both textile and sanitize were skipped' if skip_textile && skip_sanitize
|
35
|
+
|
36
|
+
sanitize_options = options.empty? ? Sanitize::Config::RELAXED : options
|
37
|
+
red_cloth_options = attributes.last && attributes.last.is_a?(Array) ? attributes.pop : []
|
38
|
+
|
39
|
+
raise 'No attributes were specified to filter' if attributes.empty?
|
40
|
+
|
41
|
+
type_options = %w( plain source )
|
42
|
+
|
43
|
+
attributes.each do |attribute|
|
44
|
+
define_method(attribute) do |*type|
|
45
|
+
type = type.first
|
46
|
+
|
47
|
+
if type.nil? && self[attribute]
|
48
|
+
if textiled[attribute.to_s].nil?
|
49
|
+
string = self[attribute]
|
50
|
+
string = RedCloth.new(string, red_cloth_options).to_html unless skip_textile
|
51
|
+
string = Sanitize.clean(string, sanitize_options) unless skip_sanitize
|
52
|
+
textiled[attribute.to_s] = string
|
53
|
+
end
|
54
|
+
textiled[attribute.to_s]
|
55
|
+
elsif type.nil? && self[attribute].nil?
|
56
|
+
nil
|
57
|
+
elsif type_options.include?(type.to_s)
|
58
|
+
send("#{attribute}_#{type}")
|
59
|
+
else
|
60
|
+
raise "I don't understand the `#{type}' option. Try #{type_options.join(' or ')}."
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
define_method("#{attribute}_plain", proc { strip_html(__send__(attribute)) if __send__(attribute) } )
|
65
|
+
define_method("#{attribute}_source", proc { __send__("#{attribute}_before_type_cast") } )
|
66
|
+
|
67
|
+
@textiled_attributes << attribute
|
68
|
+
end
|
69
|
+
|
70
|
+
include ActsAsSanitiled::InstanceMethods
|
71
|
+
end
|
72
|
+
|
73
|
+
def textiled_attributes
|
74
|
+
Array(@textiled_attributes)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
module InstanceMethods
|
79
|
+
def textiled
|
80
|
+
textiled? ? (@textiled ||= {}) : @attributes.dup
|
81
|
+
end
|
82
|
+
|
83
|
+
def textiled?
|
84
|
+
@is_textiled != false
|
85
|
+
end
|
86
|
+
|
87
|
+
def textiled=(bool)
|
88
|
+
@is_textiled = !!bool
|
89
|
+
end
|
90
|
+
|
91
|
+
def textilize
|
92
|
+
self.class.textiled_attributes.each { |attr| __send__(attr) }
|
93
|
+
end
|
94
|
+
|
95
|
+
def reload
|
96
|
+
textiled.clear
|
97
|
+
super
|
98
|
+
end
|
99
|
+
|
100
|
+
def write_attribute(attr_name, value)
|
101
|
+
textiled[attr_name.to_s] = nil
|
102
|
+
super
|
103
|
+
end
|
104
|
+
|
105
|
+
private
|
106
|
+
def strip_html(html)
|
107
|
+
html.gsub!(%r{</p>\n<p>}, "</p>\n\n<p>") # Workaround RedCloth 4.2.x issue
|
108
|
+
Nokogiri::HTML::DocumentFragment.parse(html).inner_text
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
data/rails/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ActiveRecord::Base.send(:include, ActsAsSanitiled)
|
@@ -0,0 +1,119 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'New object with textiled description' do
|
4
|
+
before do
|
5
|
+
@story = Story.new
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should have nil description" do
|
9
|
+
@story.description.should.be.nil
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should have nil description source" do
|
13
|
+
@story.description_source.should.be.nil
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should have nil description plain" do
|
17
|
+
@story.description_plain.should.be.nil
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe 'A standard textiled object' do
|
22
|
+
before do
|
23
|
+
@desc_textile = '_why announces __Sandbox__'
|
24
|
+
@body_textile = <<EOF
|
25
|
+
First line
|
26
|
+
Second line with *bold*
|
27
|
+
|
28
|
+
Second paragraph with special char(TM), <a href="javascript:alert('shit')">XSS attribute</a>,
|
29
|
+
script>script tag</script>, and <b>unclosed tag.
|
30
|
+
EOF
|
31
|
+
|
32
|
+
@story = Story.new(
|
33
|
+
:title => 'The Thrilling Freaky-Freaky Sandbox Hack',
|
34
|
+
:description => @desc_textile,
|
35
|
+
:body => @body_textile)
|
36
|
+
|
37
|
+
@desc_html = '_why announces <i>Sandbox</i>'
|
38
|
+
@desc_plain = '_why announces Sandbox'
|
39
|
+
|
40
|
+
@body_html = "<p>First line<br />\nSecond line with <strong>bold</strong></p>\n<p>Second paragraph with special char\342\204\242, <a>XSS attribute</a>,<br />\nscript>script tag, and <b>unclosed tag.</b></p>"
|
41
|
+
@body_plain = "First line\nSecond line with bold\n\nSecond paragraph with special char™, XSS attribute,\nscript>script tag, and unclosed tag."
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should properly textilize and strip html" do
|
45
|
+
@story.description.should.equal @desc_html
|
46
|
+
@story.description(:source).should.equal @desc_textile
|
47
|
+
@story.description(:plain).should.equal @desc_plain
|
48
|
+
|
49
|
+
@story.body.should.equal @body_html
|
50
|
+
@story.body(:source).should.equal @body_textile
|
51
|
+
@story.body(:plain).should.equal @body_plain
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should raise when given a non-sensical option" do
|
55
|
+
proc{ @story.description(:cassadaga) }.should.raise
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should pick up changes to attributes" do
|
59
|
+
@story.description.should.equal @desc_html
|
60
|
+
|
61
|
+
@story.description = "**IRb** is simple"
|
62
|
+
@story.description.should.equal "<b>IRb</b> is simple"
|
63
|
+
@story.description(:plain).should.equal "IRb is simple"
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should be able to toggle whether textile is active or not" do
|
67
|
+
@story.description.should.equal @desc_html
|
68
|
+
@story.textiled = false
|
69
|
+
@story.description.should.equal @desc_textile
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should be able to do on-demand textile caching" do
|
73
|
+
@story.textiled.size.should.equal 0
|
74
|
+
@story.textilize
|
75
|
+
@story.textiled.size.should.equal 2
|
76
|
+
@story.description.should.equal @desc_html
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should clear textiled hash on reload" do
|
80
|
+
@story.textilize
|
81
|
+
@story.textiled.size.should.equal 2
|
82
|
+
@story.reload
|
83
|
+
@story.textiled.size.should.equal 0
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
describe 'An object with one textiled and one sanitized field' do
|
88
|
+
before do
|
89
|
+
@author = Author.new(
|
90
|
+
:name => '<b>King *George*</p>',
|
91
|
+
:bio => '*Bold* but with <script>')
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should sanitize but not textilize name" do
|
95
|
+
@author.name.should.equal '<b>King *George*</b>'
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should textilize but not sanitize bio" do
|
99
|
+
@author.bio.should.equal '<p><strong>Bold</strong> but with <script></p>'
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
describe 'Defining fields on an ActiveRecord object' do
|
104
|
+
it "should not allow both skip_textile and skip_sanitize" do
|
105
|
+
proc do
|
106
|
+
class Foo < ActiveRecord::Base
|
107
|
+
acts_as_sanitiled :body, :skip_sanitize => true, :skip_textile => true
|
108
|
+
end
|
109
|
+
end.should.raise
|
110
|
+
end
|
111
|
+
|
112
|
+
it "should not allow options hash on acts_as_textiled" do
|
113
|
+
proc do
|
114
|
+
class Foo < ActiveRecord::Base
|
115
|
+
acts_as_textiled :body, :option => :is_verboten
|
116
|
+
end
|
117
|
+
end.should.raise
|
118
|
+
end
|
119
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
2
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
3
|
+
|
4
|
+
require 'acts_as_sanitiled'
|
5
|
+
require 'bacon'
|
6
|
+
require 'active_support'
|
7
|
+
|
8
|
+
class ActiveRecord
|
9
|
+
class Base
|
10
|
+
attr_reader :attributes
|
11
|
+
|
12
|
+
def initialize(attributes = {})
|
13
|
+
@attributes = attributes.dup.stringify_keys
|
14
|
+
end
|
15
|
+
|
16
|
+
def method_missing(name, *args)
|
17
|
+
if name.to_s[%r{=}]
|
18
|
+
@attributes[key = name.to_s.sub('=','')] = value = args.first
|
19
|
+
write_attribute key, value
|
20
|
+
else
|
21
|
+
self[name.to_s]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def [](value)
|
26
|
+
@attributes[value.to_s.sub('_before_type_cast', '')]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end unless defined? ActiveRecord
|
30
|
+
|
31
|
+
ActiveRecord::Base.send(:include, ActsAsSanitiled)
|
32
|
+
|
33
|
+
class Story < ActiveRecord::Base
|
34
|
+
acts_as_sanitiled :body
|
35
|
+
acts_as_sanitiled :description, [:lite_mode]
|
36
|
+
end
|
37
|
+
|
38
|
+
class Author < ActiveRecord::Base
|
39
|
+
acts_as_sanitized :name, :elements => ['b','em']
|
40
|
+
acts_as_textiled :bio
|
41
|
+
end
|
42
|
+
|
43
|
+
Bacon.summary_on_exit
|
metadata
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: acts_as_sanitiled
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Gabe da Silveira
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-10-14 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: nokogiri
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ~>
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 1.3.3
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: sanitize
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.1.0
|
34
|
+
version:
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: RedCloth
|
37
|
+
type: :runtime
|
38
|
+
version_requirement:
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: "0"
|
44
|
+
version:
|
45
|
+
- !ruby/object:Gem::Dependency
|
46
|
+
name: bacon
|
47
|
+
type: :development
|
48
|
+
version_requirement:
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: "0"
|
54
|
+
version:
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: activesupport
|
57
|
+
type: :development
|
58
|
+
version_requirement:
|
59
|
+
version_requirements: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: "0"
|
64
|
+
version:
|
65
|
+
description: "A modernized version of Chris Wansthrath's venerable acts_as_textiled. It automatically textiles and then sanitizes columns to your specification. Ryan Grove's excellent Sanitize gem with nokogiri provides the backend for speedy and robust filtering of your output in order to: restrict Textile to a subset of HTML, guarantee well-formedness, and of course prevent XSS."
|
66
|
+
email: gabe@websaviour.com
|
67
|
+
executables: []
|
68
|
+
|
69
|
+
extensions: []
|
70
|
+
|
71
|
+
extra_rdoc_files:
|
72
|
+
- LICENSE
|
73
|
+
- README.rdoc
|
74
|
+
files:
|
75
|
+
- CHANGELOG
|
76
|
+
- LICENSE
|
77
|
+
- README.rdoc
|
78
|
+
- Rakefile
|
79
|
+
- VERSION
|
80
|
+
- lib/acts_as_sanitiled.rb
|
81
|
+
- rails/init.rb
|
82
|
+
- spec/sanitiled_spec.rb
|
83
|
+
- spec/spec_helper.rb
|
84
|
+
has_rdoc: true
|
85
|
+
homepage: http://github.com/dasil003/acts_as_sanitiled
|
86
|
+
licenses: []
|
87
|
+
|
88
|
+
post_install_message:
|
89
|
+
rdoc_options:
|
90
|
+
- --charset=UTF-8
|
91
|
+
require_paths:
|
92
|
+
- lib
|
93
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - ">="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: "0"
|
98
|
+
version:
|
99
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: "0"
|
104
|
+
version:
|
105
|
+
requirements: []
|
106
|
+
|
107
|
+
rubyforge_project:
|
108
|
+
rubygems_version: 1.3.5
|
109
|
+
signing_key:
|
110
|
+
specification_version: 3
|
111
|
+
summary: Automatically textiles and/or sanitizes ActiveRecord columns
|
112
|
+
test_files:
|
113
|
+
- spec/sanitiled_spec.rb
|
114
|
+
- spec/spec_helper.rb
|