defmodule TarakanWeb.Plugs.ForwardedProtoTest do
  use ExUnit.Case, async: false

  import Plug.Conn
  import Plug.Test

  alias Tarakan.TrustedProxies
  alias TarakanWeb.Plugs.ForwardedProto

  setup do
    previous = Application.get_env(:tarakan, :trusted_proxies, [])

    on_exit(fn ->
      Application.put_env(:tarakan, :trusted_proxies, previous)
    end)

    :ok
  end

  test "rewrites the scheme when the peer is a trusted proxy" do
    Application.put_env(:tarakan, :trusted_proxies, TrustedProxies.parse("127.0.0.1,::1"))

    conn =
      conn(:get, "/")
      |> Map.put(:remote_ip, {127, 0, 0, 1})
      |> put_req_header("x-forwarded-proto", "https")
      |> ForwardedProto.call([])

    assert conn.scheme == :https

    conn =
      conn(:get, "/")
      |> Map.put(:remote_ip, {0, 0, 0, 0, 0, 0, 0, 1})
      |> Map.put(:scheme, :https)
      |> put_req_header("x-forwarded-proto", "http")
      |> ForwardedProto.call([])

    assert conn.scheme == :http
  end

  test "ignores X-Forwarded-Proto from untrusted peers" do
    Application.put_env(:tarakan, :trusted_proxies, TrustedProxies.parse("10.0.0.0/8"))

    conn =
      conn(:get, "/")
      |> Map.put(:remote_ip, {198, 51, 100, 1})
      |> put_req_header("x-forwarded-proto", "https")
      |> ForwardedProto.call([])

    assert conn.scheme == :http
  end

  test "ignores X-Forwarded-Proto without configured proxies" do
    Application.put_env(:tarakan, :trusted_proxies, [])

    conn =
      conn(:get, "/")
      |> Map.put(:remote_ip, {127, 0, 0, 1})
      |> put_req_header("x-forwarded-proto", "https")
      |> ForwardedProto.call([])

    assert conn.scheme == :http
  end

  test "leaves the scheme untouched without the header" do
    Application.put_env(:tarakan, :trusted_proxies, TrustedProxies.parse("127.0.0.1"))

    conn =
      conn(:get, "/")
      |> Map.put(:remote_ip, {127, 0, 0, 1})
      |> ForwardedProto.call([])

    assert conn.scheme == :http
  end
end
