defmodule GitGudWeb.PackageIconController do
@moduledoc """
A package's icon, for the packages pages.
The registry already serves the same bytes to F-Droid under
`/pkg/fdroid/…/icons/`, but that route authenticates with registry
tokens and knows nothing of a browser session — an `<img>` on a
private repository's page would get a 401. This gates on the
signed-in user instead, with the same per-format rule the catalog
lists packages by, so a card never shows a picture of something the
viewer couldn't fetch.
"""
use GitGudWeb, :controller
alias GitGud.Packages
alias GitGud.Packages.Package
alias GitGud.Repositories
def show(conn, %{"owner" => owner, "name" => name, "id" => id}) do
user = conn.assigns[:current_scope] && conn.assigns.current_scope.user
principal = if user, do: {:user, user, :all}, else: :anonymous
with {:ok, repo} <- fetch_repo(owner, name),
{id, ""} <- Integer.parse(id),
%Package{repository_id: rid} = package when rid == repo.id <-
GitGud.Repo.get(Package, id),
true <- Packages.Auth.authorize(principal, repo, :read, package.format),
{:ok, content_type, bytes, sha256} <- Packages.icon(package) do
etag = ~s("#{sha256}")
conn =
conn
|> put_resp_header("etag", etag)
# Private: whether it is visible depends on who is asking.
|> put_resp_header("cache-control", "private, max-age=300")
if etag in get_req_header(conn, "if-none-match") do
send_resp(conn, 304, "")
else
conn |> put_resp_content_type(content_type, nil) |> send_resp(200, bytes)
end
else
# Missing, forbidden and iconless look alike: an existence oracle
# for private packages is not what an <img> route is for.
_ -> conn |> put_status(:not_found) |> text("")
end
end
defp fetch_repo(owner, name) do
{:ok, Repositories.get_repository_by_path!(owner, name)}
rescue
Ecto.NoResultsError -> :error
end
end
neiam
/gitgud
Git Gud
public · Issues · Pulls · Labels · Forks · Compare · Actions success · Badges · Packages
⭐
1
Log in to mark this repository.
2.0 KiB · text
History
b868907