88 lines
2.4 KiB
Elixir
88 lines
2.4 KiB
Elixir
defmodule ToweropsWeb.Plugs.DetectEUUser do
|
|
@moduledoc """
|
|
Detects if a user is from an EU/EEA country that requires GDPR cookie consent.
|
|
|
|
Uses local GeoIP database to determine the user's country from their IP address.
|
|
|
|
The result is stored in conn.assigns.requires_cookie_consent
|
|
"""
|
|
import Plug.Conn
|
|
|
|
# EU/EEA country codes that require GDPR cookie consent
|
|
# EU member states + EEA countries (Norway, Iceland, Liechtenstein)
|
|
@eu_eea_countries ~w(
|
|
AT BE BG HR CY CZ DK EE FI FR DE GR HU IE IT LV LT LU MT NL PL PT RO SK SI ES SE
|
|
IS NO LI
|
|
)
|
|
|
|
# British overseas territories and Crown dependencies also covered by GDPR
|
|
@uk_territories ~w(
|
|
GB GG JE IM GI
|
|
)
|
|
|
|
@doc false
|
|
def init(opts), do: opts
|
|
|
|
@doc false
|
|
def call(conn, _opts) do
|
|
require Logger
|
|
|
|
requires_consent = detect_eu_user(conn)
|
|
|
|
# Store in process dictionary so layouts can access it
|
|
Process.put(:requires_cookie_consent, requires_consent)
|
|
|
|
conn
|
|
|> put_session(:requires_cookie_consent, requires_consent)
|
|
|> assign(:requires_cookie_consent, requires_consent)
|
|
end
|
|
|
|
defp detect_eu_user(conn) do
|
|
# In development (localhost), always show the banner for testing
|
|
hostname = conn.host
|
|
|
|
if hostname in ["localhost", "127.0.0.1"] do
|
|
true
|
|
else
|
|
detect_country_from_headers(conn)
|
|
end
|
|
end
|
|
|
|
defp detect_country_from_headers(conn) do
|
|
# Get remote IP from connection
|
|
remote_ip = get_remote_ip(conn)
|
|
|
|
case Towerops.GeoIP.lookup(remote_ip) do
|
|
country_code when is_binary(country_code) ->
|
|
eu_country?(country_code)
|
|
|
|
nil ->
|
|
# No country found - default to showing banner (conservative approach)
|
|
true
|
|
end
|
|
end
|
|
|
|
defp get_remote_ip(conn) do
|
|
# Check X-Forwarded-For header first (if behind proxy/load balancer)
|
|
case get_req_header(conn, "x-forwarded-for") do
|
|
[forwarded] ->
|
|
# X-Forwarded-For can contain multiple IPs, take the first (client IP)
|
|
forwarded
|
|
|> String.split(",")
|
|
|> List.first()
|
|
|> String.trim()
|
|
|
|
_ ->
|
|
# Fall back to direct connection IP
|
|
case conn.remote_ip do
|
|
{a, b, c, d} -> "#{a}.#{b}.#{c}.#{d}"
|
|
_ -> "0.0.0.0"
|
|
end
|
|
end
|
|
end
|
|
|
|
defp eu_country?(country_code) do
|
|
country_code = String.upcase(country_code)
|
|
country_code in @eu_eea_countries or country_code in @uk_territories
|
|
end
|
|
end
|