woof

package
v0.7.0 Latest Latest
Warning

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

Go to latest
Published: Aug 13, 2023 License: MIT Imports: 10 Imported by: 0

Documentation

Overview

Package woof provides serialization of Go values to be used in HTML documents.

As such, it also provides escaping and filter mechanisms closely related to the filters and escapers of Go's stdlib package html/template.

Terminology

A FILTER is a function that is given untrusted data for a specific content type.

If the function deems the data safe, it returns it as is.

If the data is deemed unsafe, the filter will replace the data or some of its parts with a safe replacement or delete unsafe parts, CHANGING OR FULLY REPLACING THE DATA to ensure safety.

An ESCAPER is a function that is given untrusted data for a specific content type and replaces unsafe parts with escape sequences, so that the data can be used in its content domain without unintended side effects.

Index

Constants

View Source
const UnsafeReplacement = "ZcorgiZ"

Variables

View Source
var AttrTypes = map[string]ContentType{
	"accept": ContentTypePlain,

	"action":  ContentTypeURL,
	"alt":     ContentTypePlain,
	"archive": ContentTypeURL,

	"autocomplete": ContentTypePlain,
	"autofocus":    ContentTypePlain,
	"autoplay":     ContentTypePlain,
	"background":   ContentTypeURL,
	"border":       ContentTypePlain,
	"checked":      ContentTypePlain,
	"cite":         ContentTypeURL,

	"class":    ContentTypePlain,
	"classid":  ContentTypeURL,
	"codebase": ContentTypeURL,
	"cols":     ContentTypePlain,
	"colspan":  ContentTypePlain,

	"contenteditable": ContentTypePlain,
	"contextmenu":     ContentTypePlain,
	"controls":        ContentTypePlain,
	"coords":          ContentTypePlain,

	"data":     ContentTypeURL,
	"datetime": ContentTypePlain,
	"default":  ContentTypePlain,

	"dir":       ContentTypePlain,
	"dirname":   ContentTypePlain,
	"disabled":  ContentTypePlain,
	"draggable": ContentTypePlain,
	"dropzone":  ContentTypePlain,

	"for": ContentTypePlain,

	"formaction": ContentTypeURL,

	"formtarget": ContentTypePlain,
	"headers":    ContentTypePlain,
	"height":     ContentTypePlain,
	"hidden":     ContentTypePlain,
	"high":       ContentTypePlain,
	"href":       ContentTypeURL,
	"hreflang":   ContentTypePlain,

	"icon":  ContentTypeURL,
	"id":    ContentTypePlain,
	"ismap": ContentTypePlain,

	"kind":  ContentTypePlain,
	"label": ContentTypePlain,
	"lang":  ContentTypePlain,

	"list":       ContentTypePlain,
	"longdesc":   ContentTypeURL,
	"loop":       ContentTypePlain,
	"low":        ContentTypePlain,
	"manifest":   ContentTypeURL,
	"max":        ContentTypePlain,
	"maxlength":  ContentTypePlain,
	"media":      ContentTypePlain,
	"mediagroup": ContentTypePlain,

	"min":      ContentTypePlain,
	"multiple": ContentTypePlain,
	"name":     ContentTypePlain,

	"open":    ContentTypePlain,
	"optimum": ContentTypePlain,

	"placeholder": ContentTypePlain,
	"poster":      ContentTypeURL,
	"profile":     ContentTypeURL,
	"preload":     ContentTypePlain,
	"pubdate":     ContentTypePlain,
	"radiogroup":  ContentTypePlain,
	"readonly":    ContentTypePlain,

	"required": ContentTypePlain,
	"reversed": ContentTypePlain,
	"rows":     ContentTypePlain,
	"rowspan":  ContentTypePlain,

	"spellcheck": ContentTypePlain,
	"scope":      ContentTypePlain,
	"scoped":     ContentTypePlain,
	"seamless":   ContentTypePlain,
	"selected":   ContentTypePlain,
	"shape":      ContentTypePlain,
	"size":       ContentTypePlain,
	"sizes":      ContentTypePlain,
	"span":       ContentTypePlain,
	"src":        ContentTypeURL,
	"srcdoc":     ContentTypeHTML,
	"srclang":    ContentTypePlain,
	"srcset":     ContentTypeSrcset,
	"start":      ContentTypePlain,
	"step":       ContentTypePlain,
	"style":      ContentTypeCSS,
	"tabindex":   ContentTypePlain,
	"target":     ContentTypePlain,
	"title":      ContentTypePlain,

	"usemap": ContentTypeURL,

	"width": ContentTypePlain,
	"wrap":  ContentTypePlain,
	"xmlns": ContentTypeURL,
}

AttrTypes describes the value of the given attribute. If an attribute affects (or can mask) the encoding or interpretation of other content, or affects the contents, idempotency, or credentials of a network message, then the value in this map is ContentTypeUnsafe. This map is derived from HTML5, specifically https://www.w3.org/TR/html5/Overview.html#attributes-1 as well as "%URI"-typed attributes from https://www.w3.org/TR/html4/index/attributes.html

Functions

func CanIndex

func CanIndex(val any, i any) bool

func IsZero

func IsZero(t any) bool

func Must

func Must[T ~string](ctx *Context, f func(val any) (T, error), val any) string

func MustContext

func MustContext[T ~string](ctx *Context, f func(vals ...any) (T, error), vals ...any) string

func Ptr

func Ptr[T any](t T) *T

func ResolveDefault

func ResolveDefault[T any](val *T, defaultVal T) T

func Stringify

func Stringify(val any) (string, error)

Stringify converts the passed value to a string.

It accepts values of type string, all ints, uints and floats, and fmt.Stringer. val may also be a pointer to any of the above types, or a type approximation, i.e. satisfy interface{ ~string }, interface{ ~int }, etc.

If val is nil or dereferences to nil, Stringify returns "".

If Stringify can't print a value, i.e. val is of an unsupported type, Stringify returns a pointer to an UnprintableValueError.

func Ternary

func Ternary[T any](cond bool, ifTrue, ifFalse T) T

func WriteAny

func WriteAny[T ~string](ctx *Context, escaper func(val any) (T, error), val any)

func WriteAnys

func WriteAnys[T ~string](ctx *Context, escaper func(vals ...any) (T, error), vals ...any)

func WriteAttr

func WriteAttr[T ~string](ctx *Context, name string, val any, escaper func(val any) (T, error))

WriteAttr is a utility for writing attributes, that correctly handles bool values.

If val is a bool and true, WriteAttr writes a space followed by name.

If val is a bool and false, WriteAttr writes nothing.

In any other case, WriteAttr writes a space, followed by the name, '="', and then the escaped attributes.

Types

type CSS

type CSS string

CSS encapsulates known safe content that matches any of:

  1. The CSS3 stylesheet production, such as `p { color: purple }`.
  2. The CSS3 rule production, such as `a[href=~"https:"].foo#bar`.
  3. CSS3 declaration productions, such as `color: red; margin: 2px`.
  4. The CSS3 value production, such as `rgba(0, 0, 255, 127)`.

See https://www.w3.org/TR/css3-syntax/#parsing and https://web.archive.org/web/20090211114933/http://w3.org/TR/css3-syntax#style

Use of this type presents a security risk: the encapsulated content should come from a trusted source, as it will be included verbatim in the template output.

func EscapeCSSValue

func EscapeCSSValue(val any) (CSS, error)

EscapeCSSValue escapes HTML and CSS special characters using \<hex>+ escapes.

The output is safe to use in HTML bodies and (possibly quote-wrapped) attributes without further HTML escaping.

func FilterCSSValue

func FilterCSSValue(val any) (CSS, error)

FilterCSSValue allows innocuous CSS values in the output including CSS quantities (10px or 25%), ID or class literals (#foo, .bar), keyword values (inherit, blue), and colors (#888). It filters out unsafe values, such as those that affect token boundaries, and anything that might execute scripts.

type ContentType

type ContentType uint8
const (
	ContentTypePlain ContentType = iota
	ContentTypeCSS
	ContentTypeHTML
	ContentTypeJS
	ContentTypeURL
	ContentTypeSrcset
)

func AttrType

func AttrType(name string) ContentType

AttrType returns a conservative (upper-bound on authority) guess at the type of the lowercase named attribute.

func (ContentType) String

func (t ContentType) String() string

type Context

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

func NewContext

func NewContext(w io.Writer) *Context

func (*Context) BufferClass

func (ctx *Context) BufferClass(class any)

func (*Context) BufferClassAttr

func (ctx *Context) BufferClassAttr(class HTMLAttrVal)

func (*Context) CloseStartTag

func (ctx *Context) CloseStartTag(extraClasses HTMLAttrVal, void bool)

CloseStartTag writes the buffered classes, if any, plus, optionally, the passed pre-escaped extra classes and closes the start tag.

If the tag has already been closed, CloseStartTag is a no-op.

func (*Context) Closed

func (ctx *Context) Closed()

Closed signals that an element tag has been closed.

func (*Context) InjectNonce

func (ctx *Context) InjectNonce()

func (*Context) Panic

func (ctx *Context) Panic(err error)

func (*Context) Recover

func (ctx *Context) Recover() error

func (*Context) SetScriptNonce

func (ctx *Context) SetScriptNonce(nonce any)

func (*Context) Unclosed

func (ctx *Context) Unclosed()

Unclosed signals that an element tag has been opened but not yet closed.

func (*Context) Write

func (ctx *Context) Write(s string)

func (*Context) WriteBytes

func (ctx *Context) WriteBytes(data []byte)

type HTMLAttrVal

type HTMLAttrVal string

HTMLAttrVal represents a known safe HTML attribute value fragment that can be placed between double-quotes to be used as part of an HTML attribute.

It must at least escape ["&].

Use of this type presents a security risk: the encapsulated content should come from a trusted source, as it will be included verbatim in the template output.

func EscapeHTMLAttrVal

func EscapeHTMLAttrVal(val any) (HTMLAttrVal, error)

EscapeHTMLAttrVal escapes s by replacing [&"] so that it can safely be placed between double quotes as an attribute value.

It does not perform further context specific escaping.

type HTMLBody

type HTMLBody string

HTMLBody represents a known safe n HTML fragment to be placed in the body of an element or the root of the document.

It should not be used for HTML from a third-party, or HTML with unclosed tags or comments and must escape at least [<&].

Use of this type presents a security risk: the encapsulated content should come from a trusted source, as it will be included verbatim in the template output.

func EscapeHTMLBody

func EscapeHTMLBody(val any) (HTMLBody, error)

EscapeHTMLBody replaces [&<] with escape sequences.

It should only be used to escape a tag body's content.

Since '>' is not escaped, previous start or end tags must be closed using a '>' to not cause unexpected side effects. This is the case for all escaped code generated by corgi and could only be a problem if user manually writes unclosed tags using unescaped assigns, which is discouraged by the corgi documentation.

type HTMLText

type HTMLText string

HTMLText represents an HTML fragment consisting purely of escaped text suitable to be placed both in the body of a tag (or the root of the document), and as an attribute value, possibly later enclosed in quotes.

This effectively makes HTMLText a mixture of HTMLBody and HTMLAttrVal.

As such, it must not contain any elements and must escape ["<&].

Corgi only considers HTMLText safe for "plain" attributes and won't, for example, allow the usage of a HTMLText, as an href.

Use of this type presents a security risk: the encapsulated content should come from a trusted source, as it will be included verbatim in the template output.

func EscapeHTML

func EscapeHTML(val any) (HTMLText, error)

EscapeHTML replaces [&'<>"] with escape sequences.

Usually, EscapeHTMLBody and [EscapeAttrVal] are more appropriate, as they have a smaller set of replacements, specific to their context.

This does not mean however, that content escaped with EscapeHTML, is not valid in HTML bodies or attributes (the opposite is true). Instead, EscapeHTML simply escapes more characters than required by those contexts.

type JS

type JS string

JS encapsulates a known safe EcmaScript5 Expression, for example, `(x + y * z())`. Template authors are responsible for ensuring that typed expressions do not break the intended precedence and that there is no statement/expression ambiguity as when passing an expression like "{ foo: bar() }\n['foo']()", which is both a valid Expression and a valid Program with a very different meaning.

Use of this type presents a security risk: the encapsulated content should come from a trusted source, as it will be included verbatim in the template output.

Using JS to include valid but untrusted JSON is not safe. A safe alternative is to parse the JSON with json.Unmarshal and then pass the resultant object into the template, where it will be converted to sanitized JSON when presented in a JavaScript context.

func JSify

func JSify(val any) (JS, error)

JSify converts the passed value to a JavaScript value.

It is safe to embed into HTML without further escaping.

type JSAttrVal

type JSAttrVal string

JSAttrVal is a js attribute safe to be embedded in double quotes and used as an attribute value.

Use of this type presents a security risk: the encapsulated content should come from a trusted source, as it will be included verbatim in the template output.

Using JS to include valid but untrusted JSON is not safe. A safe alternative is to parse the JSON with json.Unmarshal and then pass the resultant object into the template, where it will be converted to sanitized JSON when presented in a JavaScript context.

func EscapeJSAttrVal

func EscapeJSAttrVal(val any) (JSAttrVal, error)

type JSStr

type JSStr string

JSStr encapsulates a sequence of characters meant to be embedded between quotes in a JavaScript expression. The string must match a series of StringCharacters:

StringCharacter :: SourceCharacter but not `\` or LineTerminator
                 | EscapeSequence

Note that LineContinuations are not allowed. JSStr("foo\\nbar") is fine, but JSStr("foo\\\nbar") is not.

Use of this type presents a security risk: the encapsulated content should come from a trusted source, as it will be included verbatim in the template output.

type MapEntry

type MapEntry[K Ordered, V any] struct {
	K K
	V V
}

type MapSlice

type MapSlice[K Ordered, V any] []MapEntry[K, V]

func OrderedMap

func OrderedMap[K Ordered, V any, M ~map[K]V](m M) MapSlice[K, V]

func (MapSlice[K, V]) Len

func (m MapSlice[K, V]) Len() int

func (MapSlice[K, V]) Less

func (m MapSlice[K, V]) Less(i, j int) bool

func (MapSlice[K, V]) Swap

func (m MapSlice[K, V]) Swap(i, j int)

type Ordered

type Ordered interface {
	~int | ~int8 | ~int16 | ~int32 | ~int64 |
		~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 |
		~float32 | ~float64 |
		~string
}

type Srcset

type Srcset string

Srcset represents a known safe srcset attribute value, safe to be embedded between two double quotes and used as a srcset attribute or part of a srcset attribute.

Use of this type presents a security risk: the encapsulated content should come from a trusted source, as it will only be HTML escaped before including in template output.

func FilterSrcset

func FilterSrcset(vals ...any) (Srcset, error)

type URL

type URL string

URL represents a known safe URL or URL fragment.

Use of this type presents a security risk: the encapsulated content should come from a trusted source, as it will only be HTML escaped before including in template output.

func EscapeURL

func EscapeURL(vals ...any) (URL, error)

func FilterURL

func FilterURL(vals ...any) (URL, error)

func NormalizeURL

func NormalizeURL(u URL) URL

type UnprintableValueError

type UnprintableValueError struct {
	Val any
}

func (*UnprintableValueError) Error

func (err *UnprintableValueError) Error() string

Jump to

Keyboard shortcuts

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