solidus_backend 1.2.0 → 1.2.1

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: efdeca518bb3d26ba1e31ff07f84ca9d4ede7a2e
4
- data.tar.gz: 0d269d24b4a5c39ac7f1c432a4e2175f20f6ac71
3
+ metadata.gz: 87c62b3326ebc0d631669e3dc6d60879fe2a11b3
4
+ data.tar.gz: 246d61ab89e432641d5616cfe179f2eddc866707
5
5
  SHA512:
6
- metadata.gz: 6e90d731e9767b81704f964c19e544a88adb6267a9ad40d1e53808b3b99d7448768bfb64312d533eef18edc6b98e3713f4f144089d95839937fd537ac9b6cf54
7
- data.tar.gz: 4b24fe70e865c1abd391834370c01241f4e1f79cecef31b5d5b9db6ed93c77debe2253e4432410b58088d9e3827f18ea00362587424a32c40023b8adc22b899a
6
+ metadata.gz: 11ab1253fe0a288fe11bd7f308e209fb303496e005b49d60427e07e78ed8eca9d974a60a2c7294504d7f6ef254a583fbe2319daaaffcd3284b8d5dde844371be
7
+ data.tar.gz: 4af71715d6cea8635f07f798c005fce1fffa8d296742567cf48665423271c70147d312a1d81a490f41384e78bbac49d98d66b3e60ffa36abb87e3e98ad88636f
@@ -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
@@ -108,16 +108,10 @@ module Spree
108
108
  if html_options[:icon]
109
109
  html_options[:class] += " fa fa-#{html_options[:icon]}"
110
110
  end
111
- link_to(text_for_button_link(text, html_options), url, html_options)
111
+ link_to(text, url, html_options)
112
112
  end
113
113
  end
114
114
 
115
- def text_for_button_link(text, html_options)
116
- s = ''
117
- s << text
118
- raw(s)
119
- end
120
-
121
115
  def configurations_menu_item(link_text, url, description = '')
122
116
  %(<tr>
123
117
  <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,
@@ -1 +1 @@
1
- Rails.application.config.assets.precompile += %w( jquery-ui/* )
1
+ Rails.application.config.assets.precompile += %w( jquery-ui/* solidus-style-guide-logo.png )
@@ -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"
@@ -3,7 +3,7 @@ require 'spec_helper'
3
3
  describe "Product Taxons", :type => :feature do
4
4
  stub_authorization!
5
5
 
6
- context "managing taxons" do
6
+ context "managing taxons", js: true do
7
7
  def assert_selected_taxons(taxons)
8
8
  # Regression test for https://github.com/spree/spree/issues/2139
9
9
  taxons.each do |taxon|
@@ -14,10 +14,11 @@ describe "Product Taxons", :type => :feature do
14
14
  expect(page).to have_xpath("//*[@id = 'product_taxon_ids' and @value = '#{expected_value}']", visible: :all)
15
15
  end
16
16
 
17
- it "should allow an admin to manage taxons", :js => true do
17
+ let(:product) { create(:product) }
18
+
19
+ it "should allow an admin to manage taxons" do
18
20
  taxon_1 = create(:taxon)
19
- taxon_2 = create(:taxon, :name => 'Clothing')
20
- product = create(:product)
21
+ taxon_2 = create(:taxon, name: 'Clothing')
21
22
  product.taxons << taxon_1
22
23
 
23
24
  visit spree.edit_admin_product_path(product)
@@ -28,5 +29,17 @@ describe "Product Taxons", :type => :feature do
28
29
  click_button "Update"
29
30
  assert_selected_taxons([taxon_1, taxon_2])
30
31
  end
32
+
33
+ context "with an XSS attempt" do
34
+ let(:taxon_name) { %(<script>throw("XSS")</script>) }
35
+ let!(:taxon) { create(:taxon, name: taxon_name) }
36
+ it "displays the escaped HTML without executing it" do
37
+ visit spree.edit_admin_product_path(product)
38
+
39
+ select2_search "<script>", from: "Taxons"
40
+
41
+ expect(page).to have_content(taxon_name)
42
+ end
43
+ end
31
44
  end
32
45
  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
@@ -0,0 +1,12 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Style guide", type: :feature do
4
+ stub_authorization!
5
+
6
+ it "should render successfully" do
7
+ visit "/admin/style_guide"
8
+
9
+ # Somewhere in a style guide you'd expect to talk about colors
10
+ expect(page).to have_text "Colors"
11
+ end
12
+ 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.2.0
4
+ version: 1.2.1
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-26 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.2.0
19
+ version: 1.2.1
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.2.0
26
+ version: 1.2.1
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.2.0
33
+ version: 1.2.1
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.2.0
40
+ version: 1.2.1
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: bourbon
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -692,9 +692,11 @@ files:
692
692
  - spec/features/admin/promotion_adjustments_spec.rb
693
693
  - spec/features/admin/promotions/option_value_rule_spec.rb
694
694
  - spec/features/admin/promotions/tiered_calculator_spec.rb
695
+ - spec/features/admin/promotions/user_rule_spec.rb
695
696
  - spec/features/admin/reports_spec.rb
696
697
  - spec/features/admin/stock_transfer_spec.rb
697
698
  - spec/features/admin/store_credits_spec.rb
699
+ - spec/features/admin/style_guide_spec.rb
698
700
  - spec/features/admin/taxons_spec.rb
699
701
  - spec/features/admin/users_spec.rb
700
702
  - spec/helpers/admin/base_helper_spec.rb