Module: MAuth::Signable
Overview
module which composes a string to sign.
includer must provide
-
SIGNATURE_COMPONENTS OR SIGNATURE_COMPONENTS_V2 constant - array of keys to get from
-
#attributes_for_signing
-
#merge_headers (takes a Hash of headers; returns an instance of includer’s own class whose headers have been updated with the argument headers)
Instance Method Summary collapse
- #attributes_for_signing ⇒ Object
-
#encode_query_string(q_string) ⇒ Object
sorts query string parameters by codepoint, uri encodes keys and values, and rejoins parameters into a query string.
- #initialize(attributes_for_signing) ⇒ Object
-
#string_to_sign_v1(more_attributes) ⇒ Object
the string to sign for V1 protocol will be (where LF is line feed character) for requests: string_to_sign = http_verb + <LF> + resource_url_path (no host, port or query string; first “/” is included) + <LF> + request_body + <LF> + app_uuid + <LF> + current_seconds_since_epoch.
-
#string_to_sign_v2(override_attrs) ⇒ Object
the string to sign for V2 protocol will be (where LF is line feed character) for requests: string_to_sign = http_verb + <LF> + resource_url_path (no host, port or query string; first “/” is included) + <LF> + request_body_digest + <LF> + app_uuid + <LF> + current_seconds_since_epoch + <LF> + encoded_query_params.
-
#uri_escape(string) ⇒ Object
percent encodes special characters, preserving character encoding.
Instance Method Details
#attributes_for_signing ⇒ Object
104 105 106 |
# File 'lib/mauth/request_and_response.rb', line 104 def attributes_for_signing @attributes_for_signing end |
#encode_query_string(q_string) ⇒ Object
sorts query string parameters by codepoint, uri encodes keys and values, and rejoins parameters into a query string
83 84 85 86 87 88 |
# File 'lib/mauth/request_and_response.rb', line 83 def encode_query_string(q_string) q_string.split('&').sort.map do |part| k, e, v = part.partition('=') uri_escape(k) + e + uri_escape(v) end.join('&') end |
#initialize(attributes_for_signing) ⇒ Object
100 101 102 |
# File 'lib/mauth/request_and_response.rb', line 100 def initialize(attributes_for_signing) @attributes_for_signing = attributes_for_signing end |
#string_to_sign_v1(more_attributes) ⇒ Object
the string to sign for V1 protocol will be (where LF is line feed character) for requests:
string_to_sign =
http_verb + <LF> +
resource_url_path (no host, port or query string; first "/" is included) + <LF> +
request_body + <LF> +
app_uuid + <LF> +
current_seconds_since_epoch
for responses:
string_to_sign =
status_code_string + <LF> +
response_body_digest + <LF> +
app_uuid + <LF> +
current_seconds_since_epoch
31 32 33 34 35 36 37 38 39 |
# File 'lib/mauth/request_and_response.rb', line 31 def string_to_sign_v1(more_attributes) attributes_for_signing = self.attributes_for_signing.merge(more_attributes) missing_attributes = self.class::SIGNATURE_COMPONENTS.select { |key| !attributes_for_signing.key?(key) || attributes_for_signing[key].nil? } missing_attributes.delete(:body) # body may be omitted if missing_attributes.any? raise(UnableToSignError, "Missing required attributes to sign: #{missing_attributes.inspect}\non object to sign: #{inspect}") end self.class::SIGNATURE_COMPONENTS.map { |k| attributes_for_signing[k].to_s }.join("\n") end |
#string_to_sign_v2(override_attrs) ⇒ Object
the string to sign for V2 protocol will be (where LF is line feed character) for requests:
string_to_sign =
http_verb + <LF> +
resource_url_path (no host, port or query string; first "/" is included) + <LF> +
request_body_digest + <LF> +
app_uuid + <LF> +
current_seconds_since_epoch + <LF> +
encoded_query_params
for responses:
string_to_sign =
status_code_string + <LF> +
response_body_digest + <LF> +
app_uuid + <LF> +
current_seconds_since_epoch
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
# File 'lib/mauth/request_and_response.rb', line 57 def string_to_sign_v2(override_attrs) attrs_with_overrides = self.attributes_for_signing.merge(override_attrs) # memoization of body_digest to avoid hashing three times when we call # string_to_sign_v2 three times in client#signature_valid_v2! # note that if :body is nil we hash an empty string ('') attrs_with_overrides[:body_digest] ||= Digest::SHA512.hexdigest(attrs_with_overrides[:body] || '') attrs_with_overrides[:encoded_query_params] = encode_query_string(attrs_with_overrides[:query_string] || '') missing_attributes = self.class::SIGNATURE_COMPONENTS_V2.reject do |key| attrs_with_overrides.dig(key) end missing_attributes.delete(:body_digest) # body may be omitted missing_attributes.delete(:encoded_query_params) # query_string may be omitted if missing_attributes.any? raise(UnableToSignError, "Missing required attributes to sign: #{missing_attributes.inspect}\non object to sign: #{inspect}") end self.class::SIGNATURE_COMPONENTS_V2.map do |k| attrs_with_overrides[k].to_s.dup.force_encoding('UTF-8') end.join("\n") end |
#uri_escape(string) ⇒ Object
percent encodes special characters, preserving character encoding. encodes space as ‘%20’ does not encode A-Z, a-z, 0-9, hyphen ( - ), underscore ( _ ), period ( . ), or tilde ( ~ ) NOTE the CGI.escape spec changed in 2.5 to not escape tildes. we gsub tilde encoding back to tildes to account for older Rubies
96 97 98 |
# File 'lib/mauth/request_and_response.rb', line 96 def uri_escape(string) CGI.escape(string).gsub(/\+|%7E/, '+' => '%20', '%7E' => '~') end |