tarakan/lib/tarakan_web/plugs/forwarded_proto.ex
Maxfield Luke af6077b9c3
All checks were successful
CI and deploy / Test (push) Successful in 4m52s
CI and deploy / Deploy production (push) Successful in 23s
Initial commit on Forgejo
Fresh repository history for elektrine/tarakan hosted at
https://git.elektrine.com/elektrine/tarakan.
2026-07-29 04:43:40 -04:00

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