class GoCardless::Client

Constants

API_PATH
BASE_URLS

Attributes

merchant_id[W]

Public Class Methods

base_url() click to toggle source
# File lib/gocardless/client.rb, line 22
def base_url
  @base_url || BASE_URLS[GoCardless.environment || :production]
end
base_url=(url) click to toggle source
# File lib/gocardless/client.rb, line 18
def base_url=(url)
  @base_url = url.sub(%r|/$|, '')
end
new(args = {}) click to toggle source
# File lib/gocardless/client.rb, line 27
def initialize(args = {})
  Utils.symbolize_keys! args
  @app_id = args.fetch(:app_id) { ENV['GOCARDLESS_APP_ID'] }
  @app_secret = args.fetch(:app_secret) { ENV['GOCARDLESS_APP_SECRET'] }
  raise ClientError.new("You must provide an app_id") unless @app_id
  raise ClientError.new("You must provide an app_secret") unless @app_secret

  @oauth_client = OAuth2::Client.new(@app_id, @app_secret,
                                     :site => self.base_url,
                                     :token_url => '/oauth/access_token')

  self.access_token = args[:token] if args[:token]
  @merchant_id = args[:merchant_id] if args[:merchant_id]
end

Public Instance Methods

access_token() click to toggle source
# File lib/gocardless/client.rb, line 81
def access_token
  warn "[DEPRECATION] (gocardless-ruby) the behaviour of " +
       "Client#access_token is deprecated. In future releases it will " +
       "return the unscoped access token. If you want the scoped access " +
       "token, use 'scoped_access_token'"
  self.scoped_access_token
end
access_token=(token) click to toggle source

Set the client’s access token

@param [String] token a string with format "#{token}"

(as returned by {#access_token})
# File lib/gocardless/client.rb, line 105
def access_token=(token)
  token, scope = token.sub(/^bearer\s+/i, '').split(' ', 2)
  if scope
    warn "[DEPRECATION] (gocardless-ruby) merchant_id is now a separate " +
         "attribute, the manage_merchant scope should no longer be " +
         "included in the 'token' attribute. See http://git.io/G9y37Q " +
         "for more info."
  else
    scope = ''
  end

  @access_token = OAuth2::AccessToken.new(@oauth_client, token)
  @access_token.params['scope'] = scope

  set_merchant_id_from_scope(scope) unless @merchant_id
end
api_delete(path, data = {}) click to toggle source

Issue a DELETE request to the API server

@note this method is for internal use @param [String] path the path that will be added to the API prefix @param [Hash] data a hash of data that will be sent as the request body @return [Hash] hash the parsed response data

# File lib/gocardless/client.rb, line 166
def api_delete(path, data = {})
  api_request(:delete, path, :data => data).parsed
end
api_get(path, params = {}) click to toggle source

Issue an GET request to the API server

@note this method is for internal use @param [String] path the path that will be added to the API prefix @param [Hash] params query string parameters @return [Hash] hash the parsed response data

# File lib/gocardless/client.rb, line 136
def api_get(path, params = {})
  api_request(:get, path, :params => params).parsed
end
api_post(path, data = {}) click to toggle source

Issue a POST request to the API server

@note this method is for internal use @param [String] path the path that will be added to the API prefix @param [Hash] data a hash of data that will be sent as the request body @return [Hash] hash the parsed response data

# File lib/gocardless/client.rb, line 146
def api_post(path, data = {})
  api_request(:post, path, :data => data).parsed
end
api_put(path, data = {}) click to toggle source

Issue a PUT request to the API server

@note this method is for internal use @param [String] path the path that will be added to the API prefix @param [Hash] data a hash of data that will be sent as the request body @return [Hash] hash the parsed response data

# File lib/gocardless/client.rb, line 156
def api_put(path, data = {})
  api_request(:put, path, :data => data).parsed
end
api_request(method, path, opts = {}) click to toggle source

Issue a request to the API server, returning the full response

@note this method is for internal use @param [Symbol] method the HTTP method to use (e.g. :get, :post) @param [String] path the path that will be added to the API prefix @option [Hash] opts additional request options (e.g. form data, params)

# File lib/gocardless/client.rb, line 177
def api_request(method, path, opts = {})
  request(method, "#{API_PATH}#{path}", opts)
end
api_url() click to toggle source
# File lib/gocardless/client.rb, line 329
def api_url
  "#{base_url}#{API_PATH}"
end
authorize_url(options) click to toggle source

Generate the OAuth authorize url

@param [Hash] options parameters to be included in the url.

+:redirect_uri+ is required.

@return [String] the authorize url

# File lib/gocardless/client.rb, line 47
def authorize_url(options)
  raise ArgumentError, ':redirect_uri required' unless options[:redirect_uri]
  params = {
    :client_id => @app_id,
    :response_type => 'code',
    :scope => 'manage_merchant'
  }
  # Faraday doesn't flatten params in this case (Faraday issue #115)
  options = Hash[Utils.flatten_params(options)]
  @oauth_client.authorize_url(params.merge(options))
end
Also aliased as: new_merchant_url
base_url() click to toggle source

Get the base URL for the client. If set manually for the instance, that URL will be returned. Otherwise, it will be deferred to Client.base_url.

# File lib/gocardless/client.rb, line 325
def base_url
  @base_url || self.class.base_url
end
base_url=(url) click to toggle source

Set the base URL for this client instance. Overrides all other settings (setting the environment globally, setting the Client class’s base URL).

@param [String] url the base URL to use

# File lib/gocardless/client.rb, line 318
def base_url=(url)
  @base_url = url
end
bill(id) click to toggle source

@method bill(id) @param [String] id of the bill @return [Bill] the Bill matching the id requested

# File lib/gocardless/client.rb, line 212
def bill(id)
  Bill.find_with_client(self, id)
end
confirm_resource(params) click to toggle source

Confirm a newly-created subscription, pre-authorzation or one-off bill. This method also checks that the resource response data includes a valid signature and will raise a {SignatureError} if the signature is invalid.

@param [Hash] params the response parameters returned by the API server @return [Resource] the confirmed resource object

# File lib/gocardless/client.rb, line 269
def confirm_resource(params)
  params = prepare_params(params)

  if signature_valid?(params)
    data = {
      :resource_id => params[:resource_id],
      :resource_type => params[:resource_type],
    }

    credentials = Base64.encode64("#{@app_id}:#{@app_secret}")
    credentials = credentials.gsub(/\s/, '')
    headers = {
      'Authorization' => "Basic #{credentials}"
    }
    request(:post, "#{api_url}/confirm", :data => data,
                                              :headers => headers)

    # Initialize the correct class according to the resource's type
    klass = GoCardless.const_get(Utils.camelize(params[:resource_type]))
    klass.find_with_client(self, params[:resource_id])
  else
    raise SignatureError, 'An invalid signature was detected'
  end
end
create_bill(attrs) click to toggle source

Create a new bill under a given pre-authorization @see PreAuthorization#create_bill

@param [Hash] attrs must include :source_id (the id of the pre_authorization you want to bill from) and :amount @return [Bill] the created bill object

# File lib/gocardless/client.rb, line 222
def create_bill(attrs)
  Bill.new_with_client(self, attrs).save
end
fetch_access_token(auth_code, options) click to toggle source

Exchange the authorization code for an access token

@param [String] auth_code to exchange for the access_token @return [String] the access_token required to make API calls to resources

# File lib/gocardless/client.rb, line 64
def fetch_access_token(auth_code, options)
  raise ArgumentError, ':redirect_uri required' unless options[:redirect_uri]
  # Exchange the auth code for an access token
  @access_token = @oauth_client.auth_code.get_token(auth_code, options)

  # Use the scope to figure out which merchant we're managing
  scope = @access_token.params[:scope] || @access_token.params['scope']
  set_merchant_id_from_scope(scope)

  self.scoped_access_token
end
merchant() click to toggle source

@method merchant @return [Merchant] the merchant associated with the client’s access token

# File lib/gocardless/client.rb, line 183
def merchant
  raise ClientError, 'Access token missing' unless @access_token
  Merchant.new_with_client(self, api_get("/merchants/#{merchant_id}"))
end
merchant_id() click to toggle source

Return the merchant id, throwing a proper error if it’s missing.

# File lib/gocardless/client.rb, line 123
def merchant_id
  raise ClientError, 'No merchant id set' unless @merchant_id
  @merchant_id
end
new_bill_url(params) click to toggle source

Generate the URL for creating a new bill. The parameters passed in define various attributes of the bill. Redirecting a user to the resulting URL will show them a page where they can approve or reject the bill described by the parameters. Note that this method automatically includes the nonce, timestamp and signature.

@param [Hash] params the bill parameters @return [String] the generated URL

# File lib/gocardless/client.rb, line 258
def new_bill_url(params)
  new_limit_url(:bill, params)
end
new_merchant_url(options)
Alias for: authorize_url
new_pre_authorization_url(params) click to toggle source

Generate the URL for creating a new pre authorization. The parameters passed in define various attributes of the pre authorization. Redirecting a user to the resulting URL will show them a page where they can approve or reject the pre authorization described by the parameters. Note that this method automatically includes the nonce, timestamp and signature.

@param [Hash] params the pre authorization parameters @return [String] the generated URL

# File lib/gocardless/client.rb, line 246
def new_pre_authorization_url(params)
  new_limit_url(:pre_authorization, params)
end
new_subscription_url(params) click to toggle source

Generate the URL for creating a new subscription. The parameters passed in define various attributes of the subscription. Redirecting a user to the resulting URL will show them a page where they can approve or reject the subscription described by the parameters. Note that this method automatically includes the nonce, timestamp and signature.

@param [Hash] params the subscription parameters @return [String] the generated URL

# File lib/gocardless/client.rb, line 234
def new_subscription_url(params)
  new_limit_url(:subscription, params)
end
pre_authorization(id) click to toggle source

@method pre_authorization(id) @param [String] id of the pre_authorization @return [PreAuthorization] the pre_authorization matching the id requested

# File lib/gocardless/client.rb, line 198
def pre_authorization(id)
  PreAuthorization.find_with_client(self, id)
end
response_params_valid?(params) click to toggle source

Check that resource response data includes a valid signature.

@param [Hash] params the response parameters returned by the API server @return [Boolean] true when valid, false otherwise

# File lib/gocardless/client.rb, line 299
def response_params_valid?(params)
  params = prepare_params(params)

  signature_valid?(params)
end
scope() click to toggle source

@return [String] the scope of the current access token

# File lib/gocardless/client.rb, line 95
def scope
  if @access_token
    @access_token.params[:scope] || @access_token.params['scope']
  end
end
scoped_access_token() click to toggle source

@return [String] a serialized form of the access token with its scope

# File lib/gocardless/client.rb, line 77
def scoped_access_token
  "#{self.unscoped_access_token} #{self.scope}".strip if @access_token
end
subscription(id) click to toggle source

@method subscripton(id) @param [String] id of the subscription @return [Subscription] the subscription matching the id requested

# File lib/gocardless/client.rb, line 191
def subscription(id)
  Subscription.find_with_client(self, id)
end
unscoped_access_token() click to toggle source

@return [String] a serialized form of the access token without its scope

# File lib/gocardless/client.rb, line 90
def unscoped_access_token
  @access_token.token if @access_token
end
user(id) click to toggle source

@method user(id) @param [String] id of the user @return [User] the User matching the id requested

# File lib/gocardless/client.rb, line 205
def user(id)
  User.find_with_client(self, id)
end
user_agent() click to toggle source
# File lib/gocardless/client.rb, line 333
def user_agent
  @user_agent ||=
    begin
      gem_info = "gocardless-ruby/v#{GoCardless::VERSION}"
      ruby_engine = defined?(RUBY_ENGINE) ? RUBY_ENGINE : 'ruby'
      ruby_version = RUBY_VERSION
      ruby_version += " p#{RUBY_PATCHLEVEL}" if defined?(RUBY_PATCHLEVEL)
      comment = ["#{ruby_engine} #{ruby_version}"]
      comment << RUBY_PLATFORM if defined?(RUBY_PLATFORM)
      "#{gem_info} (#{comment.join("; ")})"
    end
end
webhook_valid?(params) click to toggle source

Validates the payload contents of a webhook request.

@param [Hash] params the contents of payload of the webhook @return [Boolean] true when valid, false otherwise

# File lib/gocardless/client.rb, line 310
def webhook_valid?(params)
  signature_valid?(params)
end

Private Instance Methods

generate_nonce() click to toggle source

Generate a random base64-encoded string

@return [String] a randomly generated string

# File lib/gocardless/client.rb, line 428
def generate_nonce
  Base64.encode64((0...45).map { rand(256).chr }.join).strip
end
new_limit_url(type, limit_params) click to toggle source

Generate the URL for creating a limit of type type, including the provided params, nonce, timestamp and signature

@param [Symbol] type the limit type (:subscription, etc) @param [Hash] params the bill parameters @return [String] the generated URL

# File lib/gocardless/client.rb, line 438
def new_limit_url(type, limit_params)
  url = URI.parse("#{base_url}/connect/#{type}s/new")

  limit_params[:merchant_id] = merchant_id
  redirect_uri = limit_params.delete(:redirect_uri)
  cancel_uri = limit_params.delete(:cancel_uri)
  state = limit_params.delete(:state)

  params = {
    :nonce       => generate_nonce,
    :timestamp   => Time.now.getutc.strftime('%Y-%m-%dT%H:%M:%SZ'),
    :client_id   => @app_id,
    type         => limit_params,
  }
  params[:redirect_uri] = redirect_uri unless redirect_uri.nil?
  params[:cancel_uri] = cancel_uri unless cancel_uri.nil?
  params[:state] = state unless state.nil?

  sign_params(params)

  url.query = Utils.normalize_params(params)
  url.to_s
end
prepare_params(params) click to toggle source

Prepare a Hash of parameters for signing. Presence of required parameters is checked and the others are discarded.

@param [Hash] params the parameters to be prepared for signing @return [Hash] the prepared parameters

# File lib/gocardless/client.rb, line 400
def prepare_params(params)
  # Create a new hash in case is a HashWithIndifferentAccess (keys are
  # always a String)
  params = Utils.symbolize_keys(Hash[params])
  # Only pull out the relevant parameters, other won't be included in the
  # signature so will cause false negatives
  keys = [:resource_id, :resource_type, :resource_uri, :state, :signature]
  params = Hash[params.select { |k,v| keys.include? k }]
  (keys - [:state]).each do |key|
    raise ArgumentError, "Parameters missing #{key}" if !params.key?(key)
  end
  params
end
request(method, path, opts = {}) click to toggle source

Send a request to the GoCardless API servers

@param [Symbol] method the HTTP method to use (e.g. :get, :post) @param [String] path the path fragment of the URL @option [Hash] opts query string parameters

# File lib/gocardless/client.rb, line 359
def request(method, path, opts = {})
  raise ClientError, 'Access token missing' unless @access_token

  opts[:headers] = {} if opts[:headers].nil?
  opts[:headers]['Accept'] = 'application/json'
  opts[:headers]['Content-Type'] = 'application/json' unless method == :get
  opts[:headers]['User-Agent'] = user_agent
  opts[:body] = MultiJson.encode(opts[:data]) if !opts[:data].nil?
  path = URI.encode(path)

  # Reset the URL in case the environment / base URL has been changed.
  @oauth_client.site = base_url

  header_keys = opts[:headers].keys.map(&:to_s)
  if header_keys.map(&:downcase).include?('authorization')
    @oauth_client.request(method, path, opts)
  else
    @access_token.send(method, path, opts)
  end
rescue OAuth2::Error => err
  raise GoCardless::ApiError.new(err.response)
end
set_merchant_id_from_scope(scope) click to toggle source

Pull the merchant id out of the access scope

# File lib/gocardless/client.rb, line 349
def set_merchant_id_from_scope(scope)
  perm = scope.split.select {|p| p.start_with?('manage_merchant:') }.first
  @merchant_id = perm.split(':')[1] if perm
end
sign_params(params) click to toggle source

Add a signature to a Hash of parameters. The signature will be generated from the app secret and the provided parameters, and should be used whenever signed data needs to be sent to GoCardless (e.g. when creating a new subscription). The signature will be added to the hash under the key :signature.

@param [Hash] params the parameters to sign @return [Hash] the parameters with the new :signature key

# File lib/gocardless/client.rb, line 390
def sign_params(params)
  params[:signature] = Utils.sign_params(params, @app_secret)
  params
end
signature_valid?(params) click to toggle source

Check if a hash’s :signature is valid

@param [Hash] params the parameters to check @return [Boolean] whether or not the signature is valid

# File lib/gocardless/client.rb, line 418
def signature_valid?(params)
  params = params.clone
  signature = params.delete(:signature)
  return false unless signature
  Utils.secure_compare(sign_params(params)[:signature], signature)
end