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