bbcoder 1.0.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -1,3 +1,3 @@
1
- source :rubygems
1
+ source "https://rubygems.org"
2
2
 
3
3
  gemspec
data/Gemfile.lock CHANGED
@@ -1,26 +1,28 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- bbcoder (1.0.0)
4
+ bbcoder (1.0.1)
5
5
 
6
6
  GEM
7
- remote: http://rubygems.org/
7
+ remote: https://rubygems.org/
8
8
  specs:
9
9
  diff-lcs (1.1.3)
10
+ rake (0.9.2.2)
10
11
  rr (1.0.4)
11
- rspec (2.9.0)
12
- rspec-core (~> 2.9.0)
13
- rspec-expectations (~> 2.9.0)
14
- rspec-mocks (~> 2.9.0)
15
- rspec-core (2.9.0)
16
- rspec-expectations (2.9.1)
12
+ rspec (2.10.0)
13
+ rspec-core (~> 2.10.0)
14
+ rspec-expectations (~> 2.10.0)
15
+ rspec-mocks (~> 2.10.0)
16
+ rspec-core (2.10.0)
17
+ rspec-expectations (2.10.0)
17
18
  diff-lcs (~> 1.1.3)
18
- rspec-mocks (2.9.0)
19
+ rspec-mocks (2.10.1)
19
20
 
20
21
  PLATFORMS
21
22
  ruby
22
23
 
23
24
  DEPENDENCIES
24
25
  bbcoder!
26
+ rake
25
27
  rr
26
28
  rspec
data/README.md CHANGED
@@ -1,3 +1,9 @@
1
+ Status
2
+ --------
3
+ I consider bbcoder to be stable so you won't see many updates to it in the future. It is perfectly fine to use in prodution. The gem itself is pretty simple so it should work across
4
+ the board with newer frameworks etc. If you find any issues or think it needs a feature please submit an issue.
5
+
6
+
1
7
  Features
2
8
  --------
3
9
 
@@ -13,9 +19,13 @@ p, b, i, u, s, del, ins, ol, ul, li, dl, dt, dd, quote, code, spoiler, url, img,
13
19
  Usage
14
20
  --------
15
21
 
16
- BBCoder.new(text).to_html
22
+ BBCoder.new(h(text)).to_html
17
23
  # or
18
- "[p]my string[/p]".bbcode_to_html
24
+ h("[p]my string[/p]").bbcode_to_html
25
+ # h() is a Rails helper function, you may use CGI.escapeHTML instead
26
+
27
+ See configuration section below on adding new parseable tags
28
+
19
29
 
20
30
  Install
21
31
  -------
@@ -23,6 +33,36 @@ Install
23
33
  gem install bbcoder
24
34
 
25
35
 
36
+ Autolinking, Smileys, XSS prevention, Newlines
37
+ --------------------------------------
38
+
39
+ bbcoder is not meant to handle smileys, autolinking or xss attacks. There are other libraries to help do this for us. I also do not consider these elements part of bbcode itself (even though there is no standard) so bbcoder will not provide support for them except in this README to give examples on how to combine them together.
40
+
41
+
42
+ #### Autolinking
43
+ Rails 2.x has a helper auto_link by default that can do this for you. For Rails 3.x you can install the rails_autolink gem.
44
+
45
+
46
+ #### Smileys
47
+ At the moment I use a jquery library to display smileys after the page has loaded. The library I use https://github.com/JangoSteve/jQuery-CSSEmoticons however it would be nice to see a gem that can parse smileys out of text into appropriate html elements with specific tags. CSS3 font-face anyone?
48
+
49
+
50
+ #### XSS
51
+ Please make sure you escaped or sanitized all HTML in the string before passing it to bbcoder!
52
+
53
+ bbcoder will now do a whitelist check against img tags and url tags by default and only allow http/https links. You can override this by putting in your own configuration if you wish. If you find any other flaws or holes please report so we can fix. bbcoder will not sanitize the rest of your input, it will only attempt to whitelist the actual html elements it will generate.
54
+
55
+
56
+ #### Newlines
57
+ When typing into a textarea a user will use newlines to indicate space between lines. This is not translated properly into br tags. I do not consider this a function for bbcoder either atm, however I do use it in combination with XSS/Sanitize above:
58
+
59
+
60
+ ##### XSS + Newlines Helper
61
+ def bbcode(text)
62
+ Sanitize.clean(text.to_s).bbcode_to_html.gsub(/\n|\r\n/, "<br />").html_safe
63
+ end
64
+
65
+
26
66
  Configuration Examples
27
67
  -----------------------
28
68
 
@@ -41,7 +81,15 @@ Configuration Examples
41
81
  tag :ol
42
82
  tag :li, :parents => [:ol, :ul]
43
83
 
44
- tag :img, :match => /^.*(png|bmp|jpe?g|gif)$/ do
84
+ tag :url, :match_link => /^https?:\/\// do
85
+ if meta.nil? || meta.empty?
86
+ %(<a href="#{content}">#{content}</a>)
87
+ else
88
+ %(<a href="#{meta}">#{content}</a>)
89
+ end
90
+ end
91
+
92
+ tag :img, :match => /^https?:\/\/.*(png|bmp|jpe?g|gif)$/, :singular => true do
45
93
  %(<a href="#{singular? ? meta : content}"><img src="#{singular? ? meta : content}" /></a>)
46
94
  end
47
95
 
@@ -53,13 +101,7 @@ Configuration Examples
53
101
  EOS
54
102
  end
55
103
 
56
- tag :url do
57
- if meta.nil? || meta.empty?
58
- %(<a href="#{content}">#{content}</a>)
59
- else
60
- %(<a href="#{meta}">#{content}</a>)
61
- end
62
- end
104
+ remove :spoiler # Removes [spoiler]
63
105
  end
64
106
 
65
107
 
@@ -69,6 +111,7 @@ Options for #tag
69
111
  * :match (regex) -> convert this tag and its content to html only if the content and meta matches the regex (see img tag above for example)
70
112
  * :match_meta (regex) -> same as :match except only for meta
71
113
  * :match_content (regex) -> same as :match except only for content
114
+ * :match_link (regex) -> special :match case, will match meta if it exists otherwise tries to match content (see url tag for usage)
72
115
  * :parents ([symbol]) -> ignore this tag if there is no open tag that matches its parents
73
116
  * :singular (true|false) -> use this if the tag does not require an ending tag
74
117
 
@@ -79,6 +122,7 @@ When you pass a block to #tag it is expecting you to return a string. You have
79
122
  * content -> Everything between the two tags (with [b]strong arm[/b] content returns 'strong arm')
80
123
  * singular? -> Tells you if this tag is being parsed in singular form or if it had an ending tag (affects if content has any data)
81
124
 
125
+ You can remove all configured tags by calling `BBCoder.configuration.clear`.
82
126
 
83
127
  Author
84
128
  ------
data/Rakefile CHANGED
@@ -4,13 +4,14 @@ Bundler.setup
4
4
  require "rspec"
5
5
  require "rspec/core/rake_task"
6
6
 
7
- Rspec::Core::RakeTask.new(:spec)
7
+ RSpec::Core::RakeTask.new(:spec)
8
8
 
9
9
  gemspec = eval(File.read(File.join(Dir.pwd, "bbcoder.gemspec")))
10
10
 
11
11
  task :build => "#{gemspec.full_name}.gem"
12
12
 
13
13
  task :test => :spec
14
+ task :default => :spec
14
15
 
15
16
  file "#{gemspec.full_name}.gem" => gemspec.files + ["bbcoder.gemspec"] do
16
17
  system "gem build bbcoder.gemspec"
data/bbcoder.gemspec CHANGED
@@ -18,6 +18,7 @@ Gem::Specification.new do |s|
18
18
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
19
  s.require_paths = ["lib"]
20
20
 
21
+ s.add_development_dependency 'rake'
21
22
  s.add_development_dependency 'rspec'
22
23
  s.add_development_dependency 'rr'
23
24
  end
data/lib/bbcoder.rb CHANGED
@@ -21,9 +21,10 @@ BBCoder.configure do
21
21
  tag :dd, :parents => [:dl]
22
22
 
23
23
  tag :quote do
24
+ quoted = meta.empty? ? '' : "\n <legend>#{meta} says</legend>"
25
+
24
26
  <<-EOS
25
- <fieldset>
26
- <legend>#{meta} says</legend>
27
+ <fieldset>#{quoted}
27
28
  <blockquote>
28
29
  #{content}
29
30
  </blockquote>
@@ -48,7 +49,7 @@ BBCoder.configure do
48
49
  EOS
49
50
  end
50
51
 
51
- tag :url do
52
+ tag :url, :match_link => /^https?:\/\// do
52
53
  if meta.nil? || meta.empty?
53
54
  %(<a href="#{content}">#{content}</a>)
54
55
  else
@@ -56,7 +57,7 @@ BBCoder.configure do
56
57
  end
57
58
  end
58
59
 
59
- tag :img, :match => /^.*(png|bmp|jpe?g|gif)$/, :singular => true do
60
+ tag :img, :match => /^https?:\/\/.*(png|bmp|jpe?g|gif)$/, :singular => true do
60
61
  %(<a href="#{singular? ? meta : content}"><img src="#{singular? ? meta : content}" /></a>)
61
62
  end
62
63
 
@@ -6,6 +6,14 @@ class BBCoder
6
6
  @@tags[value]
7
7
  end
8
8
 
9
+ def clear
10
+ @@tags = {}
11
+ end
12
+
13
+ def remove name
14
+ @@tags.delete(name.to_sym)
15
+ end
16
+
9
17
  def tag(name, options = {}, &block)
10
18
  unless block.nil?
11
19
  block.binding.eval <<-EOS
data/lib/bbcoder/tag.rb CHANGED
@@ -8,7 +8,9 @@ class BBCoder
8
8
  end
9
9
 
10
10
  def to_html(meta, content, singularity = false)
11
- return self.class.reform(name, meta, content, singularity, true) unless content_valid?(content, singularity) && meta_valid?(meta, singularity)
11
+ unless content_valid?(content, singularity) && meta_valid?(meta, singularity) && link_valid?(meta, content)
12
+ return self.class.reform(name, meta, content, singularity, true)
13
+ end
12
14
 
13
15
  if options[:block].nil?
14
16
  "<#{options[:as]}>#{content}</#{options[:as]}>"
@@ -22,6 +24,19 @@ class BBCoder
22
24
  end
23
25
  end
24
26
 
27
+ def link_valid?(meta, content)
28
+ # only run if we have a :match_link
29
+ return true if options[:match_link].nil?
30
+
31
+ if meta.nil? || meta.empty?
32
+ return false if content.match(options[:match_link]).nil?
33
+ else
34
+ return false if meta.match(options[:match_link]).nil?
35
+ end
36
+
37
+ return true
38
+ end
39
+
25
40
  def meta_valid?(meta, singularity)
26
41
  return true if meta.nil?
27
42
 
@@ -1,3 +1,3 @@
1
1
  class BBCoder
2
- VERSION = "1.0.0"
2
+ VERSION = "1.0.1"
3
3
  end
data/spec/base_spec.rb CHANGED
@@ -5,9 +5,22 @@ describe BBCoder do
5
5
  subject { BBCoder.new("[p]Text and now [b]bolded.[/b][/p]") }
6
6
 
7
7
  context "#configuration" do
8
+ before do
9
+ @tags = BBCoder::Configuration.class_variable_get(:@@tags).clone
10
+ end
11
+
12
+ after do
13
+ BBCoder::Configuration.class_variable_set(:@@tags, @tags)
14
+ end
15
+
8
16
  it "should return the same object for multiple calls" do
9
17
  BBCoder.configuration.should == BBCoder.configuration
10
18
  end
19
+
20
+ it "should allow to clear the configuration" do
21
+ BBCoder.configuration.clear
22
+ BBCoder.configuration[:spoiler].should be_nil
23
+ end
11
24
  end
12
25
 
13
26
  context "#buffer" do
@@ -17,6 +30,14 @@ describe BBCoder do
17
30
  end
18
31
 
19
32
  context "#configure" do
33
+ before do
34
+ @tags = BBCoder::Configuration.class_variable_get(:@@tags).clone
35
+ end
36
+
37
+ after do
38
+ BBCoder::Configuration.class_variable_set(:@@tags, @tags)
39
+ end
40
+
20
41
  it "should fail without a block" do
21
42
  lambda { BBCoder.configure }.should raise_error
22
43
  end
@@ -26,6 +47,13 @@ describe BBCoder do
26
47
  mock(BBCoder).configuration.stub!.instance_eval(&block)
27
48
  BBCoder.configure(&block)
28
49
  end
50
+
51
+ it "should be able to remove a tag" do
52
+ BBCoder.configure do
53
+ remove :spoiler
54
+ end
55
+ BBCoder.configuration[:spoiler].should be_nil
56
+ end
29
57
  end
30
58
 
31
59
  context "#initialize" do
data/spec/bbcoder_spec.rb CHANGED
@@ -2,6 +2,33 @@ require 'spec_helper'
2
2
 
3
3
  describe BBCoder do
4
4
 
5
+ context "quotes" do
6
+ it "displays the quoted party if provided" do
7
+ string = "[quote=weedman]Said some thing about some stuff[/quote]"
8
+
9
+ string.bbcode_to_html.should == <<-EOS
10
+ <fieldset>
11
+ <legend>weedman says</legend>
12
+ <blockquote>
13
+ Said some thing about some stuff
14
+ </blockquote>
15
+ </fieldset>
16
+ EOS
17
+ end
18
+
19
+ it "has no legend if no quoted party provided" do
20
+ string = "[quote]Said some thing about some stuff[/quote]"
21
+
22
+ string.bbcode_to_html.should == <<-EOS
23
+ <fieldset>
24
+ <blockquote>
25
+ Said some thing about some stuff
26
+ </blockquote>
27
+ </fieldset>
28
+ EOS
29
+ end
30
+ end
31
+
5
32
  context "with dirty input" do
6
33
  it "should parse content with \" in it" do
7
34
  '[p]Text phrase: "going away"[/p]'.bbcode_to_html.should == '<p>Text phrase: "going away"</p>'
@@ -20,7 +47,7 @@ describe BBCoder do
20
47
 
21
48
  result = <<-EOS
22
49
  <fieldset>
23
- <legend>weedman says</legend>
50
+ <legend>weedman says</legend>
24
51
  <blockquote>
25
52
  YES I STICKY IT ALL oF YOU WHO DON\'T LIKE it SEND YOUR HATE HERE\n\nhttp://www.gamesyn.com/plugin.php?plugin=PrivateMessages&file=message_send.php&id=20&tid=1583\n\n:} have a good day
26
53
  </blockquote>
@@ -67,7 +94,6 @@ EOS
67
94
  output = "[p]Text and now [b]bold then [i]italics[/i][/b][/p] and then a [quote]Quote[/quote]".bbcode_to_html
68
95
  output.should == <<-EOS
69
96
  <p>Text and now <strong>bold then <em>italics</em></strong></p> and then a <fieldset>
70
- <legend> says</legend>
71
97
  <blockquote>
72
98
  Quote
73
99
  </blockquote>
@@ -151,5 +177,46 @@ EOS
151
177
  "[img=image.exe]".bbcode_to_html.should == "[img=image.exe]"
152
178
  end
153
179
  end
180
+
181
+ context "with xss attacks" do
182
+ it "should reject anything other than http/https for url tags" do
183
+ "[url=javascript:alert('You got hacked!')]hacked[/url]".bbcode_to_html.should == "[url=javascript:alert('You got hacked!')]hacked[/url]"
184
+ "[url]javascript:alert('You got hacked!')[/url]".bbcode_to_html.should == "[url]javascript:alert('You got hacked!')[/url]"
185
+
186
+ '[url=javascript:window.alert("You got hacked!")]click[/url]'.bbcode_to_html.should == '[url=javascript:window.alert("You got hacked!")]click[/url]'
187
+ end
188
+
189
+ it "should reject anything other than http/https for img tags" do
190
+ "[img=javascript:alert('XSS');jpg]".bbcode_to_html.should == "[img=javascript:alert('XSS');jpg]"
191
+ "[img]javascript:alert('XSS');png[/img]".bbcode_to_html.should == "[img]javascript:alert('XSS');png[/img]"
192
+ '[img]javascript:window.alert("You got hacked!")//.jpg[/img]'.bbcode_to_html.should == '[img]javascript:window.alert("You got hacked!")//.jpg[/img]'
193
+
194
+ attack = "[img]
195
+ j
196
+ a
197
+ v
198
+ a
199
+ s
200
+ c
201
+ r
202
+ i
203
+ p
204
+ t
205
+ :
206
+ a
207
+ l
208
+ e
209
+ r
210
+ t
211
+ (
212
+ '
213
+ X
214
+ S
215
+ S
216
+ '
217
+ );jpg[/img]"
218
+ attack.bbcode_to_html.should == attack
219
+ end
220
+ end
154
221
  end
155
222
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bbcoder
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,8 +9,24 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-04-13 00:00:00.000000000 Z
12
+ date: 2013-11-12 00:00:00.000000000 Z
13
13
  dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
14
30
  - !ruby/object:Gem::Dependency
15
31
  name: rspec
16
32
  requirement: !ruby/object:Gem::Requirement
@@ -92,7 +108,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
92
108
  version: '0'
93
109
  requirements: []
94
110
  rubyforge_project: bbcoder
95
- rubygems_version: 1.8.21
111
+ rubygems_version: 1.8.23
96
112
  signing_key:
97
113
  specification_version: 3
98
114
  summary: BBCode parser