Packages

Elixir Azure Storage REST Client support Blob, Queue, Fileshare and TableStorage service

Current section

Files

Jump to
ex_azure_storage lib azure_storage request sharedkey.ex
Raw

lib/azure_storage/request/sharedkey.ex

defmodule AzureStorage.Request.SharedKey do
@moduledoc false
require Logger
alias AzureStorage.Request.Context
def sign_request(
%Context{
service: service,
headers: headers,
account: %{name: account_name, key: account_key}
} = context
) do
data =
case service do
"table" -> context |> table_service_request()
_ -> context |> generic_service_request()
end
signature = sign(account_key, data)
auth_key = %{"authorization" => "SharedKey #{account_name}:#{signature}"}
headers =
headers
|> Map.merge(auth_key)
|> Map.to_list()
|> Enum.filter(fn
{_, ""} -> false
_ -> true
end)
# Logger.debug(
# "data: #{inspect(data)}\nsignature: #{inspect(auth_key)}\nheaders: #{inspect(headers)}"
# )
headers
end
#
# helpers
#
defp sign(account_key, data) do
key =
account_key
|> Base.decode64!()
:crypto.mac(:hmac, :sha256, key, data)
|> Base.encode64()
end
defp table_service_request(%Context{headers: headers, method: method} = context) do
canonical_resource = context |> Context.get_canonical_resource()
content_type = headers |> get_content_type()
[
method_atom_to_string(method),
"\n",
"\n",
content_type,
"\n",
headers[:"x-ms-date"],
"\n",
canonical_resource
]
|> IO.iodata_to_binary()
end
defp generic_service_request(%Context{method: method, headers: headers} = context) do
canonical_resource = context |> Context.get_canonical_resource()
canonical_headers = context |> Context.get_canonical_headers()
headers_uri_str = "#{canonical_headers}\n#{canonical_resource}"
content_length = headers |> get_content_length()
content_type = headers |> get_content_type()
[
method_atom_to_string(method),
"\n",
"\n",
"\n",
content_length,
"\n",
"\n",
content_type,
"\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"\n",
headers_uri_str
]
|> IO.iodata_to_binary()
end
defp method_atom_to_string(method), do: method |> Atom.to_string() |> String.upcase()
defp get_content_length(headers) do
Map.get(headers, :"content-length", "")
end
defp get_content_type(headers) do
Map.get(headers, :"Content-Type", "")
end
end