Current section
Files
Jump to
Current section
Files
lib/shopify/hmac.ex
defmodule Shopify.HMAC do
@moduledoc """
Helper functions to verify HMAC signatures.
"""
@doc """
Verifies an HTTP query string passes HMAC verification.
See `verify/3` for more details.
## Example
query = "code=0907a61c0c8d55e99db179b68161bc00&hmac=4712bf92ffc2917d15a2f5a273e39f0116667419aa4b6ac0b3baaf26fa3c4d20&shop=some-shop.myshopify.com×tamp=1337178173"
shared_secret = "hush"
hmac = "4712bf92ffc2917d15a2f5a273e39f0116667419aa4b6ac0b3baaf26fa3c4d20"
{:ok, hmac} = Shopify.HMAC.verify(query, shared_secret)
"""
@spec verify(binary, binary) :: {:ok, binary} | {:error, binary}
def verify(query, shared_secret) do
decoded_query = URI.decode_query(query)
{hmac, decoded_message} = Map.pop(decoded_query, "hmac")
message = URI.encode_query(decoded_message)
verify(hmac, message, shared_secret)
end
@doc """
Verifies the Shopify HMAC signature.
Every request or redirect from Shopify includes an HMAC signature that can be
used to ensure that it came from Shopify.
This function will compute an SHA256 HMAC digest based on the provided
`message` and `shared_secret`. The digest is then compared to the `hmac`
signature. If they match, verification has passed. Otherwise verification
has failed.
## Example
hmac = "4712bf92ffc2917d15a2f5a273e39f0116667419aa4b6ac0b3baaf26fa3c4d20"
message = "code=0907a61c0c8d55e99db179b68161bc00&shop=some-shop.myshopify.com×tamp=1337178173"
shared_secret = "hush"
{:ok, hmac} = Shopify.HMAC.verify(hmac, message, shared_secret)
"""
@spec verify(binary, binary, binary) :: {:ok, binary} | {:error, binary}
def verify(hmac, message, shared_secret) do
digest = compute_digest(message, shared_secret)
case digest do
^hmac ->
{:ok, digest}
_otherwise ->
{:error, digest}
end
end
defp compute_digest(message, shared_secret) do
:crypto.hmac(:sha256, shared_secret, message)
|> Base.encode16
|> String.downcase
end
end