lib/pesapal/oauth.rb in pesapal-1.2.1 vs lib/pesapal/oauth.rb in pesapal-1.2.2
- old
+ new
@@ -1,178 +1,178 @@
module Pesapal
- module Oauth
+ module Oauth
- # generate query string from parameters hash
- def Oauth.generate_encoded_params_query_string(params = {})
+ # generate query string from parameters hash
+ def Oauth.generate_encoded_params_query_string(params = {})
- # 1) percent encode every key and value that will be signed
- # 2) sort the list of parameters alphabetically by encoded key
- # 3) for each key/value pair
- # - append the encoded key to the output string
- # - append the '=' character to the output string
- # - append the encoded value to the output string
- # 4) if there are more key/value pairs remaining, append a '&'
- # character to the output string
+ # 1) percent encode every key and value that will be signed
+ # 2) sort the list of parameters alphabetically by encoded key
+ # 3) for each key/value pair
+ # - append the encoded key to the output string
+ # - append the '=' character to the output string
+ # - append the encoded value to the output string
+ # 4) if there are more key/value pairs remaining, append a '&' character
+ # to the output string
- # the oauth spec says to sort lexigraphically, which is the default
- # alphabetical sort for many libraries. in case of two parameters
- # with the same encoded key, the oauth spec says to continue
- # sorting based on value
+ # the oauth spec says to sort lexigraphically, which is the default
+ # alphabetical sort for many libraries. in case of two parameters with
+ # the same encoded key, the oauth spec says to continue sorting based on
+ # value
- queries = []
- params.each do |k,v| queries.push "#{self.parameter_encode(k.to_s)}=#{self.parameter_encode(v.to_s)}" end
+ queries = []
+ params.each do |k,v| queries.push "#{self.parameter_encode(k.to_s)}=#{self.parameter_encode(v.to_s)}" end
- # parameters are sorted by name, using lexicographical byte value
- # ordering
- queries.sort!
+ # parameters are sorted by name, using lexicographical byte value
+ # ordering
+ queries.sort!
- queries.join('&')
- end
+ queries.join('&')
+ end
- # generate oauth nonce
- def Oauth.generate_nonce(length)
+ # generate oauth nonce
+ def Oauth.generate_nonce(length)
- # the consumer shall then generate a nonce value that is unique for
- # all requests with that timestamp. a nonce is a random string,
- # uniquely generated for each request. the nonce allows the service
- # provider to verify that a request has never been made before and
- # helps prevent replay attacks when requests are made over a non-
- # secure channel (such as http).
+ # the consumer shall then generate a nonce value that is unique for all
+ # requests with that timestamp. a nonce is a random string, uniquely
+ # generated for each request. the nonce allows the service provider to
+ # verify that a request has never been made before and helps prevent
+ # replay attacks when requests are made over a non- secure channel (such
+ # as http).
- chars = 'abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ0123456789'
- nonce = ''
- length.times { nonce << chars[rand(chars.size)] }
+ chars = 'abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ0123456789'
+ nonce = ''
+ length.times { nonce << chars[rand(chars.size)] }
- "#{nonce}"
- end
+ "#{nonce}"
+ end
- # generate the oauth signature using hmac-sha1 algorithm
- def Oauth.generate_oauth_signature(http_method, absolute_url, params, consumer_secret, token_secret = nil)
+ # generate the oauth signature using hmac-sha1 algorithm
+ def Oauth.generate_oauth_signature(http_method, absolute_url, params, consumer_secret, token_secret = nil)
- # the signature is calculated by passing the signature base string
- # and signing key to the hmac-sha1 hashing algorithm. the output of
- # the hmac signing function is a binary string. this needs to be
- # base64 encoded to produce the signature string.
+ # the signature is calculated by passing the signature base string and
+ # signing key to the hmac-sha1 hashing algorithm. the output of the hmac
+ # signing function is a binary string. this needs to be base64 encoded to
+ # produce the signature string.
- # for pesapal flow we don't have a token secret to we will set as
- # nil and the appropriate action will be taken as per the oauth
- # spec. see notes in the method that creates signing keys
+ # for pesapal flow we don't have a token secret to we will set as nil and
+ # the appropriate action will be taken as per the oauth spec. see notes in
+ # the method that creates signing keys
- # prepare the values we need
- digest = OpenSSL::Digest::Digest.new('sha1')
- signature_base_string = self.generate_signature_base_string(http_method, absolute_url, params)
- signing_key = self.generate_signing_key(consumer_secret, token_secret)
+ # prepare the values we need
+ digest = OpenSSL::Digest::Digest.new('sha1')
+ signature_base_string = self.generate_signature_base_string(http_method, absolute_url, params)
+ signing_key = self.generate_signing_key(consumer_secret, token_secret)
- hmac = OpenSSL::HMAC.digest(digest, signing_key, signature_base_string)
- Base64.encode64(hmac).chomp
- end
+ hmac = OpenSSL::HMAC.digest(digest, signing_key, signature_base_string)
+ Base64.encode64(hmac).chomp
+ end
- # generate query string from signable parameters hash
- def Oauth.generate_signable_encoded_params_query_string(params = {})
+ # generate query string from signable parameters hash
+ def Oauth.generate_signable_encoded_params_query_string(params = {})
- # oauth_signature parameter MUST be excluded, assumes it was already
- # initialized by calling set_parameters
- params.delete(:oauth_signature)
+ # oauth_signature parameter MUST be excluded, assumes it was already
+ # initialized by calling set_parameters
+ params.delete(:oauth_signature)
- self.generate_encoded_params_query_string params
- end
+ self.generate_encoded_params_query_string params
+ end
- # generate the oauth signature
- def Oauth.generate_signature_base_string(http_method, absolute_url, params)
+ # generate the oauth signature
+ def Oauth.generate_signature_base_string(http_method, absolute_url, params)
- # three values collected so far must be joined to make a single
- # string, from which the signature will be generated. This is
- # called the signature base string by the OAuth specification
+ # three values collected so far must be joined to make a single string,
+ # from which the signature will be generated. This is called the
+ # signature base string by the OAuth specification
- # step 1: convert the http method to uppercase
- http_method = http_method.upcase
+ # step 1: convert the http method to uppercase
+ http_method = http_method.upcase
- # step 2: percent encode the url
- url_encoded = self.parameter_encode(self.normalized_request_uri(absolute_url))
+ # step 2: percent encode the url
+ url_encoded = self.parameter_encode(self.normalized_request_uri(absolute_url))
- # step 3: percent encode the parameter string
- parameter_string_encoded = self.parameter_encode(self.generate_signable_encoded_params_query_string params)
+ # step 3: percent encode the parameter string
+ parameter_string_encoded = self.parameter_encode(self.generate_signable_encoded_params_query_string params)
- # the signature base string should contain exactly 2 ampersand '&'
- # characters. The percent '%' characters in the parameter string should
- # be encoded as %25 in the signature base string
+ # the signature base string should contain exactly 2 ampersand '&'
+ # characters. The percent '%' characters in the parameter string should be
+ # encoded as %25 in the signature base string
- "#{http_method}&#{url_encoded}&#{parameter_string_encoded}"
- end
+ "#{http_method}&#{url_encoded}&#{parameter_string_encoded}"
+ end
- # generate signing key
- def Oauth.generate_signing_key(consumer_secret, token_secret = nil)
+ # generate signing key
+ def Oauth.generate_signing_key(consumer_secret, token_secret = nil)
- # the signing key is simply the percent encoded consumer secret,
- # followed by an ampersand character '&', followed by the percent
- # encoded token secret
+ # the signing key is simply the percent encoded consumer secret, followed
+ # by an ampersand character '&', followed by the percent encoded token
+ # secret
- # note that there are some flows, such as when obtaining a request
- # token, where the token secret is not yet known. In this case, the
- # signing key should consist of the percent encoded consumer secret
- # followed by an ampersand character '&'
+ # note that there are some flows, such as when obtaining a request token,
+ # where the token secret is not yet known. In this case, the signing key
+ # should consist of the percent encoded consumer secret followed by an
+ # ampersand character '&'
- # "#{@credentials[:consumer_secret]}"
- consumer_secret_encoded = self.parameter_encode(consumer_secret)
+ # "#{@credentials[:consumer_secret]}"
+ consumer_secret_encoded = self.parameter_encode(consumer_secret)
- token_secret_encoded = ""
- unless token_secret.nil?
- token_secret_encoded = self.parameter_encode(token_secret)
- end
+ token_secret_encoded = ""
+ unless token_secret.nil?
+ token_secret_encoded = self.parameter_encode(token_secret)
+ end
- "#{consumer_secret_encoded}&#{token_secret_encoded}"
- end
+ "#{consumer_secret_encoded}&#{token_secret_encoded}"
+ end
- # normalize request absolute URL
- def Oauth.normalized_request_uri(absolute_url)
+ # normalize request absolute URL
+ def Oauth.normalized_request_uri(absolute_url)
- # the signature base string includes the request absolute url, tying
- # the signature to a specific endpoint. the url used in the
- # signature base string must include the scheme, authority, and
- # path, and must exclude the query and fragment as defined by
- # [rfc3986] section 3.
+ # the signature base string includes the request absolute url, tying the
+ # signature to a specific endpoint. the url used in the signature base
+ # string must include the scheme, authority, and path, and must exclude
+ # the query and fragment as defined by [rfc3986] section 3.
- # if the absolute request url is not available to the service
- # provider (it is always available to the consumer), it can be
- # constructed by combining the scheme being used, the http host
- # header, and the relative http request url. if the host header is
- # not available, the service provider should use the host name
- # communicated to the consumer in the documentation or other means.
+ # if the absolute request url is not available to the service provider (it
+ # is always available to the consumer), it can be constructed by combining
+ # the scheme being used, the http host header, and the relative http
+ # request url. if the host header is not available, the service provider
+ # should use the host name communicated to the consumer in the
+ # documentation or other means.
- # the service provider should document the form of url used in the
- # signature base string to avoid ambiguity due to url normalization.
- # unless specified, url scheme and authority must be lowercase and
- # include the port number; http default port 80 and https default
- # port 443 must be excluded.
+ # the service provider should document the form of url used in the
+ # signature base string to avoid ambiguity due to url normalization.
+ # unless specified, url scheme and authority must be lowercase and include
+ # the port number; http default port 80 and https default port 443 must be
+ # excluded.
- u = URI.parse(absolute_url)
+ u = URI.parse(absolute_url)
- scheme = u.scheme.downcase
- host = u.host.downcase
- path = u.path
- port = u.port
+ scheme = u.scheme.downcase
+ host = u.host.downcase
+ path = u.path
+ port = u.port
- port = (scheme == 'http' && port != 80) || (scheme == 'https' && port != 443) ? ":#{port}" : ""
- path = (path && path != '') ? path : '/'
+ port = (scheme == 'http' && port != 80) || (scheme == 'https' && port != 443) ? ":#{port}" : ""
+ path = (path && path != '') ? path : '/'
- "#{scheme}://#{host}#{port}#{path}"
- end
+ "#{scheme}://#{host}#{port}#{path}"
+ end
- # percentage encode value as per the oauth spec
- def Oauth.parameter_encode(string)
+ # percentage encode value as per the oauth spec
+ def Oauth.parameter_encode(string)
- # all parameter names and values are escaped using the [rfc3986]
- # percent-encoding (%xx) mechanism. characters not in the unreserved
- # character set ([rfc3986] section 2.3) must be encoded. characters
- # in the unreserved character set must not be encoded. hexadecimal
- # characters in encodings must be upper case. text names and values
- # must be encoded as utf-8 octets before percent-encoding them per
- # [rfc3629].
+ # all parameter names and values are escaped using the [rfc3986] percent-
+ # encoding (%xx) mechanism. characters not in the unreserved character set
+ # ([rfc3986] section 2.3) must be encoded. characters in the unreserved
+ # character set must not be encoded. hexadecimal characters in encodings
+ # must be upper case. text names and values must be encoded as utf-8
+ # octets before percent-encoding them per [rfc3629].
- # reserved character regexp, per section 5.1
- reserved_characters = /[^a-zA-Z0-9\-\.\_\~]/
+ # reserved character regexp, per section 5.1
+ reserved_characters = /[^a-zA-Z0-9\-\.\_\~]/
- URI::escape(string.to_s.force_encoding(Encoding::UTF_8), reserved_characters)
- end
+ # Apparently we can't force_encoding on a frozen string since that would modify it.
+ # What we can do is work with a copy
+ URI::escape(string.dup.to_s.force_encoding(Encoding::UTF_8), reserved_characters)
end
-end
\ No newline at end of file
+ end
+end