diff --git a/lib/plug/crypto.ex b/lib/plug/crypto.ex index 682ec05..6208fe5 100644 --- a/lib/plug/crypto.ex +++ b/lib/plug/crypto.ex @@ -333,10 +333,9 @@ defmodule Plug.Crypto do %{data: data, signed: signed} -> {data, signed, 86400} end - if expired?(signed, Keyword.get(opts, :max_age, max_age)) do - {:error, :expired} - else - {:ok, data} + case validate_age(signed, Keyword.get(opts, :max_age, max_age)) do + :ok -> {:ok, data} + error -> error end end @@ -351,9 +350,18 @@ defmodule Plug.Crypto do KeyGenerator.generate(secret_key_base, salt, iterations, length, digest, cache) end - defp expired?(_signed, :infinity), do: false - defp expired?(_signed, max_age_secs) when max_age_secs <= 0, do: true - defp expired?(signed, max_age_secs), do: signed + trunc(max_age_secs * 1000) < now_ms() + defp validate_age(_signed, :infinity), do: :ok + defp validate_age(_signed, max_age_secs) when max_age_secs <= 0, do: {:error, :expired} + + defp validate_age(signed, max_age_secs) do + now = now_ms() + + cond do + signed > now -> {:error, :invalid} + signed + trunc(max_age_secs * 1000) < now -> {:error, :expired} + true -> :ok + end + end defp now_ms, do: System.os_time(:millisecond) end diff --git a/test/plug/crypto_test.exs b/test/plug/crypto_test.exs index 95d2bf5..1811ca1 100644 --- a/test/plug/crypto_test.exs +++ b/test/plug/crypto_test.exs @@ -200,6 +200,11 @@ defmodule Plug.CryptoTest do {:error, :expired} end + test "ensures signed_at is not in future while decrypting" do + token = encrypt(@key, "secret", 1, signed_at: System.os_time(:second) + 31_536_000) + assert {:error, :invalid} = decrypt(@key, "secret", token) + end + test "passes key_iterations options to key generator" do signed1 = encrypt(@key, "secret", 1, signed_at: 0, key_iterations: 1) signed2 = encrypt(@key, "secret", 1, signed_at: 0, key_iterations: 2)