upload

package
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: Jun 8, 2026 License: MIT Imports: 12 Imported by: 0

Documentation

Overview

Package upload is part of the GoFastr framework. See https://github.com/DonaldMurillo/gofastr for documentation.

Index

Constants

View Source
const MaxFilenameBytes = 255

MaxFilenameBytes caps the sanitised filename length. A user-supplied filename has no legitimate reason to exceed a few hundred bytes; the cap protects log lines, filesystem APIs, and database columns from pathological inputs.

View Source
const SanitizeFilenameInputBound = 4 * MaxFilenameBytes

SanitizeFilenameInputBound caps the *input* length before any of the O(n) sanitisation passes (control-byte strip, replacer, interior-ext split-and-join) run. A multipart Content-Disposition filename is a MIME-header value and is NOT counted against ParseMultipartForm's maxMemory, so without this guard an attacker can ship a multi-MiB filename (bounded only by the stdlib's 10 MiB per-header cap) that amplifies into tens of MB of transient allocation and >100ms of CPU per request — strings.Split on a ~9 MiB all-dots name produces a ~9.4M-element slice. The bound is a generous multiple of MaxFilenameBytes so legitimate names with escaped / multibyte sequences survive untouched; the final MaxFilenameBytes cap still applies after sanitisation.

Variables

View Source
var ErrNotFound = errNotFound{}

ErrNotFound is wrapped by Get when the requested key doesn't exist. Callers can match on this or on errors.Is(err, os.ErrNotExist) — the returned error wraps both so existing code continues to work.

Functions

func Handler

func Handler(cfg Config) http.HandlerFunc

Handler returns an http.HandlerFunc that processes multipart file uploads. It expects a single file in the "file" form field. On success it responds with 200 and JSON Metadata.

func SanitizeFilename

func SanitizeFilename(name string) string

SanitizeFilename removes path separators, null bytes, and other dangerous characters from a filename to prevent path traversal attacks. It also neutralises double-extension smuggling — e.g. `shell.php.jpg` becomes `shell_php.jpg` — so a misconfigured web server can't be tricked into executing a hidden interior extension.

Control bytes (CR, LF, TAB, anything < 0x20) are dropped so a logged filename can't escape its log line via injected newlines or terminal control sequences. The final result is truncated to MaxFilenameBytes (preserving the extension) so an attacker can't ship a 10 MB filename.

func ValidateExt

func ValidateExt(filename string, allowed []string) error

ValidateExt checks that the file extension is in the allowed list. Extensions are compared case-insensitively without the leading dot. If allowed is empty, all extensions are permitted.

func ValidateMIME

func ValidateMIME(file io.ReadSeeker, allowed []string) error

ValidateMIME reads the first 512 bytes from file to detect MIME type, checks it against the allowed list, then resets the reader. If allowed is empty, all MIME types are permitted.

func ValidateSize

func ValidateSize(size int64, max int64) error

ValidateSize checks that the file size does not exceed max. A max of 0 means no limit.

Types

type Config

type Config struct {
	MaxSize      int64    // Maximum file size in bytes (0 = no limit)
	AllowedTypes []string // MIME type whitelist (empty = allow all)
	AllowedExts  []string // Extension whitelist (empty = allow all)
	Storage      Storage  // Storage backend implementation
}

Config holds configuration for the upload handler.

type LocalStorage

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

LocalStorage implements Storage using the local filesystem.

func NewLocalStorage

func NewLocalStorage(baseDir string) *LocalStorage

NewLocalStorage creates a LocalStorage that saves files under baseDir.

func (*LocalStorage) Delete

func (s *LocalStorage) Delete(_ context.Context, key string) error

Delete removes the file at key from the local filesystem.

func (*LocalStorage) Exists

func (s *LocalStorage) Exists(_ context.Context, key string) (bool, error)

Exists checks whether a file at key exists in the local filesystem.

func (*LocalStorage) Get

func (s *LocalStorage) Get(_ context.Context, key string) (io.ReadCloser, error)

Get opens the file at key from the local filesystem for reading.

Returns ErrNotFound (wrapping os.ErrNotExist) when the key is missing — callers can match on os.ErrNotExist or upload.ErrNotFound without parsing the message. Other errors are returned with the absolute filesystem path stripped, so a 500 propagated to an end user doesn't disclose where the data lives.

func (*LocalStorage) Save

func (s *LocalStorage) Save(_ context.Context, key string, r io.Reader) error

Save writes the file to the local filesystem under baseDir/key. It creates subdirectories as needed.

type Metadata

type Metadata struct {
	OriginalName string    `json:"original_name"`
	Size         int64     `json:"size"`
	MimeType     string    `json:"mime_type"`
	UploadedAt   time.Time `json:"uploaded_at"`
	Key          string    `json:"key"`
}

Metadata holds information about an uploaded file.

type Storage

type Storage interface {
	Save(ctx context.Context, key string, r io.Reader) error
	Delete(ctx context.Context, key string) error
	Get(ctx context.Context, key string) (io.ReadCloser, error)
	Exists(ctx context.Context, key string) (bool, error)
}

Storage defines the interface for file storage backends.

Jump to

Keyboard shortcuts

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