isl

package module
v1.1.3 Latest Latest
Warning

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

Go to latest
Published: Apr 18, 2025 License: MIT Imports: 10 Imported by: 0

README

goisl: Go Input Sanitization Library


Go Reference Release Build Status Go Report Card


Overview

goisl (Go Input Sanitization Library) is a lightweight, secure, and developer-friendly Go package designed to simplify input sanitization and safe output escaping. It supports three core use cases:

  1. Built-in Sanitization & Escaping: Quickly sanitize and escape common input types including email addresses, file names, URLs, and HTML for safe use in CLI tools, APIs, or web templates.
  2. Custom Format Overrides: Use hookable functions or wrappers to validate and clean highly specific input formats such as crypto addresses, UUIDs, IP ranges, Twitter handles, and vendor-specific API keys.
  3. CLI Integration with pflag: Seamlessly bind sanitized values to command-line flags using BindSanitizedFlag and BindSanitizedTextFlag, with panic-safe variants for required inputs.

Inspired by WordPress’s input-handling philosophy, goisl encourages a “sanitize on input, escape on output” model with modular, testable, and override-ready functions.

By using goisl, you can reduce the risk of malformed input, injection attacks, and XSS vulnerabilities while maintaining clean, consistent input handling across your Go applications.


Platform Support

goisl is tested and verified on multiple platforms and architectures, including:

  • 🐧 Ubuntu 20.04, 22.04, and 24.04 LTS
  • 🐳 Debian (Bullseye, Bookworm), CentOS Stream 9, Fedora, OS X
  • 💻 AMD64, ARM64 (e.g., Raspberry Pi), Intel, and Apple Silicon
Minimum Go Version

The minimum supported Go version is:

Go 1.18

This version is chosen based on the default Go release installed on the oldest supported Ubuntu LTS version at the time of release. Future goisl releases will follow this standard to ensure wide compatibility across cloud, desktop, and server environments.


Features

Core Functions
  • Sanitization:

    • SanitizeEmail: Validate and sanitize email addresses with optional hooks.
    • SanitizeFileName: Clean and normalize filenames while enforcing safe character sets.
    • SanitizeURL: Validate and escape user-supplied URLs.
    • HTMLSanitize: Strip unsafe tags from HTML strings.
  • Escaping:

    • EscapePlainText: Strip unsafe characters from plain text input (e.g., names, labels).
    • EscapeURL: Sanitize URLs and encode query parameters.
    • SafeEscapeHTML: Escape characters for safe HTML display (excluding %).

New in v1.1.X

  • 🧩 SanitizeXBasic helpers: Simple wrappers with default rules and no hooks.
  • 🚨 MustSanitizeXBasic: Panic-on-failure versions for CLI defaults or enforced logic.
  • BindSanitizedFlag and BindSanitizedTextFlag: Bind input flags with automatic sanitization via pflag.
  • 🧪 90.4% unit test coverage and 16 custom hook example cases tested on 6 OS platforms.
  • 🌟 Dozens of real-world override examples (API keys, crypto, social handles, and more).

Installation

go get github.com/derickschaefer/goisl
## Installation

Install the library by importing it and using `go mod tidy`:

```bash
go get github.com/derickschaefer/goisl

Usage

Email Sanitization
package main

import (
    "fmt"
    "github.com/derickschaefer/goisl"
)

func main() {
    email, err := isl.SanitizeEmail(" user@example.com ", nil)
    if err != nil {
        fmt.Println("Error:", err)
    } else {
        fmt.Println("Sanitized Email:", email)
    }
}
URL Escaping
package main

import (
    "fmt"
    "github.com/derickschaefer/goisl"
)

func main() {
    url, err := isl.EscapeURL("  http://example.com/path?query=<script>  ", "display", nil)
    if err != nil {
        fmt.Println("Error:", err)
    } else {
        fmt.Println("Escaped URL:", url)
    }
}
File Name Sanitization
package main

import (
    "fmt"
    "github.com/derickschaefer/goisl"
)

func main() {
    fileName, err := isl.SanitizeFileName("example#@!.txt", nil)
    if err != nil {
        fmt.Println("Error:", err)
    } else {
        fmt.Println("Sanitized File Name:", fileName)
    }
}
CLI Integration with pflag
package main

import (
    "fmt"
    "github.com/derickschaefer/goisl"
    "github.com/spf13/pflag"
)

func main() {
    emailFlag := isl.BindSanitizedFlag("email", "", "Email address", isl.SanitizeEmailBasic)
    urlFlag := isl.BindSanitizedFlag("url", "", "URL to sanitize", isl.SanitizeURLBasic)
    commentFlag := isl.BindSanitizedTextFlag("comment", "", "Plain text comment", nil)

    pflag.Parse()

    fmt.Println("✅ Email:", emailFlag.MustGet())
    fmt.Println("✅ URL:", urlFlag.MustGet())
    fmt.Println("✅ Comment:", commentFlag.MustGet())
}
Custom hook to block disposable email domains
package main

import (
    "errors"
    "fmt"
    "strings"

    "github.com/derickschaefer/goisl"
)

func main() {
    // Define a hook that strips email tags and blocks disposable domains
    customHook := func(local, domain string) (string, string, error) {
        // Remove anything after a '+' (e.g., user+tag@example.com → user@example.com)
        if plus := strings.Index(local, "+"); plus != -1 {
            local = local[:plus]
        }

        // Block disposable email domains
        blocked := []string{"tempmail.com", "mailinator.com"}
        domainLower := strings.ToLower(domain)
        for _, b := range blocked {
            if domainLower == b {
                return "", "", errors.New("disposable email domain not allowed")
            }
        }

        return local, domain, nil
    }

    input := "User+promo@tempmail.com"
    sanitized, err := isl.SanitizeEmail(input, customHook)
    if err != nil {
        fmt.Println("❌ Error:", err)
    } else {
        fmt.Println("✅ Sanitized:", sanitized)
    }
}
Custom hook to block known URL shortners
package main

import (
    "errors"
    "fmt"
    "net/url"
    "strings"

    "github.com/derickschaefer/goisl"
)

func main() {
    // Hook that blocks bit.ly and other known shorteners
    blockShorteners := func(parsed *url.URL) (*url.URL, error) {
        shorteners := []string{"bit.ly", "tinyurl.com", "t.co"}

        host := strings.ToLower(parsed.Host)
        for _, s := range shorteners {
            if host == s {
                return nil, errors.New("URL shorteners are not allowed")
            }
        }
        return parsed, nil
    }

    input := "https://bit.ly/3xyzABC"
    result, err := isl.EscapeURL(input, "display", blockShorteners)
    if err != nil {
        fmt.Println("❌ Error:", err)
    } else {
        fmt.Println("✅ Escaped URL:", result)
    }
}

🧪 Want more?
Explore real-world format hooks (e.g., UUIDs, API keys, Twitter handles) in the
👉 examples/README.md

Contributing

Contributions are welcome! Please: 1. Fork the repository. (not preferred but permissible) 2. Submit a pull request with a detailed description of the changes. 3. Please share custom hook examples to grow that repository.

This project is licensed under the MIT License. See the LICENSE file for details.

Documentation

Overview

Package isl provides a Go Input Sanitization Library (goisl).

goisl is inspired by WordPress's escaping and sanitization system and is designed to help developers securely process user input by providing modular, testable sanitization and escaping functions for common use cases like emails, file names, URLs, and HTML. Custom hooks are supported to support just about any sanitization scenario imagineable.

See README.md for examples and usage.

Index

Constants

View Source
const (
	MaxFileNameLength = 255
)

Constants for sanitization

Variables

View Source
var AllowedHTML = map[string][]string{
	"b":   nil,
	"a":   {"href"},
	"img": {"src", "alt"},
}

AllowedHTML defines allowed tags and their permitted attributes.

View Source
var EscapeAllowedProtocols = []string{"http", "https", "mailto", "ftp"}

EscapeAllowedProtocols defines the list of acceptable URL schemes for escaping.

View Source
var SanitizeAllowedProtocols = []string{
	"http", "https", "mailto", "ftp", "ftps", "news", "irc", "irc6",
	"ircs", "gopher", "nntp", "feed", "telnet", "mms", "rtsp", "sms",
	"svn", "tel", "fax", "xmpp", "webcal", "urn",
}

SanitizeAllowedProtocols defines the list of acceptable URL schemes for sanitization.

Functions

func EscapePlainText

func EscapePlainText(input string, hook EscapePlainTextHook) string

EscapePlainText sanitizes plain text by removing unwanted characters. It allows customization through an optional hook to permit additional characters.

func EscapeURL

func EscapeURL(input string, context string, hook URLHook) (string, error)

EscapeURL sanitizes and escapes a URL, applying an optional custom hook. This is a known and accepted complexity (gocyclo > 15).

func HTMLSanitize

func HTMLSanitize(content string, allowedHTML map[string][]string) string

HTMLSanitize sanitizes content by removing unwanted HTML tags, attributes, and protocols.

func HTMLSanitizeBasic added in v1.1.0

func HTMLSanitizeBasic(content string) string

HTMLSanitizeBasic sanitizes HTML using the default allowed HTML map.

func IsAllowedProtocol

func IsAllowedProtocol(scheme string, allowedProtocols []string) bool

IsAllowedProtocol checks if a URL scheme is in the provided allowed list.

func MustHTMLSanitizeBasic added in v1.1.0

func MustHTMLSanitizeBasic(content string) string

MustHTMLSanitizeBasic runs HTMLSanitize using the default AllowedHTML rules.

func MustSanitizeEmailBasic added in v1.1.0

func MustSanitizeEmailBasic(input string) string

MustSanitizeEmailBasic is a fail-fast wrapper that panics if SanitizeEmailBasic returns an error.

func MustSanitizeFileNameBasic added in v1.1.0

func MustSanitizeFileNameBasic(input string) string

MustSanitizeFileNameBasic is a fail-fast wrapper that panics if SanitizeFileNameBasic returns an error.

func MustSanitizeURLBasic added in v1.1.0

func MustSanitizeURLBasic(input string) string

MustSanitizeURLBasic is a fail-fast wrapper that panics if SanitizeURLBasic returns an error.

func SafeEscapeHTML

func SafeEscapeHTML(input string) string

SafeEscapeHTML escapes only specific characters, excluding '%'.

func SanitizeEmail

func SanitizeEmail(input string, hook EmailHook) (string, error)

SanitizeEmail sanitizes an email address with optional hooks for custom behavior.

func SanitizeEmailBasic added in v1.1.0

func SanitizeEmailBasic(input string) (string, error)

SanitizeEmailBasic sanitizes the email input using default behavior (no hook).

func SanitizeFileName

func SanitizeFileName(input string, hook FileNameHook) (string, error)

SanitizeFileName sanitizes a filename by removing unwanted characters, handling multiple extensions, preventing directory traversal, normalizing Unicode characters, and enforcing filename length constraints. An optional custom hook can be applied for additional validation or transformation.

func SanitizeFileNameBasic added in v1.1.0

func SanitizeFileNameBasic(input string) (string, error)

SanitizeFileNameBasic sanitizes a filename with default settings and no custom hook.

func SanitizeURL

func SanitizeURL(input string) (string, error)

SanitizeURL sanitizes the input URL using the "display" context.

func SanitizeURLBasic added in v1.1.0

func SanitizeURLBasic(input string) (string, error)

SanitizeURLBasic sanitizes the URL using the default display context and no custom hook.

Types

type EmailHook

type EmailHook func(local, domain string) (string, string, error)

EmailHook defines a function signature for custom email sanitization.

type EscapePlainTextHook

type EscapePlainTextHook func() []rune

EscapePlainTextHook defines a function signature for custom behavior.

type FileNameHook

type FileNameHook func(filename string) (string, error)

FileNameHook defines a function signature for custom filename validation or transformation. It receives the sanitized filename and can perform additional checks or modifications.

type SanitizedStringFlag added in v1.1.0

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

SanitizedStringFlag represents a sanitized string flag bound to pflag.

func BindSanitizedFlag added in v1.1.0

func BindSanitizedFlag(name, defaultValue, usage string, sanitizer func(string) (string, error)) *SanitizedStringFlag

BindSanitizedFlag binds a string flag and attaches a sanitizer function.

func (*SanitizedStringFlag) Get added in v1.1.0

func (f *SanitizedStringFlag) Get() (string, error)

Get returns the sanitized value or an error.

func (*SanitizedStringFlag) MustGet added in v1.1.0

func (f *SanitizedStringFlag) MustGet() string

MustGet returns the sanitized value or panics on error.

type SanitizedTextFlag added in v1.1.0

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

SanitizedTextFlag represents a plain text flag bound to pflag and auto-sanitized.

func BindSanitizedTextFlag added in v1.1.0

func BindSanitizedTextFlag(name, defaultValue, usage string, hook EscapePlainTextHook) *SanitizedTextFlag

BindSanitizedTextFlag registers a flag that will be sanitized using EscapePlainText. The hook argument can be nil for default sanitization.

func (*SanitizedTextFlag) Get added in v1.1.0

func (f *SanitizedTextFlag) Get() string

Get returns the sanitized text value using EscapePlainText and the optional hook.

func (*SanitizedTextFlag) MustGet added in v1.1.0

func (f *SanitizedTextFlag) MustGet() string

MustGet is an alias for Get to match other sanitized flag helpers.

type URLHook

type URLHook func(parsedURL *url.URL) (*url.URL, error)

URLHook defines a function signature for custom URL processing.

Directories

Path Synopsis
Package main contains standalone example programs that demonstrate how to use the goisl (Go Input Sanitization Library) package.
Package main contains standalone example programs that demonstrate how to use the goisl (Go Input Sanitization Library) package.

Jump to

Keyboard shortcuts

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