lib/distack/urlsign/signer.rb in distack-urlsign-0.1.0 vs lib/distack/urlsign/signer.rb in distack-urlsign-0.2.0

- old
+ new

@@ -1,6 +1,8 @@ module Distack::URLSign + InvalidSignatureError = Class.new(StandardError) + class Signer KEY_REGEX = /^[0-9A-f]+$/ def initialize(hex_key) if hex_key !~ KEY_REGEX @@ -10,28 +12,55 @@ @key = [hex_key].pack("H*") end def sign(url) if url.opaque - raise "can't sign or verify opaque URL" + raise "can't sign opaque URL" end chunks = [url.scheme, "#{url.host}:#{url.port}", url.path, url.query, url.userinfo].compact digest = OpenSSL::Digest.new("sha512") rawsig = OpenSSL::HMAC.digest(digest, @key, chunks.join) signature = Base64.urlsafe_encode64(rawsig) if url.query - q = URI.decode_www_form(url.query) + q = Rack::Utils.parse_nested_query(url.query) else - q = [] + q = {} end - q << ["_signature", signature] + q ["_signature"] = signature new_url = url.dup - new_url.query = URI.encode_www_form(q) + new_url.query = Rack::Utils.build_nested_query(q) new_url + end + + def verify(url) + if url.opaque + raise "can't verify opaque URL" + end + + q = Rack::Utils.parse_nested_query(url.query) + + original_q = q.dup + original_q.delete("_signature") + + original_qs = Rack::Utils.build_nested_query(original_q) + + chunks = [url.scheme, "#{url.host}:#{url.port}", url.path, original_qs, url.userinfo].compact + digest = OpenSSL::Digest.new("sha512") + + rawsig = OpenSSL::HMAC.digest(digest, @key, chunks.join) + signature = Base64.urlsafe_encode64(rawsig) + + if signature == q["_signature"] + new_url = url.dup + new_url.query = original_qs + new_url + else + raise InvalidSignatureError, "signature is invalid for #{url}" + end end end end