mixpanel 4.0.9 → 4.1.0

Sign up to get free protection for your applications and to get access to all the features.
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