Skip to content

Instantly share code, notes, and snippets.

@biancalpadilla
Last active September 6, 2018 01:20
Show Gist options
  • Save biancalpadilla/6ec025e81447e98be24fc3ab4362d40f to your computer and use it in GitHub Desktop.
Save biancalpadilla/6ec025e81447e98be24fc3ab4362d40f to your computer and use it in GitHub Desktop.
bigcommerce omniauth
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
after_action :set_header_for_iframe
helper_method :current_store
helper_method :current_connection
private
# require to remove X-Frame-Options to load Rails app in iframe on Bigcommerce
def set_header_for_iframe
response.headers.delete 'X-Frame-Options'
end
def current_store
if params['producer'].present?
store_hash = params['producer'].split('/').last
@current_store = Store.find_by(store_hash: store_hash)
session[:store_id] = @current_store.id
else
# @current_store = Store.find(session[:store_id])
@current_store = Store.last
end
@current_store
end
def current_connection
@connection = Bigcommerce::Connection.build(Bigcommerce::Config.new(store_hash: current_store.store_hash, client_id: ENV['BC_CLIENT_ID'], access_token: current_store.access_token))
end
end
# config/initializers/omniauth.rb
Rails.application.config.middleware.use OmniAuth::Builder do
provider :bigcommerce, ENV['BC_CLIENT_ID'], ENV['BC_CLIENT_SECRET']
end
class OmniauthsController < ApplicationController
def callback
logger.info(request.env)
CUSTOM_LOGGER.info(request.env["omniauth.auth"])
auth = request.env["omniauth.auth"]
unless auth && auth[:extra][:raw_info][:context]
return render_error("[install] Invalid credentials: #{JSON.pretty_generate(auth[:extra])}")
end
app_url = ENV['APPLICATION_URL']
email = auth[:info][:email]
name = auth[:info][:name]
store_hash = auth[:extra][:context].split('/')[1]
token = auth[:credentials][:token].token
scope = auth[:extra][:scopes]
# Lookup store
store = Store.where(store_hash: store_hash).first
if store
logger.info "[install] Updating token for store '#{store_hash}' with scope '#{scope}'"
store.update(access_token: token, scope: scope)
connection = Bigcommerce::Connection.build(Bigcommerce::Config.new(store_hash: store.store_hash, client_id: ENV['BC_CLIENT_ID'], access_token: store.access_token))
# webhook1 = Bigcommerce::Webhook.create( scope: 'store/order/created', destination: "#{app_url}/hooks/order_created", connection: connection )
# webhook2 = Bigcommerce::Webhook.create( scope: 'store/shipment/created', destination: "#{app_url}/hooks/shipment_created", connection: connection )
else
logger.info "[install] Installing app for store '#{store_hash}' with admin '#{email}'"
store = Store.create(store_hash: store_hash, access_token: token, scope: scope, email: email, username: name)
if store.present?
connection = Bigcommerce::Connection.build(Bigcommerce::Config.new(store_hash: store.store_hash, client_id: ENV['BC_CLIENT_ID'], access_token: store.access_token))
# webhook1 = Bigcommerce::Webhook.create( scope: 'store/order/created', destination: "#{app_url}/hooks/order_created", connection: connection )
# webhook2 = Bigcommerce::Webhook.create( scope: 'store/shipment/created', destination: "#{app_url}/hooks/shipment_created", connection: connection )
end
session[:store_id] = store.id
logo = Bigcommerce::StoreInfo.info(connection: connection)[:logo]
session[:store_logo] = logo.present? ? logo[:url] : 'assets/default_logo.png'
end
render 'welcome/index', status: 200
end
def uninstall
payload = parse_signed_payload
store = Store.find_by(store_hash: payload["store_hash"])
store.destroy if store.present?
Rails.logger.debug "Store Removed successfully"
render nothing: true, status: 200
end
def load
payload = parse_signed_payload
@payload = payload
return render_error('[load] Invalid payload signature!') unless payload
email = payload['user']['email']
@email = email
store_hash = payload['store_hash']
# Lookup store
@store = Store.find_by(store_hash: store_hash)
connection = Bigcommerce::Connection.build(Bigcommerce::Config.new(store_hash: @store.store_hash, client_id: ENV['BC_CLIENT_ID'], access_token: @store.access_token))
return render_error("[load] Store not found!") unless @store
logger.info "[load] Loading app for user '#{email}' on store '#{store_hash}'"
session[:store_id] = @store.id
logo = Bigcommerce::StoreInfo.info(connection: connection)[:logo]
session[:store_logo] = logo.present? ? logo[:url] : 'assets/default_logo.png'
render 'welcome/index', status: 200
end
private
def parse_signed_payload
signed_payload = params[:signed_payload]
message_parts = signed_payload.split('.')
encoded_json_payload = message_parts[0]
encoded_hmac_signature = message_parts[1]
payload = Base64.decode64(encoded_json_payload)
provided_signature = Base64.decode64(encoded_hmac_signature)
expected_signature = sign_payload(bc_client_secret, payload)
if secure_compare(expected_signature, provided_signature)
return JSON.parse(payload)
end
nil
end
def sign_payload(secret, payload)
OpenSSL::HMAC::hexdigest('sha256', secret, payload)
end
def bc_client_id
ENV['BC_CLIENT_ID']
end
# Get client secret from env
def bc_client_secret
ENV['BC_CLIENT_SECRET']
end
# Get the API url from env
def bc_api_url
ENV['BC_API_ENDPOINT'] || 'https://api.bigcommerce.com'
end
# Full url to this app
def app_url
ENV['APP_URL']
end
# The scopes we are requesting (must match what is requested in
# Developer Portal).
def scopes
ENV.fetch('SCOPES', 'store_v2_products')
end
def secure_compare(a, b)
return false if a.blank? || b.blank? || a.bytesize != b.bytesize
l = a.unpack "C#{a.bytesize}"
res = 0
b.each_byte { |byte| res |= byte ^ l.shift }
res.zero?
end
def render_error(e)
logger.warn "ERROR: #{e}"
@error = e
raise e
end
end
# config/routes.rb
Rails.application.routes.draw do
root 'welcome#index'
get '/auth/:name/callback' => 'omniauths#callback'
get '/load' => 'omniauths#load'
get '/uninstall' => 'omniauths#uninstall'
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment