module Caren module Exceptions class StandardError < ::StandardError ; end class SignatureMismatch < Caren::Exceptions::StandardError ; end class ServerSideError < Caren::Exceptions::StandardError attr_accessor :errors def initialize errors=[] self.errors = errors end end end class Api class << self # The public key file path used to verify request coming from Caren attr_accessor :caren_public_key_path # The private key file path used to sign requests coming from you attr_accessor :private_key_path # The care provider url provided by Caren. i.e. https://example.caren-cares.com attr_accessor :url end # The public key file used to verify request coming from Caren def self.caren_public_key @caren_public_key ||= OpenSSL::PKey::RSA.new(File.read(self.caren_public_key_path)) end # The private key file used to sign requests coming from you def self.private_key @private_key ||= OpenSSL::PKey::RSA.new(File.read(self.private_key_path)) end def self.put url, xml begin response = RestClient.put url, xml, :content_type => :xml, :accept => :xml, :signature => Caren::Api.sign(xml) return check_signature(response) rescue RestClient::Exception => e handle_error(e.response) end end def self.post url, xml begin response = RestClient.post url, xml, :content_type => :xml, :accept => :xml, :signature => Caren::Api.sign(xml) return check_signature(response) rescue RestClient::Exception => e handle_error(e.response) end end def self.delete url begin response = RestClient.delete url, :content_type => :xml, :accept => :xml, :signature => Caren::Api.sign return check_signature(response) rescue RestClient::Exception => e handle_error(e.response) end end def self.get url begin response = RestClient.get url, :content_type => :xml, :accept => :xml, :signature => Caren::Api.sign return check_signature(response) rescue RestClient::Exception => e handle_error(e.response) end end # Sign your string using Caren::Api.private_key def self.sign string="" encrypted_digest = Caren::Api.private_key.sign( "sha1", string ) signature = CGI.escape(Base64.encode64(encrypted_digest)) return signature end private # Check the signature of the response from rest-client def self.check_signature response return response if self.verify_signature( response.headers[:signature], response ) raise Caren::Exceptions::SignatureMismatch.new end # Verify the signature using the caren public key file def self.verify_signature signature, string="" signature = Base64.decode64(CGI.unescape(signature)) Caren::Api.caren_public_key.verify( "sha1", signature, string ) end # Raise a Caren exception on errors def self.handle_error response errors = [] doc = REXML::Document.new(response) doc.elements.each('errors/error') do |error| if error.attributes["category"] == "validation" attrs = { :on => error.attributes["on"].to_s.underscore.to_sym } errors << Caren::ValidationError.new( error.attributes["category"], error.text.strip, attrs ) else errors << Caren::Error.new( error.attributes["category"], error.text.strip ) end end raise Caren::Exceptions::ServerSideError.new(errors) end end end