diff --git a/README.md b/README.md index a12841da..c22b15cc 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ If you wish to use instance roles to obtain AWS access keys you will need to add ```elixir def deps do [ - ex_aws: "~> 0.4.0", + ex_aws: "~> 0.4.2", poison: "~> 1.2.0", httpoison: "~> 0.7.0" ] diff --git a/lib/ex_aws/auth.ex b/lib/ex_aws/auth.ex index 858f9fec..a4d6a3fb 100644 --- a/lib/ex_aws/auth.ex +++ b/lib/ex_aws/auth.ex @@ -1,11 +1,10 @@ defmodule ExAws.Auth do import ExAws.Auth.Utils - alias Timex.DateFormat @moduledoc false def headers(http_method, url, service, config, headers, body) do - now = %{Timex.Date.now | ms: 0} + now = :os.timestamp |> :calendar.now_to_universal_time headers = [ {"host", URI.parse(url).host}, {"x-amz-date", amz_date(now)} | @@ -32,8 +31,8 @@ defmodule ExAws.Auth do end def handle_temp_credentials(headers, _), do: headers - def auth_header(access_key, secret_key, http_method, url, region, service, headers, body, now) do - date = DateFormat.format!(now, "%Y%m%d", :strftime) + def auth_header(access_key, secret_key, http_method, url, region, service, headers, body, {date, _} = now) do + date = date |> quasi_iso_format scope = "#{date}/#{region}/#{service}/aws4_request" signing_key = build_signing_key(secret_key, date, region, service) @@ -59,8 +58,8 @@ defmodule ExAws.Auth do end def build_string_to_sign(canonical_request, now, scope) do - timestamp = now |> ExAws.Auth.Utils.amz_date - hashed_canonical_request = ExAws.Auth.Utils.hash_sha256(canonical_request) + timestamp = now |> amz_date + hashed_canonical_request = hash_sha256(canonical_request) [ "AWS4-HMAC-SHA256", "\n", diff --git a/lib/ex_aws/auth/utils.ex b/lib/ex_aws/auth/utils.ex index 36d70227..95a1bec1 100644 --- a/lib/ex_aws/auth/utils.ex +++ b/lib/ex_aws/auth/utils.ex @@ -1,11 +1,4 @@ defmodule ExAws.Auth.Utils do - def amz_date(now) do - now - |> Timex.DateFormat.format!("{ISOz}") - |> String.replace("-", "") - |> String.replace(":", "") - end - def hash_sha256(data) do :sha256 |> :crypto.hash(data) @@ -29,4 +22,21 @@ defmodule ExAws.Auth.Utils do |> Atom.to_string |> String.upcase end + + def amz_date({date, time}) do + date = date |> quasi_iso_format + time = time |> quasi_iso_format + + [date, "T", time, "Z"] + |> IO.iodata_to_binary + end + + def quasi_iso_format({y, m, d}) do + [y, m, d] + |> Enum.map(&Integer.to_string/1) + |> Enum.map(&zero_pad/1) + end + + defp zero_pad(<<_>> = val), do: "0" <> val + defp zero_pad(val), do: val end diff --git a/lib/ex_aws/config/auth_cache.ex b/lib/ex_aws/config/auth_cache.ex index d0fe0746..36c42149 100644 --- a/lib/ex_aws/config/auth_cache.ex +++ b/lib/ex_aws/config/auth_cache.ex @@ -1,6 +1,10 @@ defmodule ExAws.Config.AuthCache do use GenServer + @moduledoc false + + # http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html + def start_link(opts \\ []) do GenServer.start_link(__MODULE__, :ok, opts) end @@ -37,9 +41,8 @@ defmodule ExAws.Config.AuthCache do end def refresh_in(expiration) do - expiration = Timex.DateFormat.parse!(expiration, "{ISOz}") - |> Timex.Date.convert(:secs) - time_to_expiration = expiration - Timex.Date.now(:secs) + expiration = expiration |> ExAws.Utils.iso_z_to_secs + time_to_expiration = expiration - ExAws.Utils.now_in_seconds refresh_in = time_to_expiration - 2 * 60 # check two min prior to expiration refresh_in * 1000 end diff --git a/lib/ex_aws/utils.ex b/lib/ex_aws/utils.ex index 8ece8e98..b2309566 100644 --- a/lib/ex_aws/utils.ex +++ b/lib/ex_aws/utils.ex @@ -47,4 +47,29 @@ defmodule ExAws.Utils do def upcase(value) when is_binary(value) do String.upcase(value) end + + @seconds_0_to_1970 :calendar.datetime_to_gregorian_seconds({{1970, 1, 1}, {0, 0, 0}}) + + def iso_z_to_secs(<>) do + <> = date + <> = time + year = year |> String.to_integer + mon = mon |> String.to_integer + day = day |> String.to_integer + hour = hour |> String.to_integer + min = min |> String.to_integer + sec = sec |> String.to_integer + + # Seriously? Gregorian seconds but not epoch seconds? + greg_secs = :calendar.datetime_to_gregorian_seconds({{year, mon, day}, {hour, min, sec}}) + greg_secs - @seconds_0_to_1970 + end + + def now_in_seconds do + greg_secs = :os.timestamp + |> :calendar.now_to_universal_time + |> :calendar.datetime_to_gregorian_seconds + + greg_secs - @seconds_0_to_1970 + end end diff --git a/mix.exs b/mix.exs index 1ca0619e..4ed2e76a 100644 --- a/mix.exs +++ b/mix.exs @@ -3,7 +3,7 @@ defmodule ExAws.Mixfile do def project do [app: :ex_aws, - version: "0.4.1", + version: "0.4.2", elixir: "~> 1.0", description: "AWS client. Currently supports Dynamo, Kinesis, Lambda, S3", name: "ExAws", @@ -14,20 +14,17 @@ defmodule ExAws.Mixfile do end def application do - [applications: [:logger, :timex, :crypto], + [applications: [:logger, :crypto], mod: {ExAws, []}] end defp deps do - [ - {:timex, "~> 0.13.4"}, - {:sweet_xml, "~> 0.2.1", only: [:dev, :test]} | - deps(:test_dev) - ] + deps(:test_dev) end defp deps(:test_dev) do [ + {:sweet_xml, "~> 0.2.1", only: [:dev, :test]}, {:earmark, "~> 0.1", only: :dev}, {:ex_doc, "~> 0.7", only: :dev}, {:sweet_xml, "~> 0.2.1", only: [:test]}, diff --git a/mix.lock b/mix.lock index a8118b2b..ffe3cd7d 100644 --- a/mix.lock +++ b/mix.lock @@ -9,5 +9,4 @@ "mixunit": {:hex, :mixunit, "0.9.2"}, "poison": {:hex, :poison, "1.2.1"}, "ssl_verify_hostname": {:hex, :ssl_verify_hostname, "1.0.5"}, - "sweet_xml": {:hex, :sweet_xml, "0.2.1"}, - "timex": {:hex, :timex, "0.13.4"}} + "sweet_xml": {:hex, :sweet_xml, "0.2.1"}} diff --git a/test/lib/ex_aws/auth/utils_test.exs b/test/lib/ex_aws/auth/utils_test.exs new file mode 100644 index 00000000..22582585 --- /dev/null +++ b/test/lib/ex_aws/auth/utils_test.exs @@ -0,0 +1,15 @@ +defmodule ExAws.Auth.UtilsTest do + use ExUnit.Case, async: true + import ExAws.Auth.Utils + + test "quasi_iso_date/1" do + assert quasi_iso_format({2015, 1, 2}) == ["2015", "01", "02"] + assert quasi_iso_format({2015, 11, 12}) == ["2015", "11", "12"] + end + + test "amz_date/1" do + assert amz_date({{2015, 1, 2}, {1, 3, 5}}) == "20150102T010305Z" + assert amz_date({{2015, 11, 22}, {11, 31, 51}}) == "20151122T113151Z" + end + +end diff --git a/test/lib/ex_aws/utils_test.exs b/test/lib/ex_aws/utils_test.exs index d74fd845..1532405b 100644 --- a/test/lib/ex_aws/utils_test.exs +++ b/test/lib/ex_aws/utils_test.exs @@ -24,4 +24,8 @@ defmodule ExAws.UtilsTest do assert %{"FooBar" => ["foo", "bar"]} == [foo_bar: ["foo", "bar"]] |> camelize_keys(deep: true) end + + test "iso_z_to_secs/1" do + assert iso_z_to_secs("2015-07-05T22:16:18Z") == 1436134578 + end end