How to generate signature using SHA-1 HMAC for google map in ruby
Question: I am trying to generate signature using SHA-1 HMAC in ruby for google maps
calls. I have got a python's code from the internet which I am trying to copy
into ruby. Following is phython's code

    
    
    import urllib.parse
    import base64
    import hashlib
    import hmac 
    GOOGLEAPIS_URL = 'http://maps.googleapis.com'
    STREETVIEW_ENDPOINT = '/maps/api/streetview'
    encodedParams = urllib.parse.urlencode({'size':'50x50','location':'42.35878993272469,-71.05793081223965','sensor':'false','client':'gme-securealert'});
    privateKey = 'Encoded_Key' # e.g XEL-B9Zs3lRLajIXkD-bqTYix20=
    decodedKey = base64.urlsafe_b64decode(privateKey)
    urlToSign = STREETVIEW_ENDPOINT + '?' + encodedParams
    print(urlToSign)
    signature = hmac.new(decodedKey, urlToSign.encode('utf-8') , hashlib.sha1)
    encodedSignature = base64.urlsafe_b64encode(signature.digest())
    print(encodedSignature
    

)

## that generates **OI2DXDLq7Qd790Lokaxgqtis_pE=** signature.

Following is the Ruby code that I am trying to achieve same signature with.

    
    
    GOOGLE_APIS_URL= "http://maps.googleapis.com"      
    key = Encoded_Key # e.g XEL-B9Zs3lRLajIXkD-bqTYix20=
    data ='/maps/api/streetview?size=50x50&sensor=false&client=gme-securealert&location=42.35878993272469,-71.05793081223965'
    
    data_array = data.split("?")
    STREET_VIEW_ENDPOINT = data_array[0]
    query_string = data_array[1]
    
    encoded_query_string =  URI.escape(query_string) # to encode parameters only
    decoded_key = Base64.decode64(key) # to decode the key
    
    data = STREET_VIEW_ENDPOINT << '?' << encoded_query_string
    #p "DATA #{data}"
    #data = Base64.decode64(data)
    #puts "data #{data}"
    digest = OpenSSL::Digest.new('sha1')
    p OpenSSL::HMAC.digest(digest, decoded_key, data)
    hmac = Base64.encode64(OpenSSL::HMAC.digest(digest, decoded_key, data))
    p hmac
    

but this seems to be not working for me. Please guide.


Answer: You can create the hash for request parameters and use URI.encode_www_form for
encoding parameters. Use Base64.urlsafe_decode64 and Base64.urlsafe_encode64
instead of Base64.decode64 and Base64.encode64. In my case, I have used
reverse geocoding api. You will need to ammend the parameters and
REVERSE_GEOCODING_ENDPOINT_JSON. Hope this will help you. Please let me know
if you have any queries.

    
    
    GOOGLE_MAPS_API_CLIENT_ID = 'gme-xyz'
    GOOGLE_MAPS_API_CRYPTO_KEY = 'private_key'
    GOOGLEAPIS_HTTP_URL = 'http://maps.googleapis.com'
    REVERSE_GEOCODING_ENDPOINT_JSON = '/maps/api/geocode/json'
    
    str_latlng = lat.to_s + ',' + lon.to_s
    encoded_params = URI.encode_www_form({'latlng' => str_latlng,
                                          'client' => GOOGLE_MAPS_API_CLIENT_ID})
    decoded_key = Base64.urlsafe_decode64(GOOGLE_MAPS_API_CRYPTO_KEY)
    url_to_sign = REVERSE_GEOCODING_ENDPOINT_JSON + '?' + encoded_params
    digest = OpenSSL::Digest.new('sha1')
    signature = OpenSSL::HMAC.digest(digest, decoded_key, url_to_sign)
    encoded_signature = Base64.urlsafe_encode64(signature)
    signed_url = GOOGLEAPIS_HTTP_URL + REVERSE_GEOCODING_ENDPOINT_JSON + '?' + encoded_params + '&signature='+encoded_signature
    

