mixpanel 4.0.9 → 4.1.0

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/README.md CHANGED
@@ -4,6 +4,8 @@ This Gem will not be maintained anymore, there is an Official gem being develope
4
4
 
5
5
  We will merge PR for bugs for a little period of time, but no new features will be added.
6
6
 
7
+ # Upgrade to 4.1.0 to avoid XSS Vulnerability
8
+
7
9
  [Official Gem repository](https://github.com/mixpanel/mixpanel-ruby)
8
10
 
9
11
  ## Table of Contents
@@ -35,7 +35,10 @@ module Mixpanel
35
35
  end
36
36
 
37
37
  def append(type, *args)
38
- queue << [type, args.collect {|arg| arg.to_json}]
38
+ js_args = args.collect do |arg|
39
+ escape_object_for_js(arg).to_json
40
+ end
41
+ queue << [type, js_args]
39
42
  end
40
43
 
41
44
  protected
@@ -86,5 +89,73 @@ module Mixpanel
86
89
  0
87
90
  end
88
91
  end
92
+
93
+ private
94
+
95
+ # Recursively escape anything in a primitive, array, or hash, in
96
+ # preparation for jsonifying it
97
+ def escape_object_for_js(object, i = 0)
98
+
99
+ if object.kind_of? Hash
100
+ # Recursive case
101
+ Hash.new.tap do |h|
102
+ object.each do |k, v|
103
+ h[escape_object_for_js(k, i + 1)] = escape_object_for_js(v, i + 1)
104
+ end
105
+ end
106
+
107
+ elsif object.kind_of? Enumerable
108
+ # Recursive case
109
+ object.map do |elt|
110
+ escape_object_for_js(elt, i + 1)
111
+ end
112
+
113
+ elsif object.respond_to? :iso8601
114
+ # Base case - safe object
115
+ object.iso8601
116
+
117
+ elsif object.kind_of?(Numeric)
118
+ # Base case - safe object
119
+ object
120
+
121
+ elsif [true, false, nil].member?(object)
122
+ # Base case - safe object
123
+ object
124
+
125
+ else
126
+ # Base case - use string sanitizer from ActiveSupport
127
+ escape_javascript(object.to_s)
128
+
129
+ end
130
+ end
131
+
132
+ # All this code borrowed from rails/action_pack - ActionView::Helpers::JavascriptHelper
133
+
134
+ JS_ESCAPE_MAP = {
135
+ '\\' => '\\\\',
136
+ '</' => '<\/',
137
+ "\r\n" => '\n',
138
+ "\n" => '\n',
139
+ "\r" => '\n',
140
+ '"' => '\\"',
141
+ "'" => "\\'"
142
+ }
143
+
144
+ JS_ESCAPE_MAP["\342\200\250".force_encoding(Encoding::UTF_8).encode!] = '&#x2028;'
145
+ JS_ESCAPE_MAP["\342\200\251".force_encoding(Encoding::UTF_8).encode!] = '&#x2029;'
146
+
147
+ # Escapes carriage returns and single and double quotes for JavaScript segments.
148
+ #
149
+ # Also available through the alias j(). This is particularly helpful in JavaScript
150
+ # responses, like:
151
+ #
152
+ # $('some_element').replaceWith('<%=j render 'some/element_template' %>');
153
+ def escape_javascript(javascript)
154
+ if javascript
155
+ javascript.gsub(/(\\|<\/|\r\n|\342\200\250|\342\200\251|[\n\r"'])/u) {|match| JS_ESCAPE_MAP[match] }
156
+ else
157
+ ''
158
+ end
159
+ end
89
160
  end
90
161
  end
@@ -2,7 +2,7 @@ files = ['README.md', 'LICENSE', 'Rakefile', 'mixpanel.gemspec', '{spec,lib}/**/
2
2
 
3
3
  spec = Gem::Specification.new do |s|
4
4
  s.name = "mixpanel"
5
- s.version = "4.0.9"
5
+ s.version = "4.1.0"
6
6
  s.rubyforge_project = "mixpanel"
7
7
  s.description = "Simple lib to track events in Mixpanel service. It can be used in any rack based framework."
8
8
  s.author = "Alvaro Gil"
@@ -146,6 +146,24 @@ describe Mixpanel::Tracker do
146
146
  mixpanel_queue_should_include(@mixpanel, "track", "Sign up", props)
147
147
  end
148
148
 
149
+ it "should sanitize property values" do
150
+ @mixpanel.append_track("Sign up", {:referer => "</script><script>alert('XSS');</script>"})
151
+ @mixpanel.queue.size.should == 1
152
+ enqueued = @mixpanel.queue.first
153
+ properties_json = enqueued[1][1]
154
+ properties_json.should_not match(%r|</script>|)
155
+ end
156
+
157
+ it "should be able to sanitize complex objects" do
158
+ properties = {'object' => ['foo', {2 => 1, 1 => ['bar', Time.now, nil, {'xss' => "</script><script>alert('XSS');</script>"}]}]}
159
+ @mixpanel.append_track("Sign up", properties)
160
+ @mixpanel.queue.size.should == 1
161
+ enqueued = @mixpanel.queue.first
162
+ properties_json = enqueued[1][1]
163
+ properties_json.should_not match(%r|</script>|)
164
+ end
165
+
166
+
149
167
  it "should give direct access to queue" do
150
168
  @mixpanel.append_track("Sign up", {:referer => 'http://example.com'})
151
169
  @mixpanel.queue.size.should == 1
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mixpanel
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.9
4
+ version: 4.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-11-07 00:00:00.000000000 Z
12
+ date: 2013-11-14 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: json