Packages

A Plug to test the timestamp param against our own clock

Current section

Files

Jump to
plug_shopify_verify_timestamp lib plug_shopify_verify_timestamp.ex
Raw

lib/plug_shopify_verify_timestamp.ex

defmodule PlugShopifyVerifyTimestamp do
@moduledoc """
Validate the time difference supplied in URL Parameters by Shopify.
"""
import Plug.Conn
@spec init(any) :: any
def init(options), do: options
@spec call(Plug.Conn.t(), nonempty_list(max_delta: integer(), halt_on_error: boolean())) ::
Plug.Conn.t()
def call(
%{private: %{shop_origin_type: :url}} = conn,
[max_delta: max_delta, halt_on_error: halt?] = _opts
),
do:
conn
|> put_private(:psv_timestamp_now, DateTime.utc_now() |> DateTime.to_unix())
|> shopify_timestamp
|> delta
|> validation(max_delta)
|> PlugShopifyVerifyTimestamp.Helper.halt_on_error?(
halt?,
:psv_passed_timestamp_verification
)
def call(conn, _), do: conn
@spec shopify_timestamp(Plug.Conn.t()) :: Plug.Conn.t()
def shopify_timestamp(conn) do
timestamp =
conn |> PlugShopifyVerifyTimestamp.Helper.get_param_from_url("timestamp") |> ensure_integer
put_private(conn, :psv_timestamp_shopify, timestamp)
end
defp ensure_integer(value) when is_binary(value) do
value |> String.to_integer()
end
defp ensure_integer(value) when is_nil(value) do
0
end
@spec delta(Plug.Conn.t()) :: Plug.Conn.t()
def delta(conn) do
now = conn.private[:psv_timestamp_now] |> DateTime.from_unix!()
sent = conn.private[:psv_timestamp_shopify] |> DateTime.from_unix!()
put_private(conn, :psv_timestamp_delta, DateTime.diff(now, sent))
end
@spec validation(Plug.Conn.t(), integer()) :: Plug.Conn.t()
def validation(%{private: %{psv_timestamp_delta: delta}} = conn, max_delta)
when not (delta >= max_delta),
do: conn |> put_private(:psv_passed_timestamp_verification, true)
def validation(conn, _),
do: conn |> put_private(:psv_passed_timestamp_verification, false)
end