escape_utils 0.1.8 → 0.1.9

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.9 (October 15th, 2010)
4
+ * add a flag as an optional 2nd parameter to EscapeUtils.escape_html to disable/enable the escaping of the '/' character. Defaults to the new flag EscapeUtils.html_secure
5
+
3
6
  ## 0.1.8 (September 29th, 2010)
4
7
  * fix URI escaping one last time ;)
5
8
 
data/README.rdoc CHANGED
@@ -8,6 +8,8 @@ For character encoding in 1.9, we'll return strings in whatever Encoding.default
8
8
 
9
9
  It has monkey-patches for Rack::Utils, CGI, ERB::Util and Haml and ActionView so you can drop this in and have your app start escaping fast as balls in no time
10
10
 
11
+ It supports HTML, URL, URI and Javascript escaping/unescaping.
12
+
11
13
  == Installing
12
14
 
13
15
  gem install escape_utils
@@ -34,6 +36,19 @@ It has monkey-patches for Rack::Utils, CGI, ERB::Util and Haml and ActionView so
34
36
  require 'escape_utils/html/cgi' # to patch CGI
35
37
  require 'escape_utils/html/haml' # to patch Haml::Helpers
36
38
 
39
+ === URL
40
+
41
+ ==== Escaping
42
+
43
+ url = "https://www.yourmom.com/cgi-bin/session.cgi?sess_args=mcEA~!!#*YH*>@!U"
44
+ escaped_url = EscapeUtils.url_escape(url)
45
+
46
+ ==== Unescaping
47
+
48
+ url = "https://www.yourmom.com/cgi-bin/session.cgi?sess_args=mcEA~!!#*YH*>@!U"
49
+ escaped_url = EscapeUtils.url_escape(url)
50
+ EscapeUtils.url_unescape(escaped_url) == url # => true
51
+
37
52
  === Javascript
38
53
 
39
54
  ==== Escaping
@@ -41,6 +56,12 @@ It has monkey-patches for Rack::Utils, CGI, ERB::Util and Haml and ActionView so
41
56
  javascript = `curl -s http://code.jquery.com/jquery-1.4.2.js`
42
57
  escaped_javascript = EscapeUtils.escape_javascript(javascript)
43
58
 
59
+ ==== Unescaping
60
+
61
+ javascript = `curl -s http://code.jquery.com/jquery-1.4.2.js`
62
+ escaped_javascript = EscapeUtils.escape_javascript(javascript)
63
+ EscapeUtils.unescape_javascript(escaped_javascript) == javascript # => true
64
+
44
65
  ==== Monkey Patches
45
66
 
46
67
  require 'escape_utils/javascript/action_view' # to patch ActionView::Helpers::JavaScriptHelper
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.8
1
+ 0.1.9
data/escape_utils.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{escape_utils}
8
- s.version = "0.1.8"
8
+ s.version = "0.1.9"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Brian Lopez"]
12
- s.date = %q{2010-09-29}
12
+ s.date = %q{2010-10-15}
13
13
  s.email = %q{seniorlopez@gmail.com}
14
14
  s.extensions = ["ext/extconf.rb"]
15
15
  s.extra_rdoc_files = [
data/ext/escape_utils.c CHANGED
@@ -4,47 +4,43 @@
4
4
  static rb_encoding *utf8Encoding;
5
5
  #endif
6
6
 
7
+ static VALUE mEscapeUtils;
8
+ static ID rb_html_secure;
9
+
7
10
  #define IS_HEX(c) (c >= 48 || c <= 57) && (c >= 65 || c <= 70) && (c >= 97 || c <= 102)
8
11
  #define NOT_HEX(c) (c < 48 || c > 57) && (c < 65 || c > 90) && (c < 97 || c > 122)
9
12
  #define UNHEX(c) (c >= '0' && c <= '9' ? c - '0' : c >= 'A' && c <= 'F' ? c - 'A' + 10 : c - 'a' + 10)
10
13
  #define URI_SAFE(c) (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c== 45 || c == 46 || c == 95 || c == 126
11
14
  // ALPHA / DIGIT / "-" / "." / "_" / "~"
12
15
 
13
- static size_t escape_html(unsigned char *out, const unsigned char *in, size_t in_len) {
16
+ static size_t escape_html(unsigned char *out, const unsigned char *in, size_t in_len, unsigned short int secure) {
14
17
  size_t total = 0;
15
18
  unsigned char curChar;
16
19
 
17
20
  total = in_len;
18
21
  while (in_len) {
19
22
  curChar = *in++;
20
- switch (curChar) {
21
- case '<':
23
+
24
+ if (curChar == '<') {
22
25
  *out++ = '&'; *out++ = 'l'; *out++ = 't'; *out++ = ';';
23
26
  total += 3;
24
- break;
25
- case '>':
27
+ } else if (curChar == '>') {
26
28
  *out++ = '&'; *out++ = 'g'; *out++ = 't'; *out++ = ';';
27
29
  total += 3;
28
- break;
29
- case '&':
30
+ } else if (curChar == '&') {
30
31
  *out++ = '&'; *out++ = 'a'; *out++ = 'm'; *out++ = 'p'; *out++ = ';';
31
32
  total += 4;
32
- break;
33
- case '\'':
33
+ } else if (curChar == '\'') {
34
34
  *out++ = '&'; *out++ = '#'; *out++ = '3'; *out++ = '9'; *out++ = ';';
35
35
  total += 4;
36
- break;
37
- case '\"':
36
+ } else if (curChar == '\"') {
38
37
  *out++ = '&'; *out++ = 'q'; *out++ = 'u'; *out++ = 'o'; *out++ = 't'; *out++ = ';';
39
38
  total += 5;
40
- break;
41
- case '/':
39
+ } else if (secure && curChar == '/') {
42
40
  *out++ = '&'; *out++ = '#'; *out++ = '4'; *out++ = '7'; *out++ = ';';
43
41
  total += 4;
44
- break;
45
- default:
42
+ } else {
46
43
  *out++ = curChar;
47
- break;
48
44
  }
49
45
  in_len--;
50
46
  }
@@ -282,7 +278,19 @@ static size_t unescape_uri(unsigned char *out, const unsigned char *in, size_t i
282
278
  return total;
283
279
  }
284
280
 
285
- static VALUE rb_escape_html(VALUE self, VALUE str) {
281
+ static VALUE rb_escape_html(int argc, VALUE * argv, VALUE self) {
282
+ VALUE str, rb_secure = rb_funcall(mEscapeUtils, rb_html_secure, 0);
283
+ unsigned short secure = 1;
284
+ if (rb_secure == Qfalse) {
285
+ secure = 0;
286
+ }
287
+
288
+ if (rb_scan_args(argc, argv, "11", &str, &rb_secure) == 2) {
289
+ if (rb_secure == Qfalse) {
290
+ secure = 0;
291
+ }
292
+ }
293
+
286
294
  Check_Type(str, T_STRING);
287
295
 
288
296
  VALUE rb_output_buf;
@@ -298,7 +306,7 @@ static VALUE rb_escape_html(VALUE self, VALUE str) {
298
306
  unsigned char *outBuf = (unsigned char *)malloc(sizeof(unsigned char *)*(len*5));
299
307
 
300
308
  // perform our escape, returning the new string's length
301
- new_len = escape_html(outBuf, inBuf, len);
309
+ new_len = escape_html(outBuf, inBuf, len, secure);
302
310
 
303
311
  // create our new ruby string
304
312
  rb_output_buf = rb_str_new((char *)outBuf, new_len);
@@ -572,26 +580,28 @@ static VALUE rb_unescape_uri(VALUE self, VALUE str) {
572
580
 
573
581
  /* Ruby Extension initializer */
574
582
  void Init_escape_utils_ext() {
575
- VALUE mEscape = rb_define_module("EscapeUtils");
576
- rb_define_method(mEscape, "escape_html", rb_escape_html, 1);
577
- rb_define_module_function(mEscape, "escape_html", rb_escape_html, 1);
578
- rb_define_method(mEscape, "unescape_html", rb_unescape_html, 1);
579
- rb_define_module_function(mEscape, "unescape_html", rb_unescape_html, 1);
580
- rb_define_method(mEscape, "escape_javascript", rb_escape_javascript, 1);
581
- rb_define_module_function(mEscape, "escape_javascript", rb_escape_javascript, 1);
582
- rb_define_method(mEscape, "unescape_javascript", rb_unescape_javascript, 1);
583
- rb_define_module_function(mEscape, "unescape_javascript", rb_unescape_javascript, 1);
584
- rb_define_method(mEscape, "escape_url", rb_escape_url, 1);
585
- rb_define_module_function(mEscape, "escape_url", rb_escape_url, 1);
586
- rb_define_method(mEscape, "unescape_url", rb_unescape_url, 1);
587
- rb_define_module_function(mEscape, "unescape_url", rb_unescape_url, 1);
588
- rb_define_method(mEscape, "escape_uri", rb_escape_uri, 1);
589
- rb_define_module_function(mEscape, "escape_uri", rb_escape_uri, 1);
590
- rb_define_method(mEscape, "unescape_uri", rb_unescape_uri, 1);
591
- rb_define_module_function(mEscape, "unescape_uri", rb_unescape_uri, 1);
583
+ mEscapeUtils = rb_define_module("EscapeUtils");
584
+ rb_define_method(mEscapeUtils, "escape_html", rb_escape_html, -1);
585
+ rb_define_module_function(mEscapeUtils, "escape_html", rb_escape_html, -1);
586
+ rb_define_method(mEscapeUtils, "unescape_html", rb_unescape_html, 1);
587
+ rb_define_module_function(mEscapeUtils, "unescape_html", rb_unescape_html, 1);
588
+ rb_define_method(mEscapeUtils, "escape_javascript", rb_escape_javascript, 1);
589
+ rb_define_module_function(mEscapeUtils, "escape_javascript", rb_escape_javascript, 1);
590
+ rb_define_method(mEscapeUtils, "unescape_javascript", rb_unescape_javascript, 1);
591
+ rb_define_module_function(mEscapeUtils, "unescape_javascript", rb_unescape_javascript, 1);
592
+ rb_define_method(mEscapeUtils, "escape_url", rb_escape_url, 1);
593
+ rb_define_module_function(mEscapeUtils, "escape_url", rb_escape_url, 1);
594
+ rb_define_method(mEscapeUtils, "unescape_url", rb_unescape_url, 1);
595
+ rb_define_module_function(mEscapeUtils, "unescape_url", rb_unescape_url, 1);
596
+ rb_define_method(mEscapeUtils, "escape_uri", rb_escape_uri, 1);
597
+ rb_define_module_function(mEscapeUtils, "escape_uri", rb_escape_uri, 1);
598
+ rb_define_method(mEscapeUtils, "unescape_uri", rb_unescape_uri, 1);
599
+ rb_define_module_function(mEscapeUtils, "unescape_uri", rb_unescape_uri, 1);
592
600
 
593
601
  #ifdef HAVE_RUBY_ENCODING_H
594
602
  utf8Encoding = rb_utf8_encoding();
595
603
  #endif
604
+
605
+ rb_html_secure = rb_intern("html_secure");
596
606
  }
597
607
 
data/lib/escape_utils.rb CHANGED
@@ -4,7 +4,19 @@ require 'escape_utils_ext'
4
4
 
5
5
  EscapeUtils.send(:extend, EscapeUtils)
6
6
  module EscapeUtils
7
- VERSION = "0.1.8"
7
+ VERSION = "0.1.9"
8
+
9
+ # turn on/off the escaping of the '/' character during HTML escaping
10
+ # Escaping '/' is recommended by the OWASP - http://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet#RULE_.231_-_HTML_Escape_Before_Inserting_Untrusted_Data_into_HTML_Element_Content
11
+ # This is because quotes around HTML attributes are optional in most/all modern browsers at the time of writing (10/15/2010)
12
+ @@html_secure = true
13
+
14
+ def self.html_secure
15
+ @@html_secure
16
+ end
17
+ def self.html_secure=(val)
18
+ @@html_secure = val
19
+ end
8
20
 
9
21
  autoload :HtmlSafety, 'escape_utils/html_safety'
10
22
  end
@@ -7,12 +7,12 @@ module EscapeUtils
7
7
  if s.html_safe?
8
8
  s.to_s.html_safe
9
9
  else
10
- EscapeUtils.escape_html(s.to_s).html_safe
10
+ EscapeUtils.escape_html(s.to_s, EscapeUtils.html_secure).html_safe
11
11
  end
12
12
  end
13
13
  else
14
14
  def _escape_html(s)
15
- EscapeUtils.escape_html(s.to_s)
15
+ EscapeUtils.escape_html(s.to_s, EscapeUtils.html_secure)
16
16
  end
17
17
  end
18
18
  end
@@ -6,10 +6,20 @@ describe EscapeUtils, "escape_html" do
6
6
  EscapeUtils.should respond_to(:escape_html)
7
7
  end
8
8
 
9
- it "should escape a basic html tag" do
9
+ it "should escape a basic html tag, also escaping the '/' character if the secure parameter is true" do
10
10
  EscapeUtils.escape_html("<some_tag/>").should eql("&lt;some_tag&#47;&gt;")
11
11
  end
12
12
 
13
+ it "should escape a basic html tag, not escaping the '/' character if the secure parameter is false" do
14
+ EscapeUtils.escape_html("<some_tag/>", false).should eql("&lt;some_tag/&gt;")
15
+ end
16
+
17
+ it "should escape a basic html tag, not escaping the '/' character if EscapeUtils.html_secure is false" do
18
+ EscapeUtils.html_secure = false
19
+ EscapeUtils.escape_html("<some_tag/>").should eql("&lt;some_tag/&gt;")
20
+ EscapeUtils.html_secure = true
21
+ end
22
+
13
23
  it "should escape double-quotes" do
14
24
  EscapeUtils.escape_html("<some_tag some_attr=\"some value\"/>").should eql("&lt;some_tag some_attr=&quot;some value&quot;&#47;&gt;")
15
25
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: escape_utils
3
3
  version: !ruby/object:Gem::Version
4
- hash: 11
4
+ hash: 9
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 1
9
- - 8
10
- version: 0.1.8
9
+ - 9
10
+ version: 0.1.9
11
11
  platform: ruby
12
12
  authors:
13
13
  - Brian Lopez
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-09-29 00:00:00 -07:00
18
+ date: 2010-10-15 00:00:00 -07:00
19
19
  default_executable:
20
20
  dependencies: []
21
21