solidus_backend 1.1.2 → 1.1.3

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of solidus_backend might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 29c8705d452ce74aad7d08b555aadc11a97b6731
4
- data.tar.gz: 2d2cf2f35445346d51af6fc42413059c3143b8f8
3
+ metadata.gz: cd04d936c53077456873f926bdbc5f0a4ad82e37
4
+ data.tar.gz: 95fcac4f435671f54116dc09f2807f414acc1e0d
5
5
  SHA512:
6
- metadata.gz: 017c4b597f2b74b6b322a589cd9d838ba2fed96eeef04dca2b8e8c74f152f3f1e367d7aae45e2d36cc7a19464556a9ec1ebd5e366d6cf22f233bc6118dcb1da1
7
- data.tar.gz: 7c0bf214c2d9656452cbfacacc6d8c414d1a99f753c9a0915a14e92d9a552e29dc35296f4138db7ebce5d2dd1047b9f2f3868cc0e094d408e71dbad634ee02df
6
+ metadata.gz: 1366f87ab6e4bdfc6fe49a70dcaede2c32485c34e7f82380e4f6b075dc3f04079c053d25012315e2f2a7d8ac855e91d8f9ae514b9b83adf55a04f656066c354e
7
+ data.tar.gz: be9d240cf0dab33875e6fe90b72b36380ee328b2ab94695380ab50067de67877a3e4c8fa208f341cbc1d81547dd761bb5fc24a221d687401354bf25be36a4653
@@ -24,7 +24,7 @@ $(document).ready(function() {
24
24
  }
25
25
  },
26
26
  results: function(data, page) {
27
- return { results: data }
27
+ return { results: data.users }
28
28
  }
29
29
  },
30
30
  dropdownCssClass: 'customer_search',
@@ -52,7 +52,7 @@ $(document).ready(function() {
52
52
  });
53
53
  });
54
54
  }
55
- return customer.email;
55
+ return Select2.util.escapeMarkup(customer.email);
56
56
  }
57
57
  })
58
58
  }
@@ -1,6 +1,10 @@
1
1
  $(document).ready(function () {
2
2
  'use strict';
3
3
 
4
+ function formatOptionType(option_type) {
5
+ return Select2.util.escapeMarkup(option_type.presentation + ' (' + option_type.name + ')');
6
+ }
7
+
4
8
  if ($('#product_option_type_ids').length > 0) {
5
9
  $('#product_option_type_ids').select2({
6
10
  placeholder: Spree.translations.option_type_placeholder,
@@ -31,12 +35,8 @@ $(document).ready(function () {
31
35
  };
32
36
  }
33
37
  },
34
- formatResult: function (option_type) {
35
- return option_type.presentation + ' (' + option_type.name + ')';
36
- },
37
- formatSelection: function (option_type) {
38
- return option_type.presentation + ' (' + option_type.name + ')';
39
- }
38
+ formatResult: formatOptionType,
39
+ formatSelection: formatOptionType
40
40
  });
41
41
  }
42
42
  });
@@ -6,6 +6,10 @@ $.fn.optionValueAutocomplete = function (options) {
6
6
  var multiple = typeof(options['multiple']) !== 'undefined' ? options['multiple'] : true;
7
7
  var productSelect = options['productSelect'];
8
8
 
9
+ function formatOptionValue(option_value) {
10
+ return Select2.util.escapeMarkup(option_value.name);
11
+ }
12
+
9
13
  this.select2({
10
14
  minimumInputLength: 3,
11
15
  multiple: multiple,
@@ -33,11 +37,7 @@ $.fn.optionValueAutocomplete = function (options) {
33
37
  return { results: data };
34
38
  }
35
39
  },
36
- formatResult: function (option_value) {
37
- return option_value.name;
38
- },
39
- formatSelection: function (option_value) {
40
- return option_value.name;
41
- }
40
+ formatResult: formatOptionValue,
41
+ formatSelection: formatOptionValue
42
42
  });
43
43
  };
@@ -5,6 +5,10 @@ $.fn.productAutocomplete = function (options) {
5
5
  options = options || {}
6
6
  var multiple = typeof(options['multiple']) !== 'undefined' ? options['multiple'] : true
7
7
 
8
+ function formatProduct(product) {
9
+ return Select2.util.escapeMarkup(product.name);
10
+ }
11
+
8
12
  this.select2({
9
13
  minimumInputLength: 3,
10
14
  multiple: multiple,
@@ -39,12 +43,8 @@ $.fn.productAutocomplete = function (options) {
39
43
  };
40
44
  }
41
45
  },
42
- formatResult: function (product) {
43
- return product.name;
44
- },
45
- formatSelection: function (product) {
46
- return product.name;
47
- }
46
+ formatResult: formatProduct,
47
+ formatSelection: formatProduct
48
48
  });
49
49
  };
50
50
 
@@ -17,5 +17,5 @@ jQuery ->
17
17
  return { results: data.stock_items, more: more }
18
18
  formatResult: (stock_item) ->
19
19
  variantTemplate({ variant: stock_item.variant })
20
- formatSelection: (stock_item) ->
21
- "#{stock_item.variant.name} (#{stock_item.variant.options_text})"
20
+ formatSelection: (stock_item, container, excapeMarkup) ->
21
+ Select2.util.escapeMarkup("#{stock_item.variant.name} (#{stock_item.variant.options_text})")
@@ -1,6 +1,10 @@
1
1
  'use strict';
2
2
 
3
3
  var set_taxon_select = function(){
4
+ function formatTaxon(taxon) {
5
+ return Select2.util.escapeMarkup(taxon.pretty_name);
6
+ }
7
+
4
8
  if ($('#product_taxon_ids').length > 0) {
5
9
  $('#product_taxon_ids').select2({
6
10
  placeholder: Spree.translations.taxon_placeholder,
@@ -37,12 +41,8 @@ var set_taxon_select = function(){
37
41
  };
38
42
  }
39
43
  },
40
- formatResult: function (taxon) {
41
- return taxon.pretty_name;
42
- },
43
- formatSelection: function (taxon) {
44
- return taxon.pretty_name;
45
- }
44
+ formatResult: formatTaxon,
45
+ formatSelection: formatTaxon
46
46
  });
47
47
  }
48
48
  }
@@ -45,6 +45,9 @@ $ ->
45
45
  sortable.trigger('sortupdate', item: draggable)
46
46
  , 250
47
47
 
48
+ formatTaxon = (taxon) ->
49
+ Select2.util.escapeMarkup(taxon.pretty_name)
50
+
48
51
  $('#taxon_id').select2
49
52
  dropdownCssClass: "taxon_select_box",
50
53
  placeholder: Spree.translations.find_a_taxon,
@@ -59,10 +62,8 @@ $ ->
59
62
  results: (data) ->
60
63
  results: data['taxons'],
61
64
  more: data.current_page < data.pages
62
- formatResult: (taxon) ->
63
- taxon.pretty_name
64
- formatSelection: (taxon) ->
65
- taxon.pretty_name
65
+ formatResult: formatTaxon,
66
+ formatSelection: formatTaxon
66
67
 
67
68
  $('#taxon_id').on "change", (e) ->
68
69
  Spree.ajax
@@ -1,6 +1,10 @@
1
1
  $.fn.userAutocomplete = function () {
2
2
  'use strict';
3
3
 
4
+ function formatUser(user) {
5
+ return Select2.util.escapeMarkup(user.email);
6
+ }
7
+
4
8
  this.select2({
5
9
  minimumInputLength: 1,
6
10
  multiple: true,
@@ -8,7 +12,7 @@ $.fn.userAutocomplete = function () {
8
12
  $.get(Spree.routes.user_search, {
9
13
  ids: element.val()
10
14
  }, function (data) {
11
- callback(data);
15
+ callback(data.users);
12
16
  });
13
17
  },
14
18
  ajax: {
@@ -23,16 +27,12 @@ $.fn.userAutocomplete = function () {
23
27
  },
24
28
  results: function (data) {
25
29
  return {
26
- results: data
30
+ results: data.users
27
31
  };
28
32
  }
29
33
  },
30
- formatResult: function (user) {
31
- return user.email;
32
- },
33
- formatSelection: function (user) {
34
- return user.email;
35
- }
34
+ formatResult: formatUser,
35
+ formatSelection: formatUser
36
36
  });
37
37
  };
38
38
 
@@ -33,8 +33,8 @@ $.fn.variantAutocomplete = (searchOptions = {}) ->
33
33
  results: data["variants"]
34
34
 
35
35
  formatResult: formatVariantResult
36
- formatSelection: (variant) ->
36
+ formatSelection: (variant, container, escapeMarkup) ->
37
37
  if !!variant.options_text
38
- variant.name + " (#{variant.options_text})"
38
+ Select2.util.escapeMarkup("#{variant.name} (#{variant.options_text}")
39
39
  else
40
- variant.name
40
+ Select2.util.escapeMarkup(variant.name)
@@ -26,11 +26,15 @@ module Spree
26
26
  parts << variant.product.name
27
27
  parts << "(#{variant.options_text})" if variant.options_text.present?
28
28
  parts << line_item.display_total
29
- parts.join("<br>").html_safe
29
+ safe_join(parts, "<br />".html_safe)
30
30
  end
31
31
 
32
32
  def display_shipment(shipment)
33
- "#{Spree.t(:shipment)} ##{shipment.number}<br>#{shipment.display_cost}".html_safe
33
+ parts = [
34
+ "#{Spree.t(:shipment)} ##{shipment.number}",
35
+ shipment.display_cost
36
+ ]
37
+ safe_join(parts, "<br />".html_safe)
34
38
  end
35
39
 
36
40
  def display_order(order)
@@ -15,8 +15,8 @@ module Spree
15
15
  obj = object.respond_to?(:errors) ? object : instance_variable_get("@#{object}")
16
16
 
17
17
  if obj && obj.errors[method].present?
18
- errors = obj.errors[method].map { |err| h(err) }.join('<br />').html_safe
19
- content_tag(:span, errors, :class => 'formError')
18
+ errors = safe_join(obj.errors[method], "<br />".html_safe)
19
+ content_tag(:span, errors, class: 'formError')
20
20
  else
21
21
  ''
22
22
  end
@@ -132,12 +132,11 @@ module Spree
132
132
 
133
133
  def preference_fields(object, form)
134
134
  return unless object.respond_to?(:preferences)
135
- object.preferences.keys.map{ |key|
136
-
135
+ fields = object.preferences.keys.map { |key|
137
136
  form.label("preferred_#{key}", Spree.t(key) + ": ") +
138
- preference_field_for(form, "preferred_#{key}", :type => object.preference_type(key))
139
-
140
- }.join("<br />").html_safe
137
+ preference_field_for(form, "preferred_#{key}", type: object.preference_type(key))
138
+ }
139
+ safe_join(fields, "<br />".html_safe)
141
140
  end
142
141
 
143
142
  def link_to_add_fields(name, target, options = {})
@@ -74,7 +74,7 @@ module Spree
74
74
  options[:class] = (options[:class].to_s + " fa fa-#{icon_name} icon_link with-tip").strip
75
75
  options[:class] += ' no-text' if options[:no_text]
76
76
  options[:title] = text if options[:no_text]
77
- text = options[:no_text] ? '' : raw("<span class='text'>#{text}</span>")
77
+ text = options[:no_text] ? '' : content_tag(:span, text, class: 'text')
78
78
  options.delete(:no_text)
79
79
  link_to(text, url, options)
80
80
  end
@@ -107,16 +107,10 @@ module Spree
107
107
  if html_options[:icon]
108
108
  html_options[:class] += " fa fa-#{html_options[:icon]}"
109
109
  end
110
- link_to(text_for_button_link(text, html_options), url, html_options)
110
+ link_to(text, url, html_options)
111
111
  end
112
112
  end
113
113
 
114
- def text_for_button_link(text, html_options)
115
- s = ''
116
- s << text
117
- raw(s)
118
- end
119
-
120
114
  def configurations_menu_item(link_text, url, description = '')
121
115
  %(<tr>
122
116
  <td>#{link_to(link_text, url)}</td>
@@ -12,7 +12,7 @@ module Spree
12
12
  :data => { :confirm => Spree.t(:order_sure_want_to, :event => Spree.t(event)) })
13
13
  end
14
14
  end
15
- links.join('&nbsp;').html_safe
15
+ safe_join(links, '&nbsp;'.html_safe)
16
16
  end
17
17
 
18
18
  def line_item_shipment_price(line_item, quantity)
@@ -9,7 +9,8 @@ module Spree
9
9
  :selected => ('selected' if selected)) do
10
10
  (taxon.ancestors.pluck(:name) + [taxon.name]).join(" -> ")
11
11
  end
12
- end.join("").html_safe
12
+ end
13
+ safe_join(options)
13
14
  end
14
15
 
15
16
  def option_types_options_for(product)
@@ -20,7 +21,8 @@ module Spree
20
21
  :selected => ('selected' if selected)) do
21
22
  option_type.name
22
23
  end
23
- end.join("").html_safe
24
+ end
25
+ safe_join(options)
24
26
  end
25
27
  end
26
28
  end
@@ -15,9 +15,9 @@ module Spree
15
15
 
16
16
  def display_variant(stock_movement)
17
17
  variant = stock_movement.stock_item.variant
18
- output = variant.name
19
- output += "<br>(#{variant.options_text})" unless variant.options_text.blank?
20
- output.html_safe
18
+ output = [variant.name]
19
+ output << variant.options_text unless variant.options_text.blank?
20
+ safe_join(output, "<br />".html_safe)
21
21
  end
22
22
  end
23
23
  end
@@ -1,4 +1,4 @@
1
- collection(@users)
1
+ collection(@users => :users)
2
2
  attributes :email, :id
3
3
  address_fields = [:firstname, :lastname,
4
4
  :address1, :address2,
@@ -172,6 +172,18 @@ describe "New Order", :type => :feature do
172
172
  end
173
173
  end
174
174
 
175
+ context "customer with attempted XSS", js: true do
176
+ let(:xss_string) { %(<script>throw("XSS")</script>) }
177
+ before do
178
+ user.update!(email: xss_string)
179
+ end
180
+ it "displays the user's email escaped without executing" do
181
+ click_on "Customer Details"
182
+ targetted_select2_search user.email, from: "#s2id_customer_search"
183
+ expect(page).to have_field("Email", with: xss_string)
184
+ end
185
+ end
186
+
175
187
  def fill_in_address(kind = "bill")
176
188
  fill_in "First Name", with: "John 99"
177
189
  fill_in "Last Name", with: "Doe"
@@ -11,15 +11,16 @@ describe "Product Taxons", :type => :feature do
11
11
  Capybara.ignore_hidden_elements = false
12
12
  end
13
13
 
14
- context "managing taxons" do
14
+ context "managing taxons", js: true do
15
15
  def selected_taxons
16
16
  find("#product_taxon_ids").value.split(',').map(&:to_i).uniq
17
17
  end
18
18
 
19
- it "should allow an admin to manage taxons", :js => true do
19
+ let(:product) { create(:product) }
20
+
21
+ it "should allow an admin to manage taxons" do
20
22
  taxon_1 = create(:taxon)
21
- taxon_2 = create(:taxon, :name => 'Clothing')
22
- product = create(:product)
23
+ taxon_2 = create(:taxon, name: 'Clothing')
23
24
  product.taxons << taxon_1
24
25
 
25
26
  visit spree.admin_path
@@ -39,5 +40,17 @@ describe "Product Taxons", :type => :feature do
39
40
  expect(page).to have_css(".select2-search-choice", text: taxon_1.name)
40
41
  expect(page).to have_css(".select2-search-choice", text: taxon_2.name)
41
42
  end
43
+
44
+ context "with an XSS attempt" do
45
+ let(:taxon_name) { %(<script>throw("XSS")</script>) }
46
+ let!(:taxon) { create(:taxon, name: taxon_name) }
47
+ it "displays the escaped HTML without executing it" do
48
+ visit spree.edit_admin_product_path(product)
49
+
50
+ select2_search "<script>", from: "Taxons"
51
+
52
+ expect(page).to have_content(taxon_name)
53
+ end
54
+ end
42
55
  end
43
56
  end
@@ -36,6 +36,26 @@ feature 'Promotion with option value rule' do
36
36
  expect(first_rule.preferred_eligible_values).to eq Hash[product.id => [option_value.id]]
37
37
  end
38
38
 
39
+ context "with an attempted XSS" do
40
+ let(:xss_string) { %(<script>throw("XSS")</script>) }
41
+ before do
42
+ option_value.update!(name: xss_string)
43
+ end
44
+ scenario "adding an option value rule", js: true do
45
+ select2 "Option Value(s)", from: "Add rule of type"
46
+ within("#rules_container") { click_button "Add" }
47
+
48
+ within("#rules_container .promotion-block") do
49
+ click_button "Add"
50
+ end
51
+
52
+ within('.promo-rule-option-value') do
53
+ targetted_select2_search product.name, from: '.js-promo-rule-option-value-product-select'
54
+ targetted_select2_search option_value.name, from: '.js-promo-rule-option-value-option-values-select'
55
+ end
56
+ end
57
+ end
58
+
39
59
  context "with an existing option value rule" do
40
60
  given(:variant1) { create :variant }
41
61
  given(:variant2) { create :variant }
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ feature 'Promotion with user rule', js: true do
4
+ stub_authorization!
5
+
6
+ given(:promotion) { create :promotion }
7
+
8
+ background do
9
+ visit spree.edit_admin_promotion_path(promotion)
10
+ end
11
+
12
+ context "with an attempted XSS" do
13
+ let(:xss_string) { %(<script>throw("XSS")</script>) }
14
+ given!(:user) { create(:user, email: xss_string) }
15
+
16
+ scenario "adding an option value rule" do
17
+ select2 "User", from: "Add rule of type"
18
+ within("#rules_container") { click_button "Add" }
19
+
20
+ select2_search "<script>", from: "Choose users"
21
+
22
+ expect(page).to have_content(xss_string)
23
+ end
24
+ end
25
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: solidus_backend
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.2
4
+ version: 1.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Solidus Team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-01-22 00:00:00.000000000 Z
11
+ date: 2016-02-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: solidus_api
@@ -16,28 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - '='
18
18
  - !ruby/object:Gem::Version
19
- version: 1.1.2
19
+ version: 1.1.3
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - '='
25
25
  - !ruby/object:Gem::Version
26
- version: 1.1.2
26
+ version: 1.1.3
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: solidus_core
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - '='
32
32
  - !ruby/object:Gem::Version
33
- version: 1.1.2
33
+ version: 1.1.3
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - '='
39
39
  - !ruby/object:Gem::Version
40
- version: 1.1.2
40
+ version: 1.1.3
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: bourbon
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -662,6 +662,7 @@ files:
662
662
  - spec/features/admin/promotion_adjustments_spec.rb
663
663
  - spec/features/admin/promotions/option_value_rule_spec.rb
664
664
  - spec/features/admin/promotions/tiered_calculator_spec.rb
665
+ - spec/features/admin/promotions/user_rule_spec.rb
665
666
  - spec/features/admin/reports_spec.rb
666
667
  - spec/features/admin/stock_transfer_spec.rb
667
668
  - spec/features/admin/store_credits_spec.rb
@@ -734,3 +735,4 @@ signing_key:
734
735
  specification_version: 4
735
736
  summary: Admin interface for the Solidus e-commerce framework.
736
737
  test_files: []
738
+ has_rdoc: