Module: ApiSignature::Utils
- Defined in:
- lib/api_signature/utils.rb
Class Method Summary collapse
- .canonical_header_value(value) ⇒ Object
- .hexhmac(key, value) ⇒ Object
- .hmac(key, value) ⇒ Object
- .normalize_keys(hash) ⇒ Object
- .normalized_querystring(querystring) ⇒ Object
- .safe_parse_datetime(value, format = nil) ⇒ Object
-
.secure_compare(string_a, string_b) ⇒ Object
constant-time comparison algorithm to prevent timing attacks.
- .sha256_hexdigest(value) ⇒ String<SHA256 Hexdigest>
- .standard_port?(uri) ⇒ true/false
- .uri_escape(string) ⇒ Object private
- .uri_escape_path(path) ⇒ Object
- .url_path(path, uri_escape_path = false) ⇒ Object
Class Method Details
.canonical_header_value(value) ⇒ Object
84 85 86 |
# File 'lib/api_signature/utils.rb', line 84 def self.canonical_header_value(value) value.match(/^".*"$/) ? value : value.gsub(/\s+/, ' ').strip end |
.hexhmac(key, value) ⇒ Object
92 93 94 |
# File 'lib/api_signature/utils.rb', line 92 def self.hexhmac(key, value) OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), key, value) end |
.hmac(key, value) ⇒ Object
88 89 90 |
# File 'lib/api_signature/utils.rb', line 88 def self.hmac(key, value) OpenSSL::HMAC.digest(OpenSSL::Digest.new('sha256'), key, value) end |
.normalize_keys(hash) ⇒ Object
96 97 98 99 100 |
# File 'lib/api_signature/utils.rb', line 96 def self.normalize_keys(hash) return {} unless hash hash.transform_keys { |key| key.to_s.downcase } end |
.normalized_querystring(querystring) ⇒ Object
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
# File 'lib/api_signature/utils.rb', line 61 def self.normalized_querystring(querystring) return unless querystring params = querystring.split('&') params = params.map { |p| p.match(/=/) ? p : p + '=' } # We have to sort by param name and preserve order of params that # have the same name. Default sort <=> in JRuby will swap members # occasionally when <=> is 0 (considered still sorted), but this # causes our normalized query string to not match the sent querystring. # When names match, we then sort by their original order params.each.with_index.sort do |a, b| a, a_offset = a a_name = a.split('=')[0] b, b_offset = b b_name = b.split('=')[0] if a_name == b_name a_offset <=> b_offset else a_name <=> b_name end end.map(&:first).join('&') end |
.safe_parse_datetime(value, format = nil) ⇒ Object
113 114 115 116 117 118 |
# File 'lib/api_signature/utils.rb', line 113 def self.safe_parse_datetime(value, format = nil) format ||= ApiSignature.configuration.datetime_format DateTime.strptime(value, format) rescue ArgumentError => _e nil end |
.secure_compare(string_a, string_b) ⇒ Object
constant-time comparison algorithm to prevent timing attacks
103 104 105 106 107 108 109 110 111 |
# File 'lib/api_signature/utils.rb', line 103 def self.secure_compare(string_a, string_b) return false if string_a.nil? || string_b.nil? || string_a.bytesize != string_b.bytesize l = string_a.unpack "C#{string_a.bytesize}" res = 0 string_b.each_byte { |byte| res |= byte ^ l.shift } res == 0 end |
.sha256_hexdigest(value) ⇒ String<SHA256 Hexdigest>
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
# File 'lib/api_signature/utils.rb', line 13 def self.sha256_hexdigest(value) if (File === value || Tempfile === value) && !value.path.nil? && File.exist?(value.path) OpenSSL::Digest::SHA256.file(value).hexdigest elsif value.respond_to?(:read) sha256 = OpenSSL::Digest::SHA256.new while chunk = value.read(1024 * 1024, buffer ||= '') # 1MB sha256.update(chunk) end value.rewind sha256.hexdigest else OpenSSL::Digest::SHA256.hexdigest(value) end end |
.standard_port?(uri) ⇒ true/false
33 34 35 36 |
# File 'lib/api_signature/utils.rb', line 33 def self.standard_port?(uri) (uri.scheme == 'http' && uri.port == 80) || (uri.scheme == 'https' && uri.port == 443) end |
.uri_escape(string) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
53 54 55 56 57 58 59 |
# File 'lib/api_signature/utils.rb', line 53 def self.uri_escape(string) if string.nil? nil else CGI.escape(string.encode('UTF-8')).gsub('+', '%20').gsub('%7E', '~') end end |
.uri_escape_path(path) ⇒ Object
48 49 50 |
# File 'lib/api_signature/utils.rb', line 48 def self.uri_escape_path(path) path.gsub(/[^\/]+/) { |part| uri_escape(part) } end |
.url_path(path, uri_escape_path = false) ⇒ Object
38 39 40 41 42 43 44 45 46 |
# File 'lib/api_signature/utils.rb', line 38 def self.url_path(path, uri_escape_path = false) path = '/' if path == '' if uri_escape_path uri_escape_path(path) else path end end |