module OAuth::Helper
Public Instance Methods
# File lib/oauth/helper.rb 20 def _escape(string) 21 # Percent-encode per RFC 3986 (unreserved: A-Z a-z 0-9 - . _ ~) 22 # Encode by byte to ensure stable behavior across Ruby versions and encodings. 23 bytes = string.to_s.b.bytes 24 bytes.map do |b| 25 ch = b.chr 26 if ch =~ OAuth::RESERVED_CHARACTERS 27 "%%%02X" % b 28 else 29 ch 30 end 31 end.join 32 end
Escape value by URL encoding all non-reserved character.
See Also: OAuth core spec version 1.0, section 5.1
# File lib/oauth/helper.rb 14 def escape(value) 15 _escape(value.to_s.to_str) 16 rescue ArgumentError 17 _escape(value.to_s.to_str.force_encoding(Encoding::UTF_8)) 18 end
Generate a random key of up to size bytes. The value returned is Base64 encoded with non-word characters removed.
# File lib/oauth/helper.rb 52 def generate_key(size = 32) 53 Base64.encode64(OpenSSL::Random.random_bytes(size)).gsub(/\W/, "") 54 end
Normalize a Hash of parameter values. Parameters are sorted by name, using lexicographical byte value ordering. If two or more parameters share the same name, they are sorted by their value. Parameters are concatenated in their sorted order into a single string. For each parameter, the name is separated from the corresponding value by an “=” character, even if the value is empty. Each name-value pair is separated by an “&” character.
See Also: OAuth core spec version 1.0, section 9.1.1
# File lib/oauth/helper.rb 69 def normalize(params) 70 params.sort.map do |k, values| 71 case values 72 when Array 73 # make sure the array has an element so we don't lose the key 74 values << nil if values.empty? 75 # multiple values were provided for a single key 76 if values[0].is_a?(Hash) 77 normalize_nested_query(values, k) 78 else 79 values.sort.collect do |v| 80 [escape(k), escape(v)].join("=") 81 end 82 end 83 when Hash 84 normalize_nested_query(values, k) 85 else 86 [escape(k), escape(values)].join("=") 87 end 88 end * "&" 89 end
Returns a string representation of the Hash like in URL query string build_nested_query({:level_1 => {:level_2 => ['value_1','value_2']}}, 'prefix'))
#=> ["prefix%5Blevel_1%5D%5Blevel_2%5D%5B%5D=value_1", "prefix%5Blevel_1%5D%5Blevel_2%5D%5B%5D=value_2"]
# File lib/oauth/helper.rb 94 def normalize_nested_query(value, prefix = nil) 95 case value 96 when Array 97 value.map do |v| 98 normalize_nested_query(v, "#{prefix}[]") 99 end.flatten.sort 100 when Hash 101 value.map do |k, v| 102 normalize_nested_query(v, prefix ? "#{prefix}[#{k}]" : k) 103 end.flatten.sort 104 else 105 [escape(prefix), escape(value)].join("=") 106 end 107 end
Parse an Authorization / WWW-Authenticate header into a hash. Takes care of unescaping and removing surrounding quotes. Raises a OAuth::Problem if the header is not parsable into a valid hash. Does not validate the keys or values.
hash = parse_header(headers['Authorization'] || headers['WWW-Authenticate']) hash['oauth_timestamp'] #=>"1234567890"
# File lib/oauth/helper.rb 117 def parse_header(header) 118 # decompose 119 params = header[6, header.length].split(/[,=&]/) 120 121 # odd number of arguments - must be a malformed header. 122 raise OAuth::Problem, "Invalid authorization header" if params.size.odd? 123 124 params.map! do |v| 125 # strip and unescape 126 val = unescape(v.strip) 127 # strip quotes 128 val.sub(/^"(.*)"$/, '\1') 129 end 130 131 # convert into a Hash 132 Hash[*params.flatten] 133 end
# File lib/oauth/helper.rb 135 def stringify_keys(hash) 136 new_h = {} 137 hash.each do |k, v| 138 new_h[k.to_s] = v.is_a?(Hash) ? stringify_keys(v) : v 139 end 140 new_h 141 end
# File lib/oauth/helper.rb 34 def unescape(value) 35 # Do NOT treat "+" as space; OAuth treats '+' as a literal plus unless percent-encoded. 36 str = value.to_s.gsub("+", "%2B") 37 # Decode %HH sequences; leave malformed sequences intact. 38 decoded = str.gsub(/%([0-9A-Fa-f]{2})/) { Regexp.last_match(1).to_i(16).chr } 39 # Prefer UTF-8 when the decoded bytes form valid UTF-8; otherwise, return as binary. 40 begin 41 utf8 = decoded.dup 42 utf8.force_encoding(Encoding::UTF_8) 43 decoded = utf8 if utf8.valid_encoding? 44 rescue NameError 45 # Older Rubies without Encoding constants: keep original encoding. 46 end 47 decoded 48 end