shopify_app 13.5.0
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 +7 -0
- data/.babelrc +5 -0
- data/.github/CODEOWNERS +1 -0
- data/.github/ISSUE_TEMPLATE.md +14 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +6 -0
- data/.github/probots.yml +2 -0
- data/.github/workflows/rubocop.yml +28 -0
- data/.gitignore +16 -0
- data/.nvmrc +1 -0
- data/.rubocop.yml +17 -0
- data/.ruby-version +1 -0
- data/.travis.yml +28 -0
- data/CHANGELOG.md +505 -0
- data/Gemfile +11 -0
- data/LICENSE +19 -0
- data/README.md +620 -0
- data/Rakefile +7 -0
- data/SECURITY.md +59 -0
- data/app/assets/images/storage_access.svg +2 -0
- data/app/assets/javascripts/shopify_app/enable_cookies.js +3 -0
- data/app/assets/javascripts/shopify_app/itp_helper.js +40 -0
- data/app/assets/javascripts/shopify_app/partition_cookies.js +8 -0
- data/app/assets/javascripts/shopify_app/redirect.js +33 -0
- data/app/assets/javascripts/shopify_app/request_storage_access.js +3 -0
- data/app/assets/javascripts/shopify_app/storage_access.js +153 -0
- data/app/assets/javascripts/shopify_app/storage_access_redirect.js +17 -0
- data/app/assets/javascripts/shopify_app/top_level.js +2 -0
- data/app/assets/javascripts/shopify_app/top_level_interaction.js +11 -0
- data/app/controllers/concerns/shopify_app/authenticated.rb +16 -0
- data/app/controllers/concerns/shopify_app/require_known_shop.rb +39 -0
- data/app/controllers/shopify_app/authenticated_controller.rb +8 -0
- data/app/controllers/shopify_app/callback_controller.rb +140 -0
- data/app/controllers/shopify_app/extension_verification_controller.rb +15 -0
- data/app/controllers/shopify_app/sessions_controller.rb +184 -0
- data/app/controllers/shopify_app/webhooks_controller.rb +37 -0
- data/app/views/shopify_app/partials/_button_styles.html.erb +104 -0
- data/app/views/shopify_app/partials/_card_styles.html.erb +33 -0
- data/app/views/shopify_app/partials/_empty_state_styles.html.erb +129 -0
- data/app/views/shopify_app/partials/_layout_styles.html.erb +167 -0
- data/app/views/shopify_app/partials/_typography_styles.html.erb +35 -0
- data/app/views/shopify_app/sessions/enable_cookies.html.erb +75 -0
- data/app/views/shopify_app/sessions/new.html.erb +123 -0
- data/app/views/shopify_app/sessions/request_storage_access.html.erb +68 -0
- data/app/views/shopify_app/sessions/top_level_interaction.html.erb +64 -0
- data/app/views/shopify_app/shared/redirect.html.erb +23 -0
- data/config/locales/cs.yml +23 -0
- data/config/locales/da.yml +20 -0
- data/config/locales/de.yml +22 -0
- data/config/locales/en.yml +15 -0
- data/config/locales/es.yml +22 -0
- data/config/locales/fi.yml +20 -0
- data/config/locales/fr.yml +23 -0
- data/config/locales/hi.yml +23 -0
- data/config/locales/it.yml +21 -0
- data/config/locales/ja.yml +17 -0
- data/config/locales/ko.yml +19 -0
- data/config/locales/ms.yml +22 -0
- data/config/locales/nb.yml +21 -0
- data/config/locales/nl.yml +21 -0
- data/config/locales/pl.yml +21 -0
- data/config/locales/pt-BR.yml +21 -0
- data/config/locales/pt-PT.yml +22 -0
- data/config/locales/sv.yml +21 -0
- data/config/locales/th.yml +20 -0
- data/config/locales/tr.yml +22 -0
- data/config/locales/zh-CN.yml +16 -0
- data/config/locales/zh-TW.yml +16 -0
- data/config/routes.rb +23 -0
- data/docs/Quickstart.md +93 -0
- data/docs/Releasing.md +18 -0
- data/docs/Troubleshooting.md +16 -0
- data/docs/install-on-dev-shop.png +0 -0
- data/docs/test-your-app.png +0 -0
- data/images/app-proxy-screenshot.png +0 -0
- data/karma.conf.js +44 -0
- data/lib/generators/shopify_app/add_after_authenticate_job/add_after_authenticate_job_generator.rb +47 -0
- data/lib/generators/shopify_app/add_after_authenticate_job/templates/after_authenticate_job.rb +11 -0
- data/lib/generators/shopify_app/add_marketing_activity_extension/add_marketing_activity_extension_generator.rb +40 -0
- data/lib/generators/shopify_app/add_marketing_activity_extension/templates/marketing_activities_controller.rb +62 -0
- data/lib/generators/shopify_app/add_webhook/add_webhook_generator.rb +69 -0
- data/lib/generators/shopify_app/add_webhook/templates/webhook_job.rb.tt +13 -0
- data/lib/generators/shopify_app/app_proxy_controller/app_proxy_controller_generator.rb +26 -0
- data/lib/generators/shopify_app/app_proxy_controller/templates/app_proxy_controller.rb +8 -0
- data/lib/generators/shopify_app/app_proxy_controller/templates/app_proxy_route.rb +11 -0
- data/lib/generators/shopify_app/app_proxy_controller/templates/index.html.erb +19 -0
- data/lib/generators/shopify_app/authenticated_controller/authenticated_controller_generator.rb +15 -0
- data/lib/generators/shopify_app/authenticated_controller/templates/authenticated_controller.rb +5 -0
- data/lib/generators/shopify_app/controllers/controllers_generator.rb +30 -0
- data/lib/generators/shopify_app/home_controller/home_controller_generator.rb +26 -0
- data/lib/generators/shopify_app/home_controller/templates/home_controller.rb +8 -0
- data/lib/generators/shopify_app/home_controller/templates/index.html.erb +21 -0
- data/lib/generators/shopify_app/install/install_generator.rb +83 -0
- data/lib/generators/shopify_app/install/templates/_flash_messages.html.erb +3 -0
- data/lib/generators/shopify_app/install/templates/embedded_app.html.erb +41 -0
- data/lib/generators/shopify_app/install/templates/flash_messages.js +24 -0
- data/lib/generators/shopify_app/install/templates/omniauth.rb +3 -0
- data/lib/generators/shopify_app/install/templates/session_store.rb +4 -0
- data/lib/generators/shopify_app/install/templates/shopify_app.js +15 -0
- data/lib/generators/shopify_app/install/templates/shopify_app.rb.tt +15 -0
- data/lib/generators/shopify_app/install/templates/shopify_app_index.js +2 -0
- data/lib/generators/shopify_app/install/templates/shopify_provider.rb +20 -0
- data/lib/generators/shopify_app/install/templates/user_agent.rb +6 -0
- data/lib/generators/shopify_app/rotate_shopify_token_job/rotate_shopify_token_job_generator.rb +16 -0
- data/lib/generators/shopify_app/rotate_shopify_token_job/templates/rotate_shopify_token.rake +17 -0
- data/lib/generators/shopify_app/rotate_shopify_token_job/templates/rotate_shopify_token_job.rb +42 -0
- data/lib/generators/shopify_app/routes/routes_generator.rb +32 -0
- data/lib/generators/shopify_app/routes/templates/routes.rb +12 -0
- data/lib/generators/shopify_app/shop_model/shop_model_generator.rb +43 -0
- data/lib/generators/shopify_app/shop_model/templates/db/migrate/create_shops.erb +15 -0
- data/lib/generators/shopify_app/shop_model/templates/shop.rb +8 -0
- data/lib/generators/shopify_app/shop_model/templates/shops.yml +3 -0
- data/lib/generators/shopify_app/shopify_app_generator.rb +18 -0
- data/lib/generators/shopify_app/user_model/templates/db/migrate/create_users.erb +16 -0
- data/lib/generators/shopify_app/user_model/templates/user.rb +8 -0
- data/lib/generators/shopify_app/user_model/templates/users.yml +4 -0
- data/lib/generators/shopify_app/user_model/user_model_generator.rb +43 -0
- data/lib/generators/shopify_app/views/views_generator.rb +30 -0
- data/lib/shopify_app.rb +61 -0
- data/lib/shopify_app/configuration.rb +94 -0
- data/lib/shopify_app/controller_concerns/app_proxy_verification.rb +38 -0
- data/lib/shopify_app/controller_concerns/csrf_protection.rb +15 -0
- data/lib/shopify_app/controller_concerns/embedded_app.rb +20 -0
- data/lib/shopify_app/controller_concerns/itp.rb +45 -0
- data/lib/shopify_app/controller_concerns/localization.rb +23 -0
- data/lib/shopify_app/controller_concerns/login_protection.rb +231 -0
- data/lib/shopify_app/controller_concerns/payload_verification.rb +24 -0
- data/lib/shopify_app/controller_concerns/webhook_verification.rb +23 -0
- data/lib/shopify_app/engine.rb +25 -0
- data/lib/shopify_app/jobs/scripttags_manager_job.rb +16 -0
- data/lib/shopify_app/jobs/webhooks_manager_job.rb +16 -0
- data/lib/shopify_app/managers/scripttags_manager.rb +78 -0
- data/lib/shopify_app/managers/webhooks_manager.rb +62 -0
- data/lib/shopify_app/middleware/jwt_middleware.rb +42 -0
- data/lib/shopify_app/middleware/same_site_cookie_middleware.rb +34 -0
- data/lib/shopify_app/session/in_memory_session_store.rb +31 -0
- data/lib/shopify_app/session/in_memory_shop_session_store.rb +14 -0
- data/lib/shopify_app/session/in_memory_user_session_store.rb +14 -0
- data/lib/shopify_app/session/jwt.rb +61 -0
- data/lib/shopify_app/session/null_user_session_store.rb +22 -0
- data/lib/shopify_app/session/session_repository.rb +56 -0
- data/lib/shopify_app/session/session_storage.rb +20 -0
- data/lib/shopify_app/session/shop_session_storage.rb +42 -0
- data/lib/shopify_app/session/user_session_storage.rb +42 -0
- data/lib/shopify_app/test_helpers/all.rb +2 -0
- data/lib/shopify_app/test_helpers/webhook_verification_helper.rb +17 -0
- data/lib/shopify_app/utils.rb +24 -0
- data/lib/shopify_app/version.rb +4 -0
- data/package-lock.json +7177 -0
- data/package.json +28 -0
- data/service.yml +7 -0
- data/shipit.rubygems.yml +4 -0
- data/shopify_app.gemspec +37 -0
- data/translation.yml +7 -0
- data/webpack.config.js +24 -0
- data/yarn.lock +5263 -0
- metadata +420 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
ShopifyApp.configure do |config|
|
|
2
|
+
config.application_name = "<%= @application_name %>"
|
|
3
|
+
config.api_key = ENV['SHOPIFY_API_KEY']
|
|
4
|
+
config.secret = ENV['SHOPIFY_API_SECRET']
|
|
5
|
+
config.old_secret = "<%= @old_secret %>"
|
|
6
|
+
config.scope = "<%= @scope %>" # Consult this page for more scope options:
|
|
7
|
+
# https://help.shopify.com/en/api/getting-started/authentication/oauth/scopes
|
|
8
|
+
config.embedded_app = <%= embedded_app? %>
|
|
9
|
+
config.after_authenticate_job = false
|
|
10
|
+
config.api_version = "<%= @api_version %>"
|
|
11
|
+
config.shop_session_repository = 'Shop'
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# ShopifyApp::Utils.fetch_known_api_versions # Uncomment to fetch known api versions from shopify servers on boot
|
|
15
|
+
# ShopifyAPI::ApiVersion.version_lookup_mode = :raise_on_unknown # Uncomment to raise an error if attempting to use an api version that was not previously known
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
provider :shopify,
|
|
4
|
+
ShopifyApp.configuration.api_key,
|
|
5
|
+
ShopifyApp.configuration.secret,
|
|
6
|
+
scope: ShopifyApp.configuration.scope,
|
|
7
|
+
setup: lambda { |env|
|
|
8
|
+
strategy = env['omniauth.strategy']
|
|
9
|
+
|
|
10
|
+
shopify_auth_params = strategy.session['shopify.omniauth_params']&.with_indifferent_access
|
|
11
|
+
shop = if shopify_auth_params.present?
|
|
12
|
+
"https://#{shopify_auth_params[:shop]}"
|
|
13
|
+
else
|
|
14
|
+
''
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
strategy.options[:client_options][:site] = shop
|
|
18
|
+
strategy.options[:old_client_secret] = ShopifyApp.configuration.old_secret
|
|
19
|
+
strategy.options[:per_user_permissions] = strategy.session[:user_tokens]
|
|
20
|
+
}
|
data/lib/generators/shopify_app/rotate_shopify_token_job/rotate_shopify_token_job_generator.rb
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rails/generators/base'
|
|
4
|
+
|
|
5
|
+
module ShopifyApp
|
|
6
|
+
module Generators
|
|
7
|
+
class RotateShopifyTokenJobGenerator < Rails::Generators::Base
|
|
8
|
+
source_root File.expand_path('../templates', __FILE__)
|
|
9
|
+
|
|
10
|
+
def add_rotate_shopify_token_job
|
|
11
|
+
copy_file('rotate_shopify_token_job.rb', "app/jobs/shopify/rotate_shopify_token_job.rb")
|
|
12
|
+
copy_file('rotate_shopify_token.rake', "lib/tasks/shopify/rotate_shopify_token.rake")
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
namespace :shopify do
|
|
3
|
+
desc "Rotate shopify tokens for all active shops"
|
|
4
|
+
task :rotate_shopify_tokens, [:refresh_token] => :environment do |_t, args|
|
|
5
|
+
all_active_shops.find_each do |shop|
|
|
6
|
+
Shopify::RotateShopifyTokenJob.perform_later(
|
|
7
|
+
shop_domain: shop.shopify_domain,
|
|
8
|
+
refresh_token: args[:refresh_token]
|
|
9
|
+
)
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Its implementation will depend on the app configuration. Change accordingly.
|
|
14
|
+
def all_active_shops
|
|
15
|
+
Shop.all
|
|
16
|
+
end
|
|
17
|
+
end
|
data/lib/generators/shopify_app/rotate_shopify_token_job/templates/rotate_shopify_token_job.rb
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shopify
|
|
4
|
+
class RotateShopifyTokenJob < ActiveJob::Base
|
|
5
|
+
def perform(params)
|
|
6
|
+
@shop = Shop.find_by(shopify_domain: params[:shop_domain])
|
|
7
|
+
return unless @shop
|
|
8
|
+
|
|
9
|
+
config = ShopifyApp.configuration
|
|
10
|
+
uri = URI("https://#{@shop.shopify_domain}/admin/oauth/access_token")
|
|
11
|
+
post_data = {
|
|
12
|
+
client_id: config.api_key,
|
|
13
|
+
client_secret: config.secret,
|
|
14
|
+
refresh_token: params[:refresh_token],
|
|
15
|
+
access_token: @shop.shopify_token,
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
@response = Net::HTTP.post_form(uri, post_data)
|
|
19
|
+
return log_error(response_exception_error_message) unless @response.is_a?(Net::HTTPSuccess)
|
|
20
|
+
|
|
21
|
+
access_token = JSON.parse(@response.body)['access_token']
|
|
22
|
+
return log_error(no_access_token_error_message) unless access_token
|
|
23
|
+
|
|
24
|
+
@shop.update(shopify_token: access_token)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def log_error(message)
|
|
30
|
+
Rails.logger.error(message)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def no_access_token_error_message
|
|
34
|
+
"RotateShopifyTokenJob response returned no access token for shop: #{@shop.shopify_domain}"
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def response_exception_error_message
|
|
38
|
+
"RotateShopifyTokenJob failed for shop: #{@shop.shopify_domain}." \
|
|
39
|
+
"Response returned status: #{@response.code}. Error message: #{@response.message}. "
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require 'rails/generators/base'
|
|
3
|
+
|
|
4
|
+
module ShopifyApp
|
|
5
|
+
module Generators
|
|
6
|
+
class RoutesGenerator < Rails::Generators::Base
|
|
7
|
+
source_root File.expand_path('../templates', __FILE__)
|
|
8
|
+
|
|
9
|
+
def inject_shopify_app_routes_into_application_routes
|
|
10
|
+
route(session_routes)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def disable_engine_routes
|
|
14
|
+
gsub_file(
|
|
15
|
+
'config/routes.rb',
|
|
16
|
+
"mount ShopifyApp::Engine, at: '/'",
|
|
17
|
+
''
|
|
18
|
+
)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def session_routes
|
|
24
|
+
File.read(routes_file_path)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def routes_file_path
|
|
28
|
+
File.expand_path(find_in_source_paths('routes.rb'))
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
controller :sessions do
|
|
4
|
+
get 'login' => :new, :as => :login
|
|
5
|
+
post 'login' => :create, :as => :authenticate
|
|
6
|
+
get 'auth/shopify/callback' => :callback
|
|
7
|
+
get 'logout' => :destroy, :as => :logout
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
namespace :webhooks do
|
|
11
|
+
post ':type' => :receive
|
|
12
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require 'rails/generators/base'
|
|
3
|
+
require 'rails/generators/active_record'
|
|
4
|
+
|
|
5
|
+
module ShopifyApp
|
|
6
|
+
module Generators
|
|
7
|
+
class ShopModelGenerator < Rails::Generators::Base
|
|
8
|
+
include Rails::Generators::Migration
|
|
9
|
+
source_root File.expand_path('../templates', __FILE__)
|
|
10
|
+
|
|
11
|
+
def create_shop_model
|
|
12
|
+
copy_file('shop.rb', 'app/models/shop.rb')
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def create_shop_migration
|
|
16
|
+
migration_template('db/migrate/create_shops.erb', 'db/migrate/create_shops.rb')
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def update_shopify_app_initializer
|
|
20
|
+
gsub_file('config/initializers/shopify_app.rb', 'ShopifyApp::InMemoryShopSessionStore', 'Shop')
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def create_shop_fixtures
|
|
24
|
+
copy_file('shops.yml', 'test/fixtures/shops.yml')
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def rails_migration_version
|
|
30
|
+
Rails.version.match(/\d\.\d/)[0]
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
class << self
|
|
34
|
+
private :next_migration_number
|
|
35
|
+
|
|
36
|
+
# for generating a timestamp when using `create_migration`
|
|
37
|
+
def next_migration_number(dir)
|
|
38
|
+
ActiveRecord::Generators::Base.next_migration_number(dir)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
class CreateShops < ActiveRecord::Migration[<%= rails_migration_version %>]
|
|
2
|
+
def self.up
|
|
3
|
+
create_table :shops do |t|
|
|
4
|
+
t.string :shopify_domain, null: false
|
|
5
|
+
t.string :shopify_token, null: false
|
|
6
|
+
t.timestamps
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
add_index :shops, :shopify_domain, unique: true
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def self.down
|
|
13
|
+
drop_table :shops
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module ShopifyApp
|
|
3
|
+
module Generators
|
|
4
|
+
class ShopifyAppGenerator < Rails::Generators::Base
|
|
5
|
+
def initialize(args, *options)
|
|
6
|
+
@opts = options.first
|
|
7
|
+
super(args, *options)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def run_all_generators
|
|
11
|
+
generate("shopify_app:install #{@opts.join(' ')}")
|
|
12
|
+
generate("shopify_app:shop_model")
|
|
13
|
+
generate("shopify_app:authenticated_controller")
|
|
14
|
+
generate("shopify_app:home_controller")
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
class CreateUsers < ActiveRecord::Migration[<%= rails_migration_version %>]
|
|
2
|
+
def self.up
|
|
3
|
+
create_table :users do |t|
|
|
4
|
+
t.bigint :shopify_user_id, null: false
|
|
5
|
+
t.string :shopify_domain, null: false
|
|
6
|
+
t.string :shopify_token, null: false
|
|
7
|
+
t.timestamps
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
add_index :users, :shopify_user_id, unique: true
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def self.down
|
|
14
|
+
drop_table :users
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require 'rails/generators/base'
|
|
3
|
+
require 'rails/generators/active_record'
|
|
4
|
+
|
|
5
|
+
module ShopifyApp
|
|
6
|
+
module Generators
|
|
7
|
+
class UserModelGenerator < Rails::Generators::Base
|
|
8
|
+
include Rails::Generators::Migration
|
|
9
|
+
source_root File.expand_path('../templates', __FILE__)
|
|
10
|
+
|
|
11
|
+
def create_user_model
|
|
12
|
+
copy_file('user.rb', 'app/models/user.rb')
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def create_user_migration
|
|
16
|
+
migration_template('db/migrate/create_users.erb', 'db/migrate/create_users.rb')
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def update_shopify_app_initializer
|
|
20
|
+
gsub_file('config/initializers/shopify_app.rb', 'ShopifyApp::InMemoryUserSessionStore', 'User')
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def create_user_fixtures
|
|
24
|
+
copy_file('users.yml', 'test/fixtures/users.yml')
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def rails_migration_version
|
|
30
|
+
Rails.version.match(/\d\.\d/)[0]
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
class << self
|
|
34
|
+
private :next_migration_number
|
|
35
|
+
|
|
36
|
+
# for generating a timestamp when using `create_migration`
|
|
37
|
+
def next_migration_number(dir)
|
|
38
|
+
ActiveRecord::Generators::Base.next_migration_number(dir)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require 'rails/generators/base'
|
|
3
|
+
|
|
4
|
+
module ShopifyApp
|
|
5
|
+
module Generators
|
|
6
|
+
class ViewsGenerator < Rails::Generators::Base
|
|
7
|
+
source_root File.expand_path("../../../../..", __FILE__)
|
|
8
|
+
|
|
9
|
+
def create_views
|
|
10
|
+
views.each do |view|
|
|
11
|
+
copy_file view
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
private
|
|
16
|
+
|
|
17
|
+
def views
|
|
18
|
+
files_within_root('.', 'app/views/**/*.*')
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def files_within_root(prefix, glob)
|
|
22
|
+
root = "#{self.class.source_root}/#{prefix}"
|
|
23
|
+
|
|
24
|
+
Dir["#{root}/#{glob}"].sort.map do |full_path|
|
|
25
|
+
full_path.sub(root, '.').gsub('/./', '/')
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
data/lib/shopify_app.rb
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require 'shopify_app/version'
|
|
3
|
+
|
|
4
|
+
# deps
|
|
5
|
+
require 'shopify_api'
|
|
6
|
+
require 'omniauth-shopify-oauth2'
|
|
7
|
+
require 'redirect_safely'
|
|
8
|
+
|
|
9
|
+
module ShopifyApp
|
|
10
|
+
def self.rails6?
|
|
11
|
+
Rails::VERSION::MAJOR >= 6
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def self.use_webpacker?
|
|
15
|
+
rails6? &&
|
|
16
|
+
defined?(Webpacker) == 'constant' &&
|
|
17
|
+
!configuration.disable_webpacker
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# config
|
|
21
|
+
require 'shopify_app/configuration'
|
|
22
|
+
|
|
23
|
+
# engine
|
|
24
|
+
require 'shopify_app/engine'
|
|
25
|
+
|
|
26
|
+
# utils
|
|
27
|
+
require 'shopify_app/utils'
|
|
28
|
+
|
|
29
|
+
# controller concerns
|
|
30
|
+
require 'shopify_app/controller_concerns/csrf_protection'
|
|
31
|
+
require 'shopify_app/controller_concerns/localization'
|
|
32
|
+
require 'shopify_app/controller_concerns/itp'
|
|
33
|
+
require 'shopify_app/controller_concerns/login_protection'
|
|
34
|
+
require 'shopify_app/controller_concerns/embedded_app'
|
|
35
|
+
require 'shopify_app/controller_concerns/payload_verification'
|
|
36
|
+
require 'shopify_app/controller_concerns/app_proxy_verification'
|
|
37
|
+
require 'shopify_app/controller_concerns/webhook_verification'
|
|
38
|
+
|
|
39
|
+
# jobs
|
|
40
|
+
require 'shopify_app/jobs/webhooks_manager_job'
|
|
41
|
+
require 'shopify_app/jobs/scripttags_manager_job'
|
|
42
|
+
|
|
43
|
+
# managers
|
|
44
|
+
require 'shopify_app/managers/webhooks_manager'
|
|
45
|
+
require 'shopify_app/managers/scripttags_manager'
|
|
46
|
+
|
|
47
|
+
# middleware
|
|
48
|
+
require 'shopify_app/middleware/jwt_middleware'
|
|
49
|
+
require 'shopify_app/middleware/same_site_cookie_middleware'
|
|
50
|
+
|
|
51
|
+
# session
|
|
52
|
+
require 'shopify_app/session/in_memory_session_store'
|
|
53
|
+
require 'shopify_app/session/in_memory_shop_session_store'
|
|
54
|
+
require 'shopify_app/session/in_memory_user_session_store'
|
|
55
|
+
require 'shopify_app/session/jwt'
|
|
56
|
+
require 'shopify_app/session/null_user_session_store'
|
|
57
|
+
require 'shopify_app/session/session_repository'
|
|
58
|
+
require 'shopify_app/session/session_storage'
|
|
59
|
+
require 'shopify_app/session/shop_session_storage'
|
|
60
|
+
require 'shopify_app/session/user_session_storage'
|
|
61
|
+
end
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module ShopifyApp
|
|
3
|
+
class Configuration
|
|
4
|
+
# Shopify App settings. These values should match the configuration
|
|
5
|
+
# for the app in your Shopify Partners page. Change your settings in
|
|
6
|
+
# `config/initializers/shopify_app.rb`
|
|
7
|
+
attr_accessor :application_name
|
|
8
|
+
attr_accessor :api_key
|
|
9
|
+
attr_accessor :secret
|
|
10
|
+
attr_accessor :old_secret
|
|
11
|
+
attr_accessor :scope
|
|
12
|
+
attr_accessor :embedded_app
|
|
13
|
+
alias_method :embedded_app?, :embedded_app
|
|
14
|
+
attr_accessor :webhooks
|
|
15
|
+
attr_accessor :scripttags
|
|
16
|
+
attr_accessor :after_authenticate_job
|
|
17
|
+
attr_accessor :api_version
|
|
18
|
+
|
|
19
|
+
# customise urls
|
|
20
|
+
attr_accessor :root_url
|
|
21
|
+
attr_writer :login_url
|
|
22
|
+
|
|
23
|
+
# customise ActiveJob queue names
|
|
24
|
+
attr_accessor :scripttags_manager_queue_name
|
|
25
|
+
attr_accessor :webhooks_manager_queue_name
|
|
26
|
+
|
|
27
|
+
# configure myshopify domain for local shopify development
|
|
28
|
+
attr_accessor :myshopify_domain
|
|
29
|
+
|
|
30
|
+
# ability to have webpacker installed but not used in this gem and the generators
|
|
31
|
+
attr_accessor :disable_webpacker
|
|
32
|
+
|
|
33
|
+
# allow namespacing webhook jobs
|
|
34
|
+
attr_accessor :webhook_jobs_namespace
|
|
35
|
+
|
|
36
|
+
# allow enabling of same site none on cookies
|
|
37
|
+
attr_writer :enable_same_site_none
|
|
38
|
+
|
|
39
|
+
# allow enabling jwt headers for authentication
|
|
40
|
+
attr_accessor :allow_jwt_authentication
|
|
41
|
+
|
|
42
|
+
def initialize
|
|
43
|
+
@root_url = '/'
|
|
44
|
+
@myshopify_domain = 'myshopify.com'
|
|
45
|
+
@scripttags_manager_queue_name = Rails.application.config.active_job.queue_name
|
|
46
|
+
@webhooks_manager_queue_name = Rails.application.config.active_job.queue_name
|
|
47
|
+
@disable_webpacker = ENV['SHOPIFY_APP_DISABLE_WEBPACKER'].present?
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def login_url
|
|
51
|
+
@login_url || File.join(@root_url, 'login')
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def user_session_repository=(klass)
|
|
55
|
+
ShopifyApp::SessionRepository.user_storage = klass
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def user_session_repository
|
|
59
|
+
ShopifyApp::SessionRepository.user_storage
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def shop_session_repository=(klass)
|
|
63
|
+
ShopifyApp::SessionRepository.shop_storage = klass
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def shop_session_repository
|
|
67
|
+
ShopifyApp::SessionRepository.shop_storage
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def has_webhooks?
|
|
71
|
+
webhooks.present?
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def has_scripttags?
|
|
75
|
+
scripttags.present?
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def enable_same_site_none
|
|
79
|
+
!Rails.env.test? && (@enable_same_site_none.nil? ? embedded_app? : @enable_same_site_none)
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def self.configuration
|
|
84
|
+
@configuration ||= Configuration.new
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def self.configuration=(config)
|
|
88
|
+
@configuration = config
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def self.configure
|
|
92
|
+
yield configuration
|
|
93
|
+
end
|
|
94
|
+
end
|