defmodule TencentCloud.Core do
@moduledoc """
Common functions for TencentCloud.
"""
@doc """
Gen Common Headers
## Examples
iex> TencentCloud.Core.common_headers(
...> %{
...> host: "nlp.tencentcloudapi.com",
...> action: "ChatBot",
...> version: "2019-04-08",
...> region: "ap-guangzhou",
...> date: "2021-09-27",
...> timestamp: 1632706407,
...> access_key_id: "GebjUWWJJVnL1en1gtgb52CmNJN8CqdKC0ne",
...> access_key_secret: "QtXXc6HftX/LEwrSi+MR4OyVEnEslwyg"
...> },
...> ~s({"Query":"你好,红领巾,我叫白胡子"})
...> )
[
{"X-TC-Action", "ChatBot"},
{"X-TC-Region", "ap-guangzhou"},
{"X-TC-Timestamp", "1632706407"},
{"X-TC-Version", "2019-04-08"},
{"Authorization", "TC3-HMAC-SHA256 Credential=GebjUWWJJVnL1en1gtgb52CmNJN8CqdKC0ne/2021-09-27/nlp/tc3_request, SignedHeaders=content-type;host, Signature=3ec0d092a50635e6bdfcf051750d55dca5bc39e270348d8e46f928d50d3ed833"},
{"Content-Type", "application/json; charset=utf-8"},
{"Host", "nlp.tencentcloudapi.com"}
]
"""
@spec common_headers(common :: map, body :: binary) :: list
def common_headers(
%{
host: host,
action: action,
version: version,
region: region,
access_key_id: secret_id,
access_key_secret: secret_key
} = common,
body
) do
content_type = Map.get(common, :content_type, "application/json; charset=utf-8")
timestamp = Map.get_lazy(common, :timestamp, fn -> System.system_time(:second) end) |> to_string()
date =
Map.get_lazy(common, :date, fn -> :erlang.date() |> Date.from_erl!() |> Date.to_string() end)
service = Map.get_lazy(common, :service, fn -> host |> String.split(".") |> hd() end)
credential_scope = "#{date}/#{service}/tc3_request"
signature =
sign(host, body, content_type, timestamp, date, service, credential_scope, secret_key)
authorization =
"TC3-HMAC-SHA256 Credential=#{secret_id}/#{credential_scope}, SignedHeaders=content-type;host, Signature=#{signature}"
[
{"X-TC-Action", action},
{"X-TC-Region", region},
{"X-TC-Timestamp", timestamp},
{"X-TC-Version", version},
{"Authorization", authorization},
{"Content-Type", content_type},
{"Host", host}
]
end
def sign(host, body, content_type, timestamp, date, service, credential_scope, secret_key) do
canonical_request =
"POST\n/\n\ncontent-type:#{content_type}\nhost:#{host}\n\ncontent-type;host\n#{hash(body)}"
string_to_sign =
"TC3-HMAC-SHA256\n#{timestamp}\n#{credential_scope}\n#{hash(canonical_request)}"
hmac_sha("TC3" <> secret_key, date)
|> hmac_sha(service)
|> hmac_sha("tc3_request")
|> hmac_sha(string_to_sign)
|> Base.encode16(case: :lower)
end
@compile {:inline, hash: 1, hmac_sha: 2}
defp hash(data), do: :crypto.hash(:sha256, data) |> Base.encode16(case: :lower)
defp hmac_sha(key, data), do: :crypto.mac(:hmac, :sha256, key, data)
end