Help us shape the future of Go! Take the 2026 Go Developer Survey

brandimage

package
v0.21.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 29, 2026 License: AGPL-3.0 Imports: 5 Imported by: 0

Documentation

Overview

Package brandimage is the one place that decides what counts as a brand mark: which formats Atlas accepts, whether a body really is one, and under what headers it is handed back to a browser.

There is more than one mark in an installation. ADR-0148 gave the instance its own — the operator's, shown on the sign-in screen and in the console. The portal added a second kind: a catalogue's, shown to the customer group that catalogue is for (ADR-0316). They are stored in different places and gated by different rules, and that is as it should be.

What must not differ is the check. An uploaded image is attacker-influenced content that this server persists and later serves to every browser that opens the page; the validation on the way in and the headers on the way out are the whole of the mitigation. Two copies of that pair is one copy that a future hardening will miss — so both marks read it from here, and a third will too.

It is deliberately a gate rather than a sanitiser. An SVG is a document format with scripting in it, and no byte-level inspection makes one safe; what makes it safe is Serve's response — nosniff pins the declared type, and a `default-src 'none'; sandbox` policy neutralises script even when the image is opened as a top-level document, which is the only context where an SVG's script would run at all (an <img> never runs it).

Index

Constants

This section is empty.

Variables

View Source
var Mark = newSet(map[string]string{"image/png": "png", "image/svg+xml": "svg"})

Mark is what a brand mark may be: a raster PNG or a vector SVG. An instance's mark and a catalogue's are both marks, and both take this set.

View Source
var Photo = newSet(map[string]string{"image/png": "png", "image/jpeg": "jpg"})

Photo is what a picture of a person may be: PNG or JPEG.

**Deliberately not SVG**, and that is the one place the two sets differ in kind rather than in taste. An SVG is a document with scripting in it; Serve makes one inert, but a mark has a reason to be a vector — it is drawn, it is scaled, a designer delivers one — and a photograph does not. A picture of a person arrives from a camera or from a directory, and both give raster bytes. Accepting a format nothing needs, in the one place where the uploader is every account rather than an administrator, is widening the surface for nothing.

JPEG is here because that is what Microsoft Graph answers with for a user's photo. A set that refused it would have made the directory path impossible and said nothing about why.

View Source
var Picture = newSet(map[string]string{
	"image/png": "png", "image/jpeg": "jpg", "image/svg+xml": "svg",
})

Picture is what a product in the catalogue may be shown as: a photograph or a vendor's mark, so PNG, JPEG **and** SVG.

It is the union of the two sets above, and the reason is who uploads it. Photo refuses SVG because a picture of a person arrives from a camera and the uploader there is every account; a product picture arrives from whoever maintains the catalogue — a product manager, the same kind of privileged author who sets a catalogue's mark — and half of what they have is a vector, because half of what a service catalogue sells is software with a logo rather than a thing with a photograph. A set that refused SVG would be answered by converting the logo to a raster, badly, once per product.

What makes that safe is Serve and nothing else: the bytes are validated as the type they claim, served under a sandbox policy with no script origin, and never inlined into a page.

Functions

func NormalizeType

func NormalizeType(h string) string

NormalizeType canonicalises an upload's Content-Type to a bare, lowercase media type, dropping any parameters (e.g. "image/svg+xml; charset=utf-8").

func Serve

func Serve(w http.ResponseWriter, contentType string, data []byte)

Serve writes a stored mark as the response, under the headers that make a hostile SVG inert. Callers have already decided who may see it; this decides only how it travels.

func Valid

func Valid(contentType string, data []byte) bool

Valid reports whether the bytes look like the media type they were declared as: the PNG or JPEG magic for a raster image, well-formed UTF-8 containing an "<svg" root for a vector one. An unknown type is never valid.

It answers for every Set, and knowing a type here does not make a surface take it — the surface's own set decides that, and asks this only about what it already accepts.

Types

type Set

type Set struct {
	// contains filtered or unexported fields
}

A Set is what one upload surface accepts: which media types, and the extension each is stored under.

There is a set per surface and one Valid for all of them, and the split is the point. Whether bytes really are the type they claim is a security question with one answer everywhere — two copies of it is one copy a future hardening will miss. *Which* types a surface accepts is a different question, and the surfaces genuinely differ: see Mark and Photo.

func (Set) ExtFor

func (s Set) ExtFor(contentType string) (string, bool)

ExtFor is the extension an accepted upload is stored under; ok is false for a type this surface does not take, which makes it the acceptance test as well.

func (Set) Exts

func (s Set) Exts() []string

Exts is the stored extensions, in a fixed order.

func (Set) TypeFor

func (s Set) TypeFor(ext string) (string, bool)

TypeFor is the media type a stored extension is reported as.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL