shopify_app 12.0.0 → 12.0.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d7f75f25ebd3015036f89240acd78fb1d38bd85c6c61c361df564e0eaa1e2195
4
- data.tar.gz: 5b91f6dd61dd686a9cce74123a3b6de0498f683488204768542aa128e312f90f
3
+ metadata.gz: 3552d2c9437c900a3217f00b142d81d187cfad26a4a3ea84ca3e1b64cb03dc14
4
+ data.tar.gz: 6aa9bde06b9635c5d61c6c01271ee073f54b7473ee4dbce8c4cf3af9f776d1aa
5
5
  SHA512:
6
- metadata.gz: 9119cf0bf9b9ad3a9f03c89877a7fc2337b99a98b36ec5ec01446b9a9ef15841e0bf7ba05631d15d827b5b32c535c1176f5b4b46227846ace43d27c9d55155cb
7
- data.tar.gz: c084b5f9fd03727c865621a6615e2837179f262941b2ef3c5b083515d4e23b075e0d904f9cccee29140c78d117c2624fad4ef73c883aaa0ba087d0bc816a9685
6
+ metadata.gz: 1b1c648bd6ecc8ed980b1f15354edb3a85856a4d80c5598b020cc4d9dd0bec1bfb90da82c01bcefeb9deb75376fc023d43f5b3b406aaecc77fab03061c63c8fb
7
+ data.tar.gz: e3647c88c1b956c6ec76c8f0414a4f4c9e4ae3f97b5502adbd9e9507b7dbd94559d6905a3175f9a45267d5b6cd165ad6394bce08cb91530f8c777624c5ba9522
@@ -1,3 +1,28 @@
1
+ 12.0.5
2
+ -----
3
+ * Updating shopify_api gem to 9.0.1
4
+
5
+ 12.0.4
6
+ ------
7
+ * Reverts reverted PR (#895) #897
8
+
9
+ 12.0.3
10
+ ------
11
+ * Moves samesite middleware higher in the stack #898
12
+ * Fix issue where not redirecting user to granted storage page casues infinite loop #900
13
+
14
+ 12.0.2
15
+ ------
16
+ * Reverts "Fix for return_to in safari after enable_cookies/granted_storage_access" introduced in 12.0.1
17
+
18
+ 12.0.1
19
+ ------
20
+ * disable samesite cookie middleware in tests
21
+ * middleware compatibility for ruby 2.3
22
+ * samesite cookie fixes for javascript libraries
23
+ * change generators to add AppBridge instead of EASDK
24
+ * Fix for return_to in safari after enable_cookies/granted_storage_access
25
+
1
26
  12.0.0
2
27
  -----
3
28
  * Updating shopify_api gem to 9.0.0
data/README.md CHANGED
@@ -91,7 +91,9 @@ SHOPIFY_API_KEY=your api key
91
91
  SHOPIFY_API_SECRET=your api secret
92
92
  ```
93
93
 
94
- These values can be found on the "App Setup" page in the [Shopify Partners Dashboard][dashboard]. If you are checking your code into a code repository, ensure your `.gitignore` prevents your `.env` file from being checked into any publicly accessible code.
94
+ These values can be found on the "App Setup" page in the [Shopify Partners Dashboard][dashboard]. If you are checking your code into a code repository, ensure your `.gitignore` prevents your `.env` file from being checked into any publicly accessible code.
95
+
96
+ **You will need to load the ENV variables into your enviroment, you can do this with the [dot-env](https://github.com/bkeepers/dotenv) gem or any other method you wish to.**
95
97
 
96
98
  ### Install Generator
97
99
 
@@ -287,6 +289,14 @@ bin/rails g shopify_app:add_after_authenticate_job
287
289
 
288
290
  If you want to perform that action only once, e.g. send a welcome email to the user when they install the app, you should make sure that this action is idempotent, meaning that it won't have an impact if run multiple times.
289
291
 
292
+ API Versioning
293
+ --------------
294
+
295
+ Shopify's API is versioned, and you can [read about that process in the Shopify Developers documentation page](https://shopify.dev/concepts/about-apis/versioning).
296
+
297
+ Since shopify_app gem version 1.11.0, the included shopify_api gem has also been updated to allow you to easily set and switch what version of the Shopify API you want your app or service to use, as well as surface warnings to Rails apps about [deprecated endpoints, GraphQL fields and more](https://shopify.dev/concepts/about-apis/versioning#deprecation-practices).
298
+
299
+ See the [shopify_api gem README](https://github.com/Shopify/shopify_api/) for more details.
290
300
 
291
301
  WebhooksManager
292
302
  ---------------
@@ -4,31 +4,31 @@
4
4
  this.itpAction = document.getElementById('TopLevelInteractionButton');
5
5
  this.redirectUrl = opts.redirectUrl;
6
6
  }
7
-
7
+
8
8
  ITPHelper.prototype.redirect = function() {
9
9
  sessionStorage.setItem('shopify.top_level_interaction', true);
10
10
  window.location.href = this.redirectUrl;
11
11
  }
12
-
12
+
13
13
  ITPHelper.prototype.userAgentIsAffected = function() {
14
14
  return Boolean(document.hasStorageAccess);
15
15
  }
16
-
16
+
17
17
  ITPHelper.prototype.canPartitionCookies = function() {
18
18
  var versionRegEx = /Version\/12\.0\.?\d? Safari/;
19
19
  return versionRegEx.test(navigator.userAgent);
20
20
  }
21
-
21
+
22
22
  ITPHelper.prototype.setUpContent = function(onClick) {
23
23
  this.itpContent.style.display = 'block';
24
24
  this.itpAction.addEventListener('click', this.redirect.bind(this));
25
25
  }
26
-
26
+
27
27
  ITPHelper.prototype.execute = function() {
28
28
  if (!this.itpContent) {
29
29
  return;
30
30
  }
31
-
31
+
32
32
  if (this.userAgentIsAffected()) {
33
33
  this.setUpContent();
34
34
  } else {
@@ -28,18 +28,47 @@
28
28
  window.parent.location.href = this.redirectData.myshopifyUrl + '/admin/apps';
29
29
  }
30
30
 
31
- StorageAccessHelper.prototype.redirectToAppHome = function() {
32
- window.location.href = this.redirectData.appHomeUrl;
31
+ StorageAccessHelper.prototype.redirectToAppTargetUrl = function() {
32
+ window.location.href = this.redirectData.appTargetUrl;
33
+ }
34
+
35
+ StorageAccessHelper.prototype.sameSiteNoneIncompatible = function(ua) {
36
+ return ua.includes("iPhone OS 12_") || ua.includes("iPad; CPU OS 12_") || //iOS 12
37
+ (ua.includes("UCBrowser/")
38
+ ? this.isOlderUcBrowser(ua) //UC Browser < 12.13.2
39
+ : (ua.includes("Chrome/5") || ua.includes("Chrome/6"))) ||
40
+ ua.includes("Chromium/5") || ua.includes("Chromium/6") ||
41
+ (ua.includes(" OS X 10_14_") &&
42
+ ((ua.includes("Version/") && ua.includes("Safari")) || //Safari on MacOS 10.14
43
+ ua.endsWith("(KHTML, like Gecko)"))); //Web view on MacOS 10.14
44
+ }
45
+
46
+ StorageAccessHelper.prototype.isOlderUcBrowser = function(ua) {
47
+ var match = ua.match(/UCBrowser\/(\d+)\.(\d+)\.(\d+)\./);
48
+ if (!match) return false;
49
+ var major = parseInt(match[1]);
50
+ var minor = parseInt(match[2]);
51
+ var build = parseInt(match[3]);
52
+ if (major != 12) return major < 12;
53
+ if (minor != 13) return minor < 13;
54
+ return build < 2;
55
+ }
56
+
57
+ StorageAccessHelper.prototype.setCookie = function(value) {
58
+ if(!this.sameSiteNoneIncompatible(navigator.userAgent)) {
59
+ value += '; secure; SameSite=None'
60
+ }
61
+ document.cookie = value;
33
62
  }
34
63
 
35
64
  StorageAccessHelper.prototype.grantedStorageAccess = function() {
36
65
  try {
37
66
  sessionStorage.setItem('shopify.granted_storage_access', true);
38
- document.cookie = 'shopify.granted_storage_access=true';
67
+ this.setCookie('shopify.granted_storage_access=true');
39
68
  if (!document.cookie) {
40
69
  throw 'Cannot set third-party cookie.'
41
70
  }
42
- this.redirectToAppHome();
71
+ this.redirectToAppTargetUrl();
43
72
  } catch (error) {
44
73
  console.warn('Third party cookies may be blocked.', error);
45
74
  this.redirectToAppTLD(ACCESS_DENIED_STATUS);
@@ -61,7 +90,7 @@
61
90
  StorageAccessHelper.prototype.handleHasStorageAccess = function() {
62
91
  if (sessionStorage.getItem('shopify.granted_storage_access')) {
63
92
  // If app was classified by ITP and used Storage Access API to acquire access
64
- this.redirectToAppHome();
93
+ this.redirectToAppTargetUrl();
65
94
  } else {
66
95
  // If app has not been classified by ITP and still has storage access
67
96
  this.redirectToAppTLD(ACCESS_GRANTED_STATUS);
@@ -107,7 +136,7 @@
107
136
  }
108
137
 
109
138
  StorageAccessHelper.prototype.setCookieAndRedirect = function() {
110
- document.cookie = "shopify.cookies_persist=true";
139
+ this.setCookie('shopify.cookies_persist=true');
111
140
  var helper = this.setUpHelper();
112
141
  helper.redirect();
113
142
  }
@@ -20,11 +20,15 @@ module ShopifyApp
20
20
 
21
21
  render(:enable_cookies, layout: false, locals: {
22
22
  does_not_have_storage_access_url: top_level_interaction_path(
23
- shop: sanitized_shop_name
23
+ shop: sanitized_shop_name,
24
+ return_to: params[:return_to]
24
25
  ),
25
26
  has_storage_access_url: login_url_with_optional_shop(top_level: true),
26
- app_home_url: granted_storage_access_path(shop: sanitized_shop_name),
27
- current_shopify_domain: current_shopify_domain,
27
+ app_target_url: granted_storage_access_path(
28
+ shop: sanitized_shop_name,
29
+ return_to: params[:return_to]
30
+ ),
31
+ current_shopify_domain: current_shopify_domain
28
32
  })
29
33
  end
30
34
 
@@ -38,8 +42,9 @@ module ShopifyApp
38
42
 
39
43
  session['shopify.granted_storage_access'] = true
40
44
 
41
- params = { shop: @shop }
42
- redirect_to("#{return_address}?#{params.to_query}")
45
+ copy_return_to_param_to_session
46
+
47
+ redirect_to(return_address_with_params({ shop: @shop }))
43
48
  end
44
49
 
45
50
  def destroy
@@ -54,7 +59,7 @@ module ShopifyApp
54
59
  return render_invalid_shop_error unless sanitized_shop_name.present?
55
60
  session['shopify.omniauth_params'] = { shop: sanitized_shop_name }
56
61
 
57
- session[:return_to] = params[:return_to] if params[:return_to]
62
+ copy_return_to_param_to_session
58
63
 
59
64
  if user_agent_can_partition_cookies
60
65
  authenticate_with_partitioning
@@ -93,6 +98,10 @@ module ShopifyApp
93
98
  true
94
99
  end
95
100
 
101
+ def copy_return_to_param_to_session
102
+ session[:return_to] = params[:return_to] if params[:return_to]
103
+ end
104
+
96
105
  def render_invalid_shop_error
97
106
  flash[:error] = I18n.t('invalid_shop_url')
98
107
  redirect_to return_address
@@ -133,11 +142,15 @@ module ShopifyApp
133
142
  layout: false,
134
143
  locals: {
135
144
  does_not_have_storage_access_url: top_level_interaction_path(
136
- shop: sanitized_shop_name
145
+ shop: sanitized_shop_name,
146
+ return_to: session[:return_to]
137
147
  ),
138
148
  has_storage_access_url: login_url_with_optional_shop(top_level: true),
139
- app_home_url: granted_storage_access_path(shop: sanitized_shop_name),
140
- current_shopify_domain: current_shopify_domain,
149
+ app_target_url: granted_storage_access_path(
150
+ shop: sanitized_shop_name,
151
+ return_to: session[:return_to]
152
+ ),
153
+ current_shopify_domain: current_shopify_domain
141
154
  }
142
155
  )
143
156
  end
@@ -32,7 +32,7 @@
32
32
  myshopifyUrl: "https://#{current_shopify_domain}",
33
33
  hasStorageAccessUrl: "#{has_storage_access_url}",
34
34
  doesNotHaveStorageAccessUrl: "#{does_not_have_storage_access_url}",
35
- appHomeUrl: "#{app_home_url}"
35
+ appTargetUrl: "#{app_target_url}"
36
36
  },
37
37
  },
38
38
  )
@@ -24,7 +24,7 @@
24
24
  myshopifyUrl: "https://#{current_shopify_domain}",
25
25
  hasStorageAccessUrl: "#{has_storage_access_url}",
26
26
  doesNotHaveStorageAccessUrl: "#{does_not_have_storage_access_url}",
27
- appHomeUrl: "#{app_home_url}"
27
+ appTargetUrl: "#{app_target_url}"
28
28
  },
29
29
  },
30
30
  )
@@ -4,7 +4,7 @@ pt-BR:
4
4
  could_not_log_in: Não foi possível fazer login na Shopify store
5
5
  invalid_shop_url: Domínio de loja inválido
6
6
  enable_cookies_heading: Habilitar cookies de %{app}
7
- enable_cookies_body: Você deve habilitar manualmente os cookies neste navegador
7
+ enable_cookies_body: Você precisa habilitar manualmente os cookies neste navegador
8
8
  para usar %{app} dentro da Shopify.
9
9
  enable_cookies_footer: Os cookies permitem que o app o autentique armazenando temporariamente
10
10
  suas preferências e dados pessoais. Eles expiram depois de 30 dias.
@@ -3,11 +3,7 @@
3
3
  class MarketingActivitiesController < ShopifyApp::ExtensionVerificationController
4
4
  def preload_form_data
5
5
  preload_data = {
6
- "form_data": {
7
- "budget": {
8
- "currency": "USD",
9
- }
10
- }
6
+ "form_data": {}
11
7
  }
12
8
  render(json: preload_data, status: :ok)
13
9
  end
@@ -5,7 +5,7 @@ module ShopifyApp
5
5
  # for the app in your Shopify Partners page. Change your settings in
6
6
  # `config/initializers/shopify_app.rb`
7
7
  attr_accessor :application_name
8
- attr_accessor :api_key
8
+ attr_reader :api_key
9
9
  attr_accessor :secret
10
10
  attr_accessor :old_secret
11
11
  attr_accessor :scope
@@ -65,8 +65,14 @@ module ShopifyApp
65
65
  scripttags.present?
66
66
  end
67
67
 
68
+ def api_key=(key)
69
+ raise 'API Key is required and is being returned nil. \
70
+ This may indicate that your enviroment variables have not been loaded.' if key.nil?
71
+ @api_key = key
72
+ end
73
+
68
74
  def enable_same_site_none
69
- @enable_same_site_none.nil? ? embedded_app? : @enable_same_site_none
75
+ !Rails.env.test? && (@enable_same_site_none.nil? ? embedded_app? : @enable_same_site_none)
70
76
  end
71
77
  end
72
78
 
@@ -100,8 +100,10 @@ module ShopifyApp
100
100
  query_params = {}
101
101
  query_params[:shop] = sanitized_params[:shop] if params[:shop].present?
102
102
 
103
- if session[:return_to] && return_to_param_required?
104
- query_params[:return_to] = session[:return_to]
103
+ return_to = session[:return_to] || params[:return_to]
104
+
105
+ if return_to.present? && return_to_param_required?
106
+ query_params[:return_to] = return_to
105
107
  end
106
108
 
107
109
  has_referer_shop_name = referer_sanitized_shop_name.present?
@@ -165,5 +167,15 @@ module ShopifyApp
165
167
  def return_address
166
168
  session.delete(:return_to) || ShopifyApp.configuration.root_url
167
169
  end
170
+
171
+ def return_address_with_params(params)
172
+ uri = URI(return_address)
173
+ uri.query = CGI.parse(uri.query.to_s)
174
+ .symbolize_keys
175
+ .transform_values { |v| v.one? ? v.first : v }
176
+ .merge(params)
177
+ .to_query
178
+ uri.to_s
179
+ end
168
180
  end
169
181
  end
@@ -14,7 +14,7 @@ module ShopifyApp
14
14
  end
15
15
 
16
16
  initializer "shopify_app.middleware" do |app|
17
- app.config.middleware.insert_before(ActionDispatch::Cookies, ShopifyApp::SameSiteCookieMiddleware)
17
+ app.config.middleware.insert_after(::Rack::Runtime, ShopifyApp::SameSiteCookieMiddleware)
18
18
  end
19
19
  end
20
20
  end
@@ -1,60 +1,33 @@
1
1
  module ShopifyApp
2
2
  class SameSiteCookieMiddleware
3
+ COOKIE_SEPARATOR = "\n"
4
+
3
5
  def initialize(app)
4
6
  @app = app
5
7
  end
6
8
 
7
9
  def call(env)
8
- _status, headers, _body = @app.call(env)
9
- ensure
10
+ status, headers, body = @app.call(env)
10
11
  user_agent = env['HTTP_USER_AGENT']
11
12
 
12
- if headers && headers['Set-Cookie'] && !SameSiteCookieMiddleware.same_site_none_incompatible?(user_agent) &&
13
- ShopifyApp.configuration.enable_same_site_none
14
-
15
- cookies = headers['Set-Cookie'].split("\n").compact
16
-
17
- cookies.each do |cookie|
18
- unless cookie.include?("; SameSite")
19
- headers['Set-Cookie'] = headers['Set-Cookie'].gsub("#{cookie}", "#{cookie}; secure; SameSite=None")
13
+ if headers && headers['Set-Cookie'] &&
14
+ BrowserSniffer.new(user_agent).same_site_none_compatible? &&
15
+ ShopifyApp.configuration.enable_same_site_none &&
16
+ Rack::Request.new(env).ssl?
17
+
18
+ set_cookies = headers['Set-Cookie']
19
+ .split(COOKIE_SEPARATOR)
20
+ .compact
21
+ .map do |cookie|
22
+ cookie << '; Secure' if not cookie =~ /;\s*secure/i
23
+ cookie << '; SameSite=None' unless cookie =~ /;\s*samesite=/i
24
+ cookie
20
25
  end
21
- end
22
- end
23
- end
24
26
 
25
- def self.same_site_none_incompatible?(user_agent)
26
- sniffer = BrowserSniffer.new(user_agent)
27
-
28
- webkit_same_site_bug?(sniffer) || drops_unrecognized_same_site_cookies?(sniffer)
29
- rescue
30
- true
31
- end
32
-
33
- def self.webkit_same_site_bug?(sniffer)
34
- (sniffer.os == :ios && sniffer.os_version.match?(/^([0-9]|1[12])[\.\_]/)) ||
35
- (sniffer.os == :mac && sniffer.browser == :safari && sniffer.os_version.match?(/^10[\.\_]14/))
36
- end
37
-
38
- def self.drops_unrecognized_same_site_cookies?(sniffer)
39
- (chromium_based?(sniffer) && sniffer.major_browser_version >= 51 && sniffer.major_browser_version <= 66) ||
40
- (uc_browser?(sniffer) && !uc_browser_version_at_least?(sniffer: sniffer, major: 12, minor: 13, build: 2))
41
- end
42
-
43
- def self.chromium_based?(sniffer)
44
- sniffer.browser_name.downcase.match?(/chrom(e|ium)/)
45
- end
46
-
47
- def self.uc_browser?(sniffer)
48
- sniffer.user_agent.downcase.match?(/uc\s?browser/)
49
- end
50
-
51
- def self.uc_browser_version_at_least?(sniffer:, major:, minor:, build:)
52
- digits = sniffer.browser_version.split('.').map(&:to_i)
53
- return false unless digits.count >= 3
27
+ headers['Set-Cookie'] = set_cookies.join(COOKIE_SEPARATOR)
28
+ end
54
29
 
55
- return digits[0] > major if digits[0] != major
56
- return digits[1] > minor if digits[1] != minor
57
- digits[2] >= build
30
+ [status, headers, body]
58
31
  end
59
32
  end
60
33
  end
@@ -1,3 +1,3 @@
1
1
  module ShopifyApp
2
- VERSION = '12.0.0'.freeze
2
+ VERSION = '12.0.5'.freeze
3
3
  end
@@ -1,5 +1,6 @@
1
1
  {
2
2
  "name": "shopify_app",
3
+ "version": "12.0.5",
3
4
  "repository": "git@github.com:Shopify/shopify_app.git",
4
5
  "author": "Shopify",
5
6
  "license": "MIT",
@@ -23,6 +24,5 @@
23
24
  },
24
25
  "scripts": {
25
26
  "test": "./node_modules/.bin/karma start --browsers ChromeHeadless --single-run"
26
- },
27
- "version": "12.0.0"
27
+ }
28
28
  }
@@ -10,9 +10,9 @@ Gem::Specification.new do |s|
10
10
 
11
11
  s.required_ruby_version = ">= 2.3.1"
12
12
 
13
- s.add_runtime_dependency('browser_sniffer', '~> 1.1.3')
13
+ s.add_runtime_dependency('browser_sniffer', '~> 1.2.0')
14
14
  s.add_runtime_dependency('rails', '> 5.2.1')
15
- s.add_runtime_dependency('shopify_api', '~> 9.0')
15
+ s.add_runtime_dependency('shopify_api', '~> 9.0.1')
16
16
  s.add_runtime_dependency('omniauth-shopify-oauth2', '~> 2.2.0')
17
17
 
18
18
  s.add_development_dependency('rake')
@@ -29,4 +29,4 @@ Gem::Specification.new do |s|
29
29
  s.files = `git ls-files`.split("\n").reject { |f| f.match(%r{^(test|example)/}) }
30
30
  s.test_files = `git ls-files -- {test}/*`.split("\n")
31
31
  s.require_paths = ["lib"]
32
- end
32
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shopify_app
3
3
  version: !ruby/object:Gem::Version
4
- version: 12.0.0
4
+ version: 12.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shopify
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-01-29 00:00:00.000000000 Z
11
+ date: 2020-03-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: browser_sniffer
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 1.1.3
19
+ version: 1.2.0
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.3
26
+ version: 1.2.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rails
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -44,14 +44,14 @@ dependencies:
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '9.0'
47
+ version: 9.0.1
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '9.0'
54
+ version: 9.0.1
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: omniauth-shopify-oauth2
57
57
  requirement: !ruby/object:Gem::Requirement