Documentation
¶
Overview ¶
Package epform is the form contract of an endpoint (#2176): a bound script that defines form_spec(req) and form_submit(req, values) is a form. A GET is answered with the spec form_spec returns, checked here and signed into a form token; a submission is checked against the spec its token carries (declared fields only, types, required fields, limits, the honeypot and the minimum fill time) before form_submit runs, and form_submit may add its own per-field errors or accept.
Index ¶
- Constants
- Variables
- func Check(spec Spec, issued time.Time, submitted map[string][]string, files []Upload, ...) (values map[string]any, errs map[string]string, err error)
- func Defines(file *syntax.File) bool
- func DefinesSource(source string) bool
- func EmbedKey(viewerKey []byte) []byte
- func Key(master []byte) []byte
- func OpenEmbed(key []byte, endpoint, token string, now time.Time) bool
- func Sign(key []byte, endpoint string, spec Spec, now time.Time) (string, error)
- func SignEmbed(key []byte, endpoint string, now time.Time) string
- func SignViewer(key []byte, endpoint string, v Viewer, now time.Time) (string, error)
- func ViewerKey(formKey []byte) []byte
- type Choice
- type Field
- type Spec
- type Upload
- type Viewer
Constants ¶
const ( // SpecName is called with the request on a GET and returns the spec. SpecName = scriptdialect.FormSpecName // SubmitName is called with the request and the checked values on a // submission, and returns None to accept or {"errors": {...}}. SubmitName = scriptdialect.FormSubmitName )
The functions a form script defines.
const ( // TokenField carries the form token the GET issued. TokenField = "form_token" // HoneypotField is rendered hidden from people; a value in it is a // program filling every field it finds, and the submission is refused. HoneypotField = "website" )
The fields a submission carries that are the platform's, not the form's.
const ( TypeText = "text" TypeLongText = "long_text" TypeEmail = "email" TypeNumber = "number" TypeDate = "date" TypeSingleChoice = "single_choice" TypeMultipleChoice = "multiple_choice" TypeCheckbox = "checkbox" TypeHidden = "hidden" // TypeFile takes files, saved as managed resources (#2333). TypeFile = "file" )
Field types.
const ( // DefaultMinFillSeconds is how long after its token was issued a form may // be submitted, unless the spec asks for longer. DefaultMinFillSeconds = 2 // DefaultTextLength and DefaultLongTextLength bound a text field that // names no max_length; MaxLength is the most any may name. DefaultTextLength = 1000 DefaultLongTextLength = 10000 MaxLength = 100000 )
Bounds of a spec.
const ( // DefaultMaxFiles is how many files a file field takes when it names no // max_files; MaxFiles is the most any may name. DefaultMaxFiles = 1 MaxFiles = 20 // DefaultMaxFileBytes bounds each file of a field that names no // max_bytes, below the deployment's upload ceiling when that is lower. DefaultMaxFileBytes int64 = 10 << 20 )
Bounds of a file field (#2333).
const ( FileKeyName = "name" FileKeyContentType = "content_type" FileKeySize = "size" FileKeyURI = "uri" FileKeyResourceID = "resource_id" )
The keys each file of a file field is described by: in form_submit's values, and in the stored submission, which adds where it was saved.
const EmbedLabel = "endpoint-form-embed-v1"
EmbedLabel domain-separates the embed marker key from the viewer token key it is derived from.
const EmbedParam = "form_embed"
EmbedParam is the query parameter a form's page is handed its embed marker in; the page does not pass it to the form.
const EmbedTTL = 12 * time.Hour
EmbedTTL is how long an embed marker is honored after the asset it was written into was served.
const KeyLabel = "endpoint-form-v1"
KeyLabel domain-separates the form token key from the key it is derived from.
const PagePrefix = "/forms/"
PagePrefix is the hosted form pages' prefix (#2331): a form's page is PagePrefix + its endpoint's name.
const TokenTTL = 24 * time.Hour
TokenTTL is how long a form may be submitted after it was shown.
const ViewerHeader = "X-Form-Viewer"
ViewerHeader carries a viewer token on a request to a form.
const ViewerLabel = "endpoint-form-viewer-v1"
ViewerLabel domain-separates the viewer token key from the form token key it is derived from.
const ViewerParam = "form_viewer"
ViewerParam is the query parameter a form's page is handed a viewer token in; the page sends it on as ViewerHeader and does not pass it to the form.
const ViewerTTL = 12 * time.Hour
ViewerTTL is how long a viewer token is honored after the asset it was written into was opened.
Variables ¶
var ErrRefused = errors.New("the submission was refused")
ErrRefused is a submission refused as a whole rather than field by field: its token is missing, altered, expired or another form's, the honeypot was filled, or it came back sooner than a person fills it in.
var Types = []string{ TypeText, TypeLongText, TypeEmail, TypeNumber, TypeDate, TypeSingleChoice, TypeMultipleChoice, TypeCheckbox, TypeHidden, TypeFile, }
Types is every field type, in the order they are documented.
Functions ¶
func Check ¶
func Check(spec Spec, issued time.Time, submitted map[string][]string, files []Upload, now time.Time) (values map[string]any, errs map[string]string, err error)
Check is a submission checked against spec, issued when its token was signed: the values form_submit is handed, by field, or the per-field errors, or ErrRefused when the honeypot was filled or the form came back sooner than a person fills it in. Every declared field is in values: an empty one is "" (a list for a multiple choice or a file field, False for a checkbox). A file field's value describes each of its files, in the order they were sent.
func Defines ¶
Defines reports whether file is a form script: it defines form_spec taking one parameter and form_submit taking two.
func DefinesSource ¶
DefinesSource is Defines over a source, false when it does not parse.
func EmbedKey ¶
EmbedKey is the embed marker key, derived from the viewer token key; nil when that is nil.
func Key ¶
Key is the form token key, derived from master (the bot check's challenge key, which every replica derives from the browser-session signing key), so a token one replica signs opens on another. Nil when master is nil: such a deployment answers no form.
func OpenEmbed ¶
OpenEmbed reports whether token is an embed marker signed with key for endpoint and not expired.
func SignEmbed ¶
SignEmbed is the embed marker for endpoint, honored until now plus EmbedTTL; "" without a key.
func SignViewer ¶
SignViewer is the viewer token for v on endpoint, honored until now plus ViewerTTL.
Types ¶
type Field ¶
type Field struct {
Name string `json:"name"`
Label string `json:"label,omitempty"`
Type string `json:"type"`
Required bool `json:"required,omitempty"`
// MaxLength bounds a text, long text or email field's characters.
MaxLength int `json:"max_length,omitempty"`
// Min and Max bound a number field.
Min *float64 `json:"min,omitempty"`
Max *float64 `json:"max,omitempty"`
// Help is shown under the field.
Help string `json:"help,omitempty"`
Choices []Choice `json:"choices,omitempty"`
// Sensitive is encrypted when the submission is stored (#2179): the
// form's source and its table hold ciphertext, and the plaintext is read
// only on the owner's submissions view and through platform.decrypt.
// form_submit is handed it as typed.
Sensitive bool `json:"sensitive,omitempty"`
// MaxFiles, MaxBytes and Accept bound a file field (#2333): how many
// files, how large each may be, and the content types it takes, judged
// from each file's bytes ("image/png", or "image/*" for a family; none
// takes any type).
MaxFiles int `json:"max_files,omitempty"`
MaxBytes int64 `json:"max_bytes,omitempty"`
Accept []string `json:"accept,omitempty"`
}
Field is one field of a form.
type Spec ¶
type Spec struct {
Fields []Field `json:"fields"`
// Prefill is each field's starting value; a hidden field's is the value a
// submission must carry back unchanged.
Prefill map[string]any `json:"prefill,omitempty"`
// Confirmation is shown once the form is accepted.
Confirmation string `json:"confirmation,omitempty"`
// Redirect is where the browser is sent once the form is accepted.
Redirect string `json:"redirect,omitempty"`
// MinFillSeconds is how long after it was shown the form may be
// submitted, at least DefaultMinFillSeconds.
MinFillSeconds int `json:"min_fill_seconds,omitempty"`
}
Spec is what form_spec returns: the fields, the values they start with, what a person is shown once the form is accepted, and where they are sent.
func Open ¶
Open is the spec a token carries and when it was issued, or ErrRefused with why: no token, one signed with another key or altered, one issued for another endpoint, or one past TokenTTL.
func (Spec) CheckUploads ¶
CheckUploads reports a file field whose max_bytes is past ceiling, the most a managed resource may hold on this deployment (resources.managed.max_upload_bytes).
type Upload ¶
Upload is one file a submission carries: the field it was sent in, the name the browser gave it, and its bytes.
func Read ¶
Read reads a submission body into each field's values and the files it carries: a urlencoded body and a JSON object alike, where a JSON number, boolean or array of them reads as the strings a urlencoded body would carry, and a multipart/form-data body, the one form a submission with files takes (#2333).
func (Upload) ContentType ¶
ContentType is the upload's type, judged from its bytes and never from the name or type the browser sent.
type Viewer ¶
type Viewer struct {
UserID string `json:"u"`
Email string `json:"m"`
AuthType string `json:"t,omitempty"`
Persona string `json:"p,omitempty"`
Admin bool `json:"a,omitempty"`
}
Viewer is who a signed-in person was when an asset embedding a form was opened for them (#2177). A form inside an asset is framed with the asset's sandbox, whose opaque origin carries no session, so the platform writes this, signed, into the form's address as it serves the asset, and an authenticated form takes it as the caller.