analytics/lib/plausible_web/controllers/avatar_controller.ex

39 lines
1.5 KiB
Elixir
Raw Normal View History

defmodule PlausibleWeb.AvatarController do
@moduledoc """
This module proxies requests to BASE_URL/avatar/:hash to www.gravatar.com/avatar/:hash.
The purpose is to make use of Gravatar's convenient avatar service without exposing information
that could be used for tracking the Plausible user. Compared to requesting the Gravatar directly
from the browser, this proxy module protects the Plausible user from disclosing to Gravatar:
1. The client IP address
2. User-Agent
3. Referer header which can be used to track which site the user is visiting (i.e. plausible.io or self-hosted URL)
The downside is the added latency from the request having to go through the Plausible server, rather than contacting the
local CDN server operated by Gravatar's service.
"""
use PlausibleWeb, :controller
alias Plausible.HTTPClient
@gravatar_base_url "https://www.gravatar.com"
def avatar(conn, params) do
url = Path.join(@gravatar_base_url, ["avatar/", params["hash"]]) <> "?s=150&d=identicon"
case HTTPClient.impl().get(url) do
{:ok, %Finch.Response{status: 200, body: body, headers: headers}} ->
conn
|> forward_headers(headers)
|> send_resp(200, body)
{:error, _} ->
send_resp(conn, 400, "")
end
end
@forwarded_headers ["content-type", "cache-control", "expires"]
defp forward_headers(conn, headers) do
headers_to_forward = Enum.filter(headers, fn {k, _} -> k in @forwarded_headers end)
%Plug.Conn{conn | resp_headers: headers_to_forward}
end
end