shopify_app 13.0.0 → 13.0.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.
- checksums.yaml +4 -4
- data/.rubocop.yml +13 -6
- data/CHANGELOG.md +10 -0
- data/Gemfile +3 -0
- data/README.md +32 -1
- data/Rakefile +1 -0
- data/app/controllers/shopify_app/authenticated_controller.rb +1 -0
- data/app/controllers/shopify_app/callback_controller.rb +1 -1
- data/app/controllers/shopify_app/sessions_controller.rb +8 -5
- data/app/controllers/shopify_app/webhooks_controller.rb +6 -5
- data/config/locales/fi.yml +1 -1
- data/config/routes.rb +1 -0
- data/lib/generators/shopify_app/add_after_authenticate_job/add_after_authenticate_job_generator.rb +5 -3
- data/lib/generators/shopify_app/add_after_authenticate_job/templates/after_authenticate_job.rb +1 -0
- data/lib/generators/shopify_app/add_marketing_activity_extension/add_marketing_activity_extension_generator.rb +2 -1
- data/lib/generators/shopify_app/add_marketing_activity_extension/templates/marketing_activities_controller.rb +4 -4
- data/lib/generators/shopify_app/add_webhook/add_webhook_generator.rb +5 -4
- data/lib/generators/shopify_app/add_webhook/templates/webhook_job.rb +5 -0
- data/lib/generators/shopify_app/app_proxy_controller/app_proxy_controller_generator.rb +4 -3
- data/lib/generators/shopify_app/app_proxy_controller/templates/app_proxy_controller.rb +3 -3
- data/lib/generators/shopify_app/app_proxy_controller/templates/app_proxy_route.rb +10 -9
- data/lib/generators/shopify_app/controllers/controllers_generator.rb +1 -0
- data/lib/generators/shopify_app/home_controller/home_controller_generator.rb +4 -3
- data/lib/generators/shopify_app/install/install_generator.rb +9 -8
- data/lib/generators/shopify_app/install/templates/omniauth.rb +2 -1
- data/lib/generators/shopify_app/install/templates/user_agent.rb +2 -1
- data/lib/generators/shopify_app/routes/routes_generator.rb +1 -0
- data/lib/generators/shopify_app/routes/templates/routes.rb +10 -9
- data/lib/generators/shopify_app/shop_model/shop_model_generator.rb +5 -4
- data/lib/generators/shopify_app/shop_model/templates/shop.rb +1 -0
- data/lib/generators/shopify_app/shopify_app_generator.rb +4 -3
- data/lib/generators/shopify_app/user_model/templates/user.rb +1 -0
- data/lib/generators/shopify_app/user_model/user_model_generator.rb +5 -4
- data/lib/generators/shopify_app/views/views_generator.rb +1 -0
- data/lib/shopify_app.rb +7 -4
- data/lib/shopify_app/configuration.rb +15 -8
- data/lib/shopify_app/controller_concerns/app_proxy_verification.rb +3 -2
- data/lib/shopify_app/controller_concerns/embedded_app.rb +3 -2
- data/lib/shopify_app/controller_concerns/localization.rb +1 -0
- data/lib/shopify_app/controller_concerns/login_protection.rb +46 -11
- data/lib/shopify_app/controller_concerns/webhook_verification.rb +2 -1
- data/lib/shopify_app/engine.rb +1 -0
- data/lib/shopify_app/jobs/scripttags_manager_job.rb +1 -1
- data/lib/shopify_app/jobs/webhooks_manager_job.rb +1 -1
- data/lib/shopify_app/managers/scripttags_manager.rb +4 -3
- data/lib/shopify_app/managers/webhooks_manager.rb +4 -3
- data/lib/shopify_app/middleware/same_site_cookie_middleware.rb +2 -1
- data/lib/shopify_app/session/in_memory_session_store.rb +7 -3
- data/lib/shopify_app/session/in_memory_shop_session_store.rb +10 -0
- data/lib/shopify_app/session/in_memory_user_session_store.rb +10 -0
- data/lib/shopify_app/session/jwt.rb +48 -0
- data/lib/shopify_app/session/null_user_session_store.rb +22 -0
- data/lib/shopify_app/session/session_repository.rb +13 -16
- data/lib/shopify_app/session/session_storage.rb +1 -0
- data/lib/shopify_app/session/shop_session_storage.rb +21 -9
- data/lib/shopify_app/session/user_session_storage.rb +19 -8
- data/lib/shopify_app/test_helpers/all.rb +1 -0
- data/lib/shopify_app/test_helpers/webhook_verification_helper.rb +16 -0
- data/lib/shopify_app/utils.rb +6 -5
- data/lib/shopify_app/version.rb +2 -1
- data/package-lock.json +4 -4
- data/package.json +1 -1
- data/shopify_app.gemspec +8 -4
- data/yarn.lock +3 -3
- metadata +22 -3
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module ShopifyApp
|
2
3
|
class ScripttagsManager
|
3
4
|
class CreationFailed < StandardError; end
|
@@ -43,7 +44,7 @@ module ShopifyApp
|
|
43
44
|
def destroy_scripttags
|
44
45
|
scripttags = expanded_scripttags
|
45
46
|
ShopifyAPI::ScriptTag.all.each do |tag|
|
46
|
-
ShopifyAPI::ScriptTag.delete(tag.id) if
|
47
|
+
ShopifyAPI::ScriptTag.delete(tag.id) if required_scripttag?(scripttags, tag)
|
47
48
|
end
|
48
49
|
|
49
50
|
@current_scripttags = nil
|
@@ -55,8 +56,8 @@ module ShopifyApp
|
|
55
56
|
self.class.build_src(required_scripttags, shop_domain)
|
56
57
|
end
|
57
58
|
|
58
|
-
def
|
59
|
-
scripttags.map{ |w| w[:src] }.include?
|
59
|
+
def required_scripttag?(scripttags, tag)
|
60
|
+
scripttags.map { |w| w[:src] }.include?(tag.src)
|
60
61
|
end
|
61
62
|
|
62
63
|
def create_scripttag(attributes)
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module ShopifyApp
|
2
3
|
class WebhooksManager
|
3
4
|
class CreationFailed < StandardError; end
|
@@ -31,7 +32,7 @@ module ShopifyApp
|
|
31
32
|
|
32
33
|
def destroy_webhooks
|
33
34
|
ShopifyAPI::Webhook.all.to_a.each do |webhook|
|
34
|
-
ShopifyAPI::Webhook.delete(webhook.id) if
|
35
|
+
ShopifyAPI::Webhook.delete(webhook.id) if required_webhook?(webhook)
|
35
36
|
end
|
36
37
|
|
37
38
|
@current_webhooks = nil
|
@@ -39,8 +40,8 @@ module ShopifyApp
|
|
39
40
|
|
40
41
|
private
|
41
42
|
|
42
|
-
def
|
43
|
-
required_webhooks.map{ |w| w[:address] }.include?
|
43
|
+
def required_webhook?(webhook)
|
44
|
+
required_webhooks.map { |w| w[:address] }.include?(webhook.address)
|
44
45
|
end
|
45
46
|
|
46
47
|
def create_webhook(attributes)
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module ShopifyApp
|
2
3
|
class SameSiteCookieMiddleware
|
3
4
|
COOKIE_SEPARATOR = "\n"
|
@@ -19,7 +20,7 @@ module ShopifyApp
|
|
19
20
|
.split(COOKIE_SEPARATOR)
|
20
21
|
.compact
|
21
22
|
.map do |cookie|
|
22
|
-
cookie << '; Secure'
|
23
|
+
cookie << '; Secure' unless cookie =~ /;\s*secure/i
|
23
24
|
cookie << '; SameSite=None' unless cookie =~ /;\s*samesite=/i
|
24
25
|
cookie
|
25
26
|
end
|
@@ -1,4 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module ShopifyApp
|
3
|
+
# rubocop:disable Style/ClassVars
|
4
|
+
# Class var repo is needed here in order to share data between the 2 child classes.
|
2
5
|
class InMemorySessionStore
|
3
6
|
class EnvironmentError < StandardError; end
|
4
7
|
|
@@ -6,7 +9,7 @@ module ShopifyApp
|
|
6
9
|
repo[id]
|
7
10
|
end
|
8
11
|
|
9
|
-
def self.store(session, *
|
12
|
+
def self.store(session, *_args)
|
10
13
|
id = SecureRandom.uuid
|
11
14
|
repo[id] = session
|
12
15
|
id
|
@@ -18,10 +21,11 @@ module ShopifyApp
|
|
18
21
|
|
19
22
|
def self.repo
|
20
23
|
if Rails.env.production?
|
21
|
-
raise EnvironmentError
|
22
|
-
Please initialize ShopifyApp with a model that can store and retrieve sessions"
|
24
|
+
raise EnvironmentError, "Cannot use InMemorySessionStore in a Production environment. \
|
25
|
+
Please initialize ShopifyApp with a model that can store and retrieve sessions"
|
23
26
|
end
|
24
27
|
@@repo ||= {}
|
25
28
|
end
|
26
29
|
end
|
30
|
+
# rubocop:enable Style/ClassVars
|
27
31
|
end
|
@@ -1,4 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module ShopifyApp
|
2
3
|
class InMemoryShopSessionStore < InMemorySessionStore
|
4
|
+
def self.store(session, *args)
|
5
|
+
id = super
|
6
|
+
repo[session.domain] = session
|
7
|
+
id
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.retrieve_by_shopify_domain(shopify_domain)
|
11
|
+
repo[shopify_domain]
|
12
|
+
end
|
3
13
|
end
|
4
14
|
end
|
@@ -1,4 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module ShopifyApp
|
2
3
|
class InMemoryUserSessionStore < InMemorySessionStore
|
4
|
+
def self.store(session, user)
|
5
|
+
id = super
|
6
|
+
repo[user.shopify_user_id] = session
|
7
|
+
id
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.retrieve_by_shopify_user_id(user_id)
|
11
|
+
repo[user_id]
|
12
|
+
end
|
3
13
|
end
|
4
14
|
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module ShopifyApp
|
3
|
+
class JWT
|
4
|
+
def initialize(token)
|
5
|
+
@token = token
|
6
|
+
set_payload
|
7
|
+
end
|
8
|
+
|
9
|
+
def shopify_domain
|
10
|
+
payload && dest_host
|
11
|
+
end
|
12
|
+
|
13
|
+
def shopify_user_id
|
14
|
+
payload && payload['sub']
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def payload
|
20
|
+
return unless @payload
|
21
|
+
return unless dest_host
|
22
|
+
return unless dest_host == iss_host
|
23
|
+
return unless @payload['aud'] == ShopifyApp.configuration.api_key
|
24
|
+
|
25
|
+
@payload
|
26
|
+
end
|
27
|
+
|
28
|
+
def set_payload
|
29
|
+
@payload, _ = parse_token_data(ShopifyApp.configuration.secret)
|
30
|
+
configuration_old_secret = @payload && ShopifyApp.configuration
|
31
|
+
@payload, _ = parse_token_data(ShopifyApp.configuration.old_secret) unless configuration_old_secret
|
32
|
+
end
|
33
|
+
|
34
|
+
def parse_token_data(secret)
|
35
|
+
::JWT.decode(@token, secret, true, { algorithm: 'HS256' })
|
36
|
+
rescue ::JWT::DecodeError, ::JWT::VerificationError, ::JWT::ExpiredSignature, ::JWT::ImmatureSignature
|
37
|
+
nil
|
38
|
+
end
|
39
|
+
|
40
|
+
def dest_host
|
41
|
+
@payload && ShopifyApp::Utils.sanitize_shop_domain(@payload['dest'])
|
42
|
+
end
|
43
|
+
|
44
|
+
def iss_host
|
45
|
+
@payload && ShopifyApp::Utils.sanitize_shop_domain(@payload['iss'])
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module ShopifyApp
|
3
|
+
class NullUserSessionStore
|
4
|
+
class << self
|
5
|
+
def retrieve(_)
|
6
|
+
nil
|
7
|
+
end
|
8
|
+
|
9
|
+
def store(_, _)
|
10
|
+
raise SessionRepository::ConfigurationError, 'user_storage is not configured'
|
11
|
+
end
|
12
|
+
|
13
|
+
def retrieve_by_shopify_user_id(_)
|
14
|
+
nil
|
15
|
+
end
|
16
|
+
|
17
|
+
def blank?
|
18
|
+
true
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -1,23 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module ShopifyApp
|
2
3
|
class SessionRepository
|
3
4
|
class ConfigurationError < StandardError; end
|
4
5
|
|
5
6
|
class << self
|
6
|
-
|
7
|
-
@shop_storage = storage
|
7
|
+
attr_writer :shop_storage
|
8
8
|
|
9
|
-
|
10
|
-
raise ArgumentError, "shop storage must respond to :store and :retrieve"
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
def user_storage=(storage)
|
15
|
-
@user_storage = storage
|
16
|
-
|
17
|
-
unless storage.nil? || self.user_storage.respond_to?(:store) && self.user_storage.respond_to?(:retrieve)
|
18
|
-
raise ArgumentError, "user storage must respond to :store and :retrieve"
|
19
|
-
end
|
20
|
-
end
|
9
|
+
attr_writer :user_storage
|
21
10
|
|
22
11
|
def retrieve_shop_session(id)
|
23
12
|
shop_storage.retrieve(id)
|
@@ -27,6 +16,14 @@ module ShopifyApp
|
|
27
16
|
user_storage.retrieve(id)
|
28
17
|
end
|
29
18
|
|
19
|
+
def retrieve_shop_session_by_shopify_domain(shopify_domain)
|
20
|
+
shop_storage.retrieve_by_shopify_domain(shopify_domain)
|
21
|
+
end
|
22
|
+
|
23
|
+
def retrieve_user_session_by_shopify_user_id(user_id)
|
24
|
+
user_storage.retrieve_by_shopify_user_id(user_id)
|
25
|
+
end
|
26
|
+
|
30
27
|
def store_shop_session(session)
|
31
28
|
shop_storage.store(session)
|
32
29
|
end
|
@@ -36,7 +33,7 @@ module ShopifyApp
|
|
36
33
|
end
|
37
34
|
|
38
35
|
def shop_storage
|
39
|
-
load_shop_storage || raise(ConfigurationError
|
36
|
+
load_shop_storage || raise(ConfigurationError, "ShopifySessionRepository.shop_storage is not configured!")
|
40
37
|
end
|
41
38
|
|
42
39
|
def user_storage
|
@@ -51,7 +48,7 @@ module ShopifyApp
|
|
51
48
|
end
|
52
49
|
|
53
50
|
def load_user_storage
|
54
|
-
return unless @user_storage
|
51
|
+
return NullUserSessionStore unless @user_storage
|
55
52
|
@user_storage.respond_to?(:safe_constantize) ? @user_storage.safe_constantize : @user_storage
|
56
53
|
end
|
57
54
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module ShopifyApp
|
2
3
|
module ShopSessionStorage
|
3
4
|
extend ActiveSupport::Concern
|
@@ -8,7 +9,7 @@ module ShopifyApp
|
|
8
9
|
end
|
9
10
|
|
10
11
|
class_methods do
|
11
|
-
def store(auth_session, *
|
12
|
+
def store(auth_session, *_args)
|
12
13
|
shop = find_or_initialize_by(shopify_domain: auth_session.domain)
|
13
14
|
shop.shopify_token = auth_session.token
|
14
15
|
shop.save!
|
@@ -16,14 +17,25 @@ module ShopifyApp
|
|
16
17
|
end
|
17
18
|
|
18
19
|
def retrieve(id)
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
20
|
+
shop = find_by(id: id)
|
21
|
+
construct_session(shop)
|
22
|
+
end
|
23
|
+
|
24
|
+
def retrieve_by_shopify_domain(domain)
|
25
|
+
shop = find_by(shopify_domain: domain)
|
26
|
+
construct_session(shop)
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def construct_session(shop)
|
32
|
+
return unless shop
|
33
|
+
|
34
|
+
ShopifyAPI::Session.new(
|
35
|
+
domain: shop.shopify_domain,
|
36
|
+
token: shop.shopify_token,
|
37
|
+
api_version: shop.api_version,
|
38
|
+
)
|
27
39
|
end
|
28
40
|
end
|
29
41
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module ShopifyApp
|
2
3
|
module UserSessionStorage
|
3
4
|
extend ActiveSupport::Concern
|
@@ -17,14 +18,24 @@ module ShopifyApp
|
|
17
18
|
end
|
18
19
|
|
19
20
|
def retrieve(id)
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
21
|
+
user = find_by(id: id)
|
22
|
+
construct_session(user)
|
23
|
+
end
|
24
|
+
|
25
|
+
def retrieve_by_shopify_user_id(user_id)
|
26
|
+
user = find_by(shopify_user_id: user_id)
|
27
|
+
construct_session(user)
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def construct_session(user)
|
33
|
+
return unless user
|
34
|
+
ShopifyAPI::Session.new(
|
35
|
+
domain: user.shopify_domain,
|
36
|
+
token: user.shopify_token,
|
37
|
+
api_version: user.api_version,
|
38
|
+
)
|
28
39
|
end
|
29
40
|
end
|
30
41
|
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'shopify_app/test_helpers/webhook_verification_helper'
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module ShopifyApp
|
2
|
+
module TestHelpers
|
3
|
+
module WebhookVerificationHelper
|
4
|
+
def authorized_webhook_verification_headers!(params = {})
|
5
|
+
digest = OpenSSL::Digest.new('sha256')
|
6
|
+
secret = ShopifyApp.configuration.secret
|
7
|
+
valid_hmac = Base64.encode64(OpenSSL::HMAC.digest(digest, secret, params.to_query)).strip
|
8
|
+
@request.headers['HTTP_X_SHOPIFY_HMAC_SHA256'] = valid_hmac
|
9
|
+
end
|
10
|
+
|
11
|
+
def unauthorized_webhook_verification_headers!(params = {})
|
12
|
+
@request.headers['HTTP_X_SHOPIFY_HMAC_SHA256'] = "invalid_hmac"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/shopify_app/utils.rb
CHANGED
@@ -1,13 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module ShopifyApp
|
2
3
|
module Utils
|
3
|
-
|
4
4
|
def self.sanitize_shop_domain(shop_domain)
|
5
|
+
myshopify_domain = ShopifyApp.configuration.myshopify_domain
|
5
6
|
name = shop_domain.to_s.downcase.strip
|
6
|
-
name += ".#{
|
7
|
+
name += ".#{myshopify_domain}" if !name.include?(myshopify_domain.to_s) && !name.include?(".")
|
7
8
|
name.sub!(%r|https?://|, '')
|
8
9
|
|
9
10
|
u = URI("http://#{name}")
|
10
|
-
u.host if u.host&.match(/^[a-z0-9][a-z0-9\-]*[a-z0-9]\.#{Regexp.escape(
|
11
|
+
u.host if u.host&.match(/^[a-z0-9][a-z0-9\-]*[a-z0-9]\.#{Regexp.escape(myshopify_domain)}$/)
|
11
12
|
rescue URI::InvalidURIError
|
12
13
|
nil
|
13
14
|
end
|
@@ -16,8 +17,8 @@ module ShopifyApp
|
|
16
17
|
Rails.logger.info("[ShopifyAPI::ApiVersion] Fetching known Admin API Versions from Shopify...")
|
17
18
|
ShopifyAPI::ApiVersion.fetch_known_versions
|
18
19
|
Rails.logger.info("[ShopifyAPI::ApiVersion] Known API Versions: #{ShopifyAPI::ApiVersion.versions.keys}")
|
19
|
-
|
20
|
-
|
20
|
+
rescue ActiveResource::ConnectionError
|
21
|
+
logger.error("[ShopifyAPI::ApiVersion] Unable to fetch api_versions from Shopify")
|
21
22
|
end
|
22
23
|
end
|
23
24
|
end
|
data/lib/shopify_app/version.rb
CHANGED
data/package-lock.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "shopify_app",
|
3
|
-
"version": "
|
3
|
+
"version": "13.0.0",
|
4
4
|
"lockfileVersion": 1,
|
5
5
|
"requires": true,
|
6
6
|
"dependencies": {
|
@@ -1332,9 +1332,9 @@
|
|
1332
1332
|
}
|
1333
1333
|
},
|
1334
1334
|
"acorn": {
|
1335
|
-
"version": "6.
|
1336
|
-
"resolved": "https://registry.npmjs.org/acorn/-/acorn-6.
|
1337
|
-
"integrity": "sha512
|
1335
|
+
"version": "6.4.1",
|
1336
|
+
"resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz",
|
1337
|
+
"integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==",
|
1338
1338
|
"dev": true
|
1339
1339
|
},
|
1340
1340
|
"after": {
|
data/package.json
CHANGED
data/shopify_app.gemspec
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
$LOAD_PATH.push(File.expand_path('../lib', __FILE__))
|
2
3
|
require "shopify_app/version"
|
3
4
|
|
4
5
|
Gem::Specification.new do |s|
|
@@ -6,14 +7,17 @@ Gem::Specification.new do |s|
|
|
6
7
|
s.version = ShopifyApp::VERSION
|
7
8
|
s.platform = Gem::Platform::RUBY
|
8
9
|
s.author = "Shopify"
|
9
|
-
s.summary =
|
10
|
+
s.summary = 'This gem is used to get quickly started with the Shopify API'
|
10
11
|
|
11
12
|
s.required_ruby_version = ">= 2.3.1"
|
12
13
|
|
14
|
+
s.metadata['allowed_push_host'] = 'https://rubygems.org'
|
15
|
+
|
13
16
|
s.add_runtime_dependency('browser_sniffer', '~> 1.2.0')
|
14
17
|
s.add_runtime_dependency('rails', '> 5.2.1')
|
15
18
|
s.add_runtime_dependency('shopify_api', '~> 9.0.2')
|
16
19
|
s.add_runtime_dependency('omniauth-shopify-oauth2', '~> 2.2.2')
|
20
|
+
s.add_runtime_dependency('jwt', '~> 2.2.1')
|
17
21
|
|
18
22
|
s.add_development_dependency('rake')
|
19
23
|
s.add_development_dependency('byebug')
|
@@ -26,7 +30,7 @@ Gem::Specification.new do |s|
|
|
26
30
|
s.add_development_dependency('mocha')
|
27
31
|
s.add_development_dependency('webmock')
|
28
32
|
|
29
|
-
s.files =
|
30
|
-
s.test_files =
|
33
|
+
s.files = %x(git ls-files).split("\n").reject { |f| f.match(%r{^(test|example)/}) }
|
34
|
+
s.test_files = %x(git ls-files -- {test}/*).split("\n")
|
31
35
|
s.require_paths = ["lib"]
|
32
36
|
end
|