solidus_backend 1.2.0 → 1.2.1

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.

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