module Chargify2
class Direct
attr_reader :client
def initialize(client)
@client = client
validate_client
end
def secure_parameters(params = {})
SecureParameters.new(params, client)
end
def response_parameters(params = {})
ResponseParameters.new(params, client)
end
def self.signature(message, secret)
OpenSSL::HMAC.hexdigest(OpenSSL::Digest::Digest.new('sha1'), secret, message)
end
private
def validate_client
unless client.is_a?(Client)
raise ArgumentError.new("Direct.new requires a Client as an argument")
end
end
# There is no need to instantiate a SecureParameters instance directly. Use Direct#secure_parameters
# instead.
class SecureParameters
attr_reader :api_id
attr_reader :timestamp
attr_reader :nonce
attr_reader :data
attr_reader :secret
def initialize(hash, client)
args = hash.symbolize_keys
@api_id = client.api_id
@secret = client.api_secret
@timestamp = args[:timestamp]
@nonce = args[:nonce]
@data = args[:data]
validate_args
end
def to_form_inputs
output = []
output << %{}
output << %{} if timestamp?
output << %{} if nonce?
output << %{} if data?
output << %{}
output.join("\n")
end
%w(timestamp nonce data api_id secret).each do |method|
define_method("#{method}?") do
value = self.send(method)
value && !(value.is_a?(Hash) ? value : value.to_s.strip).empty?
end
end
def encoded_data
hash = data? ? data : {}
Rack::Utils.build_nested_query(hash)
end
def signature
message = "#{api_id}#{timestamp}#{nonce}#{encoded_data}"
Direct.signature(message, secret)
end
private
def h(s)
ERB::Util.html_escape(s)
end
def validate_args
if data && !data.is_a?(Hash)
raise ArgumentError.new("The 'data' must be provided as a Hash (you passed a #{data.class})")
end
unless api_id? && secret?
raise ArgumentError.new("SecureParameters require connection to a Client - was one given?")
end
end
end
# There is no need to instantiate a ResponseParameters instance directly. Use Direct#response_parameters instead.
class ResponseParameters
attr_reader :api_id
attr_reader :timestamp
attr_reader :nonce
attr_reader :status_code
attr_reader :result_code
attr_reader :call_id
attr_reader :secret
attr_reader :signature
def initialize(params, client)
args = params.symbolize_keys
@api_id = client.api_id
@secret = client.api_secret
@status_code = args[:status_code]
@timestamp = args[:timestamp]
@nonce = args[:nonce]
@result_code = args[:result_code]
@call_id = args[:call_id]
@signature = args[:signature]
validate_args
end
def verified?
message = "#{api_id}#{timestamp}#{nonce}#{status_code}#{result_code}#{call_id}"
Direct.signature(message, secret) == signature
end
def success?
status_code.to_s == '200'
end
private
def validate_args
unless api_id && secret && api_id.to_s.length > 0 && secret.to_s.length > 0
raise ArgumentError.new("ResponseParameters require connection to a Client - was one given?")
end
end
end
end
end