defmodule Desktop.Auth do
  @moduledoc """
    Auth provider that ensures that only the wanted WebView can open an interact
    with the application. A token is generated and compared to ensure no other application
    can connect to the local webserver.
  """

  import Plug.Conn
  alias Desktop.OS
  @behaviour Plug

  defp key() do
    # key should stay the same during application run,
    # but be different on each instance
    case :persistent_term.get({__MODULE__, :key}, nil) do
      nil ->
        key = :crypto.strong_rand_bytes(32)
        :persistent_term.put({__MODULE__, :key}, key)
        key

      key ->
        key
    end
  end

  def login_key() do
    Base.encode32(key(), padding: false)
  end

  def init([]), do: []

  def call(conn, _options \\ []) do
    conn = fetch_session(conn)

    case get_session(conn, :user) do
      nil -> require_auth(conn)
      true -> conn
    end
  end

  defp require_auth(conn) do
    conn = fetch_query_params(conn)

    if OS.mobile?() or Plug.Crypto.secure_compare(login_key(), conn.query_params["k"] || "") do
      put_session(conn, :user, true)
    else
      conn
      |> resp(401, "Unauthorized")
      |> halt()
    end
  end
end
