Initial commit on Forgejo
Fresh repository history for elektrine/tarakan hosted at https://git.elektrine.com/elektrine/tarakan.
This commit is contained in:
commit
af6077b9c3
455 changed files with 78366 additions and 0 deletions
75
lib/tarakan_web/controllers/badge_controller.ex
Normal file
75
lib/tarakan_web/controllers/badge_controller.ex
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
defmodule TarakanWeb.BadgeController do
|
||||
@moduledoc """
|
||||
Embeddable SVG badges for a repository's security posture.
|
||||
|
||||
Served without authentication so a README on any host can render one, and
|
||||
cached briefly so an embedded badge cannot be used to hammer the database.
|
||||
The SVG is self-contained (no external fonts or images) because most hosts
|
||||
proxy and sanitize badge images.
|
||||
"""
|
||||
|
||||
use TarakanWeb, :controller
|
||||
|
||||
alias Tarakan.Repositories
|
||||
alias Tarakan.SecurityPosture
|
||||
|
||||
@cache_seconds 900
|
||||
|
||||
def show(conn, %{"host" => host, "owner" => owner, "name" => name}) do
|
||||
render_badge(conn, Repositories.get_repository(host, owner, name))
|
||||
end
|
||||
|
||||
def show(conn, %{"owner" => owner, "name" => name}) do
|
||||
render_badge(conn, Repositories.get_repository_by_slug(owner, name))
|
||||
end
|
||||
|
||||
defp render_badge(conn, repository) do
|
||||
badge =
|
||||
case repository do
|
||||
%{listing_status: "listed"} = repository ->
|
||||
SecurityPosture.cached_badge(repository)
|
||||
|
||||
_unlisted_or_missing ->
|
||||
%{label: "security", message: "not listed", color: "#5a6a72"}
|
||||
end
|
||||
|
||||
conn
|
||||
|> put_resp_content_type("image/svg+xml")
|
||||
|> put_resp_header("cache-control", "public, max-age=#{@cache_seconds}")
|
||||
|> send_resp(200, svg(badge))
|
||||
end
|
||||
|
||||
# Flat two-part badge. Widths are estimated from character count because the
|
||||
# SVG carries no font metrics; 6.6px per character matches the 11px
|
||||
# sans-serif stack closely enough for the shape to stay tight.
|
||||
defp svg(%{label: label, message: message, color: color}) do
|
||||
label_width = text_width(label)
|
||||
message_width = text_width(message)
|
||||
total = label_width + message_width
|
||||
|
||||
"""
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="#{total}" height="20" role="img" aria-label="#{escape(label)}: #{escape(message)}">
|
||||
<title>#{escape(label)}: #{escape(message)}</title>
|
||||
<g shape-rendering="crispEdges">
|
||||
<rect width="#{label_width}" height="20" fill="#1c1f22"/>
|
||||
<rect x="#{label_width}" width="#{message_width}" height="20" fill="#{escape(color)}"/>
|
||||
</g>
|
||||
<g fill="#fff" text-anchor="middle" font-family="Verdana,DejaVu Sans,Geneva,sans-serif" font-size="11">
|
||||
<text x="#{div(label_width, 2)}" y="14">#{escape(label)}</text>
|
||||
<text x="#{label_width + div(message_width, 2)}" y="14">#{escape(message)}</text>
|
||||
</g>
|
||||
</svg>
|
||||
"""
|
||||
end
|
||||
|
||||
defp text_width(text), do: round(String.length(text) * 6.6) + 12
|
||||
|
||||
defp escape(value) do
|
||||
value
|
||||
|> to_string()
|
||||
|> String.replace("&", "&")
|
||||
|> String.replace("<", "<")
|
||||
|> String.replace(">", ">")
|
||||
|> String.replace("\"", """)
|
||||
end
|
||||
end
|
||||
Loading…
Add table
Add a link
Reference in a new issue