Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create OmniAuthConfiguration object to build future OmniAuth strategies #1190

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions lib/shopify_app.rb
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,7 @@ def self.use_webpacker?
require 'shopify_app/session/session_storage'
require 'shopify_app/session/shop_session_storage'
require 'shopify_app/session/user_session_storage'

# omniauth_configuration
NabeelAhsen marked this conversation as resolved.
Show resolved Hide resolved
require 'shopify_app/omniauth/omniauth_configuration'
end
10 changes: 10 additions & 0 deletions lib/shopify_app/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ class Configuration
attr_accessor :secret
attr_accessor :old_secret
attr_accessor :scope
attr_writer :shop_access_scopes
attr_writer :user_access_scopes
attr_accessor :embedded_app
alias_method :embedded_app?, :embedded_app
attr_accessor :webhooks
Expand Down Expand Up @@ -81,6 +83,14 @@ def has_scripttags?
def enable_same_site_none
!Rails.env.test? && (@enable_same_site_none.nil? ? embedded_app? : @enable_same_site_none)
end

def shop_access_scopes
@shop_access_scopes || scope
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems a little odd to return a singular item scope when the method name implies a collection.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed! However, the scope attribute has been used to define a collection of scopes stored in a string for a while now. Changing this will be a breaking change for shopify_app developers.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, we can mark this as future work to update scope to scopes.

end

def user_access_scopes
@user_access_scopes || scope
end
end

def self.configuration
Expand Down
64 changes: 64 additions & 0 deletions lib/shopify_app/omniauth/omniauth_configuration.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# frozen_string_literal: true

module ShopifyApp
class OmniAuthConfiguration
attr_reader :strategy, :request
attr_writer :client_options_site, :scopes, :per_user_permissions

def initialize(strategy, request)
@strategy = strategy
@request = request
end

def build_options
strategy.options[:client_options][:site] = client_options_site
strategy.options[:scope] = scopes
strategy.options[:old_client_secret] = ShopifyApp.configuration.old_secret
strategy.options[:per_user_permissions] = request_online_tokens?
end

private

def request_online_tokens?
return @per_user_permissions unless @per_user_permissions.nil?
default_request_online_tokens?
end

def scopes
@scopes || default_scopes
end

def client_options_site
@client_options_site || default_client_options_site
end

def default_scopes
if request_online_tokens?
ShopifyApp.configuration.user_access_scopes
else
ShopifyApp.configuration.shop_access_scopes
end
end

def default_client_options_site
return '' unless shop_domain.present?
"https://#{shopify_auth_params[:shop]}"
end

def default_request_online_tokens?
strategy.session[:user_tokens] && !update_shop_scopes?
end

def update_shop_scopes?
false
end

def shop_domain
request.params['shop'] || (shopify_auth_params && shopify_auth_params['shop'])
end

def shopify_auth_params
strategy.session['shopify.omniauth_params']&.with_indifferent_access
end
end
end
99 changes: 99 additions & 0 deletions test/shopify_app/omniauth/omniauth_configuration_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# frozen_string_literal: true
require 'test_helper'

module ShopifyApp
class OmniAuthConfigurationTest < Minitest::Test
attr_reader :strategy, :request

def setup
ShopifyApp.configuration.old_secret = 'old_secret'
ShopifyApp.configuration.user_access_scopes = 'read_products, read_orders'
ShopifyApp.configuration.shop_access_scopes = 'write_products, write_themes'
@strategy = mock_strategy
@request = mock_request
end

def test_configuration_builds_strategy_options_for_online_tokens
configuration = OmniAuthConfiguration.new(strategy, request)

configuration.build_options

assert_equal "https://shop.myshopify.com", strategy.options[:client_options][:site]
assert_equal ShopifyApp.configuration.user_access_scopes, strategy.options[:scope]
assert_equal ShopifyApp.configuration.old_secret, strategy.options[:old_client_secret]
assert strategy.options[:per_user_permissions]
end

def test_configuration_builds_strategy_options_for_offline_tokens
strategy.session[:user_tokens] = false
configuration = OmniAuthConfiguration.new(strategy, request)

configuration.build_options

assert_equal "https://shop.myshopify.com", strategy.options[:client_options][:site]
assert_equal ShopifyApp.configuration.shop_access_scopes, strategy.options[:scope]
assert_equal ShopifyApp.configuration.old_secret, strategy.options[:old_client_secret]
refute strategy.options[:per_user_permissions]
end

def test_configuration_configures_client_options_site_to_specified_value
configuration = OmniAuthConfiguration.new(strategy, request)
configuration.client_options_site = 'something.entirely.made.up'

configuration.build_options

assert_equal "something.entirely.made.up", strategy.options[:client_options][:site]
assert_equal ShopifyApp.configuration.user_access_scopes, strategy.options[:scope]
assert_equal ShopifyApp.configuration.old_secret, strategy.options[:old_client_secret]
assert strategy.options[:per_user_permissions]
end

def test_configuration_configures_scope_to_specified_value
configuration = OmniAuthConfiguration.new(strategy, request)
configuration.scopes = 'write_customers'

configuration.build_options

assert_equal "https://shop.myshopify.com", strategy.options[:client_options][:site]
assert_equal 'write_customers', strategy.options[:scope]
assert_equal ShopifyApp.configuration.old_secret, strategy.options[:old_client_secret]
assert strategy.options[:per_user_permissions]
end

def test_configuration_configures_per_user_permissions_to_specified_value
configuration = OmniAuthConfiguration.new(strategy, request)
configuration.per_user_permissions = false

configuration.build_options

assert_equal "https://shop.myshopify.com", strategy.options[:client_options][:site]
assert_equal ShopifyApp.configuration.shop_access_scopes, strategy.options[:scope]
assert_equal ShopifyApp.configuration.old_secret, strategy.options[:old_client_secret]
refute strategy.options[:per_user_permissions]
end

private

def mock_strategy
OpenStruct.new(
session: {
user_tokens: true,
'shopify.omniauth_params' => {
shop: 'shop.myshopify.com',
}.with_indifferent_access,
}.with_indifferent_access,
options: {
client_options: {},
}.with_indifferent_access
)
end

def mock_request
OpenStruct.new(
params: {
shop: 'shop.myshopify.com',
}.with_indifferent_access
)
end
end
end