class ShopifyAPI::Session

Constants

SECONDS_IN_A_DAY

Attributes

access_scopes[R]
api_version[R]
domain[RW]
extra[RW]
name[RW]
token[RW]
url[RW]

Public Class Methods

new(domain:, token:, access_scopes: nil, api_version: ShopifyAPI::Base.api_version, extra: {}) click to toggle source
# File lib/shopify_api/session.rb, line 90
def initialize(domain:, token:, access_scopes: nil, api_version: ShopifyAPI::Base.api_version, extra: {})
  self.domain = self.class.prepare_domain(domain)
  self.api_version = api_version
  self.token = token
  self.access_scopes = access_scopes
  self.extra = extra
end
prepare_domain(domain) click to toggle source
# File lib/shopify_api/session.rb, line 53
def prepare_domain(domain)
  return nil if domain.blank?
  # remove http:// or https://
  domain = domain.strip.gsub(%r{\Ahttps?://}, '')
  # extract host, removing any username, password or path
  shop = URI.parse("https://#{domain}").host
  # extract subdomain of .myshopify.com
  if (idx = shop.index("."))
    shop = shop.slice(0, idx)
  end
  return nil if shop.empty?
  "#{shop}.#{myshopify_domain}"
rescue URI::InvalidURIError
  nil
end
setup(params) click to toggle source
# File lib/shopify_api/session.rb, line 20
def setup(params)
  params.each { |k, value| public_send("#{k}=", value) }
end
temp(domain:, token:, api_version: ShopifyAPI::Base.api_version, &block) click to toggle source
# File lib/shopify_api/session.rb, line 24
def temp(domain:, token:, api_version: ShopifyAPI::Base.api_version, &block)
  session = new(domain: domain, token: token, api_version: api_version)

  with_session(session, &block)
end
validate_signature(params) click to toggle source
# File lib/shopify_api/session.rb, line 69
def validate_signature(params)
  params = (params.respond_to?(:to_unsafe_hash) ? params.to_unsafe_hash : params).with_indifferent_access
  return false unless (signature = params[:hmac])

  calculated_signature = OpenSSL::HMAC.hexdigest(
    OpenSSL::Digest.new('SHA256'), secret, ShopifyAPI::HmacParams.encode(params)
  )

  Rack::Utils.secure_compare(calculated_signature, signature)
end
with_session(session) { || ... } click to toggle source
# File lib/shopify_api/session.rb, line 30
def with_session(session, &_block)
  original_session = extract_current_session
  original_user = ShopifyAPI::Base.user
  original_password = ShopifyAPI::Base.password

  begin
    ShopifyAPI::Base.clear_session
    ShopifyAPI::Base.activate_session(session)
    yield
  ensure
    ShopifyAPI::Base.activate_session(original_session)
    ShopifyAPI::Base.user = original_user
    ShopifyAPI::Base.password = original_password
  end
end
with_version(api_version, &block) click to toggle source
# File lib/shopify_api/session.rb, line 46
def with_version(api_version, &block)
  original_session = extract_current_session
  session = new(domain: original_session.site, token: original_session.token, api_version: api_version)

  with_session(session, &block)
end

Private Class Methods

extract_current_session() click to toggle source
# File lib/shopify_api/session.rb, line 82
def extract_current_session
  site = ShopifyAPI::Base.site.to_s
  token = ShopifyAPI::Base.headers['X-Shopify-Access-Token']
  version = ShopifyAPI::Base.api_version
  new(domain: site, token: token, api_version: version)
end

Public Instance Methods

==(other) click to toggle source
# File lib/shopify_api/session.rb, line 166
def ==(other)
  self.class == other.class && state == other.state
end
Also aliased as: eql?
api_version=(version) click to toggle source
# File lib/shopify_api/session.rb, line 135
def api_version=(version)
  @api_version = if ApiVersion::NullVersion.matches?(version)
    ApiVersion::NullVersion
  else
    ApiVersion.find_version(version)
  end
end
create_permission_url(scope, redirect_uri, options = {}) click to toggle source
# File lib/shopify_api/session.rb, line 98
def create_permission_url(scope, redirect_uri, options = {})
  params = { client_id: api_key, scope: ShopifyAPI::ApiAccess.new(scope).to_s, redirect_uri: redirect_uri }
  params[:state] = options[:state] if options[:state]
  params["grant_options[]".to_sym] = options[:grant_options] if options[:grant_options]
  construct_oauth_url("authorize", params)
end
eql?(other)
Alias for: ==
expired?() click to toggle source
# File lib/shopify_api/session.rb, line 157
def expired?
  return false if expires_in.nil?
  expires_in <= 0
end
expires_at() click to toggle source
# File lib/shopify_api/session.rb, line 152
def expires_at
  return unless extra.present?
  @expires_at ||= Time.at(extra['expires_at']).utc
end
expires_in() click to toggle source
# File lib/shopify_api/session.rb, line 147
def expires_in
  return unless expires_at.present?
  [0, expires_at.to_i - Time.now.utc.to_i].max
end
hash() click to toggle source
# File lib/shopify_api/session.rb, line 162
def hash
  state.hash
end
request_token(params) click to toggle source
# File lib/shopify_api/session.rb, line 105
def request_token(params)
  return token if token

  twenty_four_hours_ago = Time.now.utc.to_i - SECONDS_IN_A_DAY
  unless self.class.validate_signature(params) && params[:timestamp].to_i > twenty_four_hours_ago
    raise ShopifyAPI::ValidationException, "Invalid Signature: Possible malicious login"
  end

  response = access_token_request(params[:code])
  if response.code == "200"
    self.extra = JSON.parse(response.body)
    self.token = extra.delete('access_token')

    if (expires_in = extra.delete('expires_in'))
      extra['expires_at'] = Time.now.utc.to_i + expires_in
    end
    token
  else
    raise response.msg
  end
end
shop() click to toggle source
# File lib/shopify_api/session.rb, line 127
def shop
  Shop.current
end
site() click to toggle source
# File lib/shopify_api/session.rb, line 131
def site
  "https://#{domain}"
end
valid?() click to toggle source
# File lib/shopify_api/session.rb, line 143
def valid?
  domain.present? && token.present? && api_version.is_a?(ApiVersion)
end

Protected Instance Methods

state() click to toggle source
# File lib/shopify_api/session.rb, line 174
def state
  [domain, token, api_version, extra]
end

Private Instance Methods

access_scopes=(access_scopes) click to toggle source
# File lib/shopify_api/session.rb, line 180
def access_scopes=(access_scopes)
  return unless access_scopes
  @access_scopes = ShopifyAPI::ApiAccess.new(access_scopes)
end
access_token_request(code) click to toggle source
# File lib/shopify_api/session.rb, line 189
def access_token_request(code)
  uri = URI.parse(construct_oauth_url('access_token'))
  https = Net::HTTP.new(uri.host, uri.port)
  https.use_ssl = true
  request = Net::HTTP::Post.new(uri.request_uri)
  request.set_form_data('client_id' => api_key, 'client_secret' => secret, 'code' => code)
  https.request(request)
end
construct_oauth_url(path, query_params = {}) click to toggle source
# File lib/shopify_api/session.rb, line 198
def construct_oauth_url(path, query_params = {})
  query_string = "?#{parameterize(query_params)}" unless query_params.empty?
  "https://#{domain}/admin/oauth/#{path}#{query_string}"
end
parameterize(params) click to toggle source
# File lib/shopify_api/session.rb, line 185
def parameterize(params)
  URI.encode_www_form(params)
end