Fresh repository history for elektrine/tarakan hosted at https://git.elektrine.com/elektrine/tarakan.
45 lines
1.3 KiB
Elixir
45 lines
1.3 KiB
Elixir
defmodule TarakanWeb.Plugs.ForwardedProto do
|
|
@moduledoc """
|
|
Rewrites `conn.scheme` from a trusted reverse proxy's `X-Forwarded-Proto`.
|
|
|
|
Only applies when:
|
|
|
|
1. `:trusted_proxies` is configured (CIDR strings or IPs), and
|
|
2. the direct TCP peer is inside that set.
|
|
|
|
Must run before `Plug.SSL`: behind a TLS-terminating proxy every request
|
|
arrives as plain HTTP, so `Plug.SSL` can only tell external HTTPS from HTTP
|
|
through this header - and the header is only meaningful from a peer we
|
|
trust. Untrusted peers keep the real scheme, so a direct client cannot
|
|
suppress the HTTPS redirect or HSTS by forging `X-Forwarded-Proto`.
|
|
"""
|
|
|
|
@behaviour Plug
|
|
|
|
import Plug.Conn
|
|
|
|
alias TarakanWeb.Plugs.ClientIp
|
|
|
|
@impl true
|
|
def init(opts), do: opts
|
|
|
|
@impl true
|
|
def call(conn, _opts) do
|
|
proxies = Application.get_env(:tarakan, :trusted_proxies, [])
|
|
|
|
if proxies != [] and ClientIp.trusted_ip?(conn.remote_ip, proxies) do
|
|
rewrite_scheme(conn)
|
|
else
|
|
conn
|
|
end
|
|
end
|
|
|
|
# Mirrors Plug.RewriteOn's :x_forwarded_proto semantics.
|
|
defp rewrite_scheme(conn) do
|
|
case get_req_header(conn, "x-forwarded-proto") do
|
|
["https" | _rest] -> %{conn | scheme: :https}
|
|
["http" | _rest] -> %{conn | scheme: :http}
|
|
_other -> conn
|
|
end
|
|
end
|
|
end
|