escape_utils 0.1.8 → 0.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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