masker

package module
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Jul 18, 2026 License: MIT Imports: 9 Imported by: 6

README

Go Masker

go-masker creates masked copies of Go structs, maps, slices, pointers, and scalar values. It wraps github.com/showa-93/go-mask with independent instances, predefined field profiles, fixed redaction, and configure-then-freeze semantics.

Install

go get github.com/goliatone/go-masker

Security model

Masking is most reliable for structured data with known fields or map keys. It is not a general secret scanner and cannot guarantee detection of credentials embedded in arbitrary prose.

  • Use NewSecure for credential-bearing output.
  • Omit untrusted free-form strings unless a dedicated sanitizer makes them safe.
  • Treat masking as defense in depth after field selection and allowlisting.
  • If masking returns an error, do not fall back to the original value.

The secure profile replaces credentials with the fixed marker [REDACTED]. It does not preserve token fragments or disclose their original length.

Secure instance

m, err := masker.NewSecure()
if err != nil {
    return err
}

masked, err := m.Mask(map[string]any{
    "clientSecret": "secret-value",
    "visible":      "safe-value",
})
if err != nil {
    return err // fail closed; do not use the input as fallback
}

NewSecure disables the upstream reflection cache and freezes the instance. Configure it entirely through options:

m, err := masker.NewSecure(
    masker.WithTagName("mask"),
    masker.WithMaskChar("#"),
    masker.WithMaskField("tenantCredential", masker.MaskTypeRedact),
)

Security-sensitive aliases include common snake_case, kebab-case, camelCase, PascalCase, and header-style names for passwords, secrets, tokens, authorization values, cookies, signing/private keys, credentials, API keys, and credit cards.

General instances

New creates an independent configurable instance with the compatibility profile:

m, err := masker.New(
    masker.WithProfile(masker.ProfileDefault),
    masker.WithCache(false),
)
if err != nil {
    return err
}

if err := m.RegisterMaskField("account_id", "preserveEnds(2,2)"); err != nil {
    return err
}
m.Freeze()

Available profiles:

  • ProfileDefault: compatibility rules, including partial token and identifier masking.
  • ProfileSecure: fixed full redaction for credential fields.
  • ProfileNone: no field-name rules; built-in masking functions remain registered.

Options can configure:

  • tag name and mask character;
  • cache behavior;
  • field rules;
  • custom string, integer, unsigned integer, float, and any-value functions.

Invalid options cause New to return ErrInvalidOption without returning a partial instance. Configuration after Freeze returns ErrFrozen.

Struct tags and custom rules

Struct tags take precedence over field-name profiles:

type Customer struct {
    Name       string
    Password   string
    Identifier string `mask:"preserveEnds(2,2)"`
}

Custom functions can be registered as options or before freezing:

m, err := masker.New(
    masker.WithProfile(masker.ProfileNone),
    masker.WithMaskStringFunc("custom", func(arg, value string) (string, error) {
        return "[CUSTOM]", nil
    }),
    masker.WithMaskField("label", "custom"),
)

Mask types

  • redact: fixed [REDACTED] output for strings and bytes; type-safe zero values for other sensitive values.
  • filled: repeated mask character, optionally with a requested length such as filled4.
  • fixed: fixed eight-character mask.
  • preserveEnds(start,end): preserves selected string ends; use only for non-secret identifiers.
  • hash: SHA-1 representation inherited for compatibility; not suitable as credential protection.
  • random: random numeric replacement.
  • zero: the value's zero value.

Concurrency

Configuration methods and masking are synchronized. Freeze an instance before sharing it.

  • Cache-disabled instances allow concurrent mask operations and are recommended for security-sensitive output paths.
  • Cache-enabled operations are serialized because the wrapped dependency reuses mutable reflection destinations.
  • Independent instances do not share configuration.
  • The mutable package-level Default exists for compatibility and should not be used as an application-wide configuration surface by libraries.

Compatibility helpers

Package functions such as Mask, RegisterMaskField, and SetMaskChar delegate to Default. New integrations should prefer an independent instance:

masked, err := masker.Mask(value) // compatibility path

License

MIT

Copyright (c) 2024 goliatone

Documentation

Overview

Package masker creates masked copies of structured Go values.

For credential-bearing output, construct a dedicated frozen secure instance:

m, err := masker.NewSecure(
	masker.WithMaskField("tenantCredential", masker.MaskTypeRedact),
)
if err != nil {
	return err
}
masked, err := m.Mask(value)

New creates a general independent instance. Configure it with options or registration methods, then call Freeze before sharing it across goroutines. Package-level helpers delegate to the mutable Default instance and are kept for compatibility; libraries should not use Default as global configuration.

The secure profile fully replaces recognized credential fields with a fixed marker. Preserve-ends and hash rules remain available for explicit non-secret use cases. Masking is field-based and does not reliably discover secrets in arbitrary prose, so callers should omit untrusted free-form strings and must not fall back to raw values when masking fails.

Cache-disabled Mask calls can run concurrently. Cache-enabled Mask calls are serialized to contain mutable reflection destinations in the wrapped dependency. Configuration methods are synchronized, and Freeze prevents subsequent changes.

Index

Constants

View Source
const (
	MaskTypePreserveEnds = "preserveEnds"
	MaskTypeRedact       = "redact"
	RedactedValue        = "[REDACTED]"
)

Variables

View Source
var (
	// ErrFrozen is returned when configuration is changed after Freeze.
	ErrFrozen = errors.New("masker configuration is frozen")
	// ErrInvalidOption is returned when an option cannot produce a valid masker.
	ErrInvalidOption = errors.New("invalid masker option")
)
View Source
var Default = mustNew()

Default backs the package-level compatibility helpers. New integrations should construct and freeze an independent Masker instead of mutating Default.

Functions

func Float64 added in v0.2.0

func Float64(tag string, value float64) (float64, error)

Float64 masks the given argument float64 from default masker.

func Int added in v0.2.0

func Int(tag string, value int) (int, error)

Int masks the given argument int from default masker.

func Mask

func Mask[T any](target T) (ret T, err error)

func MaskChar added in v0.2.0

func MaskChar() string

MaskChar returns the current character used for masking. from default masker.

func MaskPreserveEnds added in v0.1.0

func MaskPreserveEnds(arg string, value string) (string, error)

func MaskRedact added in v0.2.0

func MaskRedact(_ string, value string) (string, error)

MaskRedact replaces any non-empty string with a fixed marker that does not disclose the original value or its length.

func MaskRedactAny added in v0.2.0

func MaskRedactAny(_ string, value any) (any, error)

MaskRedactAny replaces strings and byte slices with RedactedValue and returns the zero value for other types. The returned value retains the input type so reflection-based struct masking remains assignable.

func RegisterMaskAnyFunc added in v0.2.0

func RegisterMaskAnyFunc(maskType string, maskFunc MaskAnyFunc)

RegisterMaskAnyFunc registers a masking function that can be applied to any type. The function will be applied when the string set in the first argument is assigned as a tag to a field in the structure. from default masker.

func RegisterMaskField added in v0.2.0

func RegisterMaskField(fieldName, maskType string)

RegisterMaskField allows you to register a mask tag to be applied to the value of a struct field or map key that matches the fieldName. If a mask tag is set on the struct field, it will take precedence. from default masker.

func RegisterMaskFloat64Func added in v0.2.0

func RegisterMaskFloat64Func(maskType string, maskFunc MaskFloat64Func)

RegisterMaskFloat64Func registers a masking function for float64 values. The function will be applied when the string set in the first argument is assigned as a tag to a field in the structure. from default masker.

func RegisterMaskIntFunc added in v0.2.0

func RegisterMaskIntFunc(maskType string, maskFunc MaskIntFunc)

RegisterMaskIntFunc registers a masking function for int values. The function will be applied when the string set in the first argument is assigned as a tag to a field in the structure. from default masker.

func RegisterMaskStringFunc added in v0.2.0

func RegisterMaskStringFunc(maskType string, maskFunc MaskStringFunc)

RegisterMaskStringFunc registers a masking function for string values. The function will be applied when the string set in the first argument is assigned as a tag to a field in the structure. from default masker.

func RegisterMaskUintFunc added in v0.2.0

func RegisterMaskUintFunc(maskType string, maskFunc MaskUintFunc)

RegisterMaskUintFunc registers a masking function for uint values. The function will be applied when the string set in the first argument is assigned as a tag to a field in the structure. from default masker.

func SetMaskChar added in v0.2.0

func SetMaskChar(s string)

SetMaskChar changes the character used for masking from default masker.

func String added in v0.2.0

func String(tag, value string) (string, error)

String masks the given argument string from default masker.

func Uint added in v0.2.0

func Uint(tag string, value uint) (uint, error)

Uint masks the given argument int from default masker.

Types

type MaskAnyFunc

type MaskAnyFunc = mask.MaskAnyFunc

type MaskFloat64Func

type MaskFloat64Func = mask.MaskFloat64Func

type MaskIntFunc

type MaskIntFunc = mask.MaskIntFunc

type MaskStringFunc

type MaskStringFunc = mask.MaskStringFunc

type MaskUintFunc

type MaskUintFunc = mask.MaskUintFunc

type Masker

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

Masker wraps go-mask with independent configuration and a concurrency-safe lifecycle. Configuration methods take an exclusive lock; masking is safe for concurrent use. Freeze prevents later configuration changes.

func New added in v0.2.0

func New(options ...Option) (*Masker, error)

New constructs an independent masker with built-in functions and the default field profile. Options are applied before the instance becomes visible.

func NewSecure added in v0.2.0

func NewSecure(options ...Option) (*Masker, error)

NewSecure constructs and freezes an independent security-profiled masker. Callers can supply additional options to override defaults before freezing.

func (*Masker) Cache

func (m *Masker) Cache(enabled bool) error

Cache toggles the wrapped masker's reflection cache.

func (*Masker) Float64

func (m *Masker) Float64(tag string, value float64) (float64, error)

func (*Masker) Freeze added in v0.2.0

func (m *Masker) Freeze() *Masker

Freeze prevents subsequent configuration changes. Masking remains available.

func (*Masker) Frozen added in v0.2.0

func (m *Masker) Frozen() bool

Frozen reports whether configuration has been frozen.

func (*Masker) Int

func (m *Masker) Int(tag string, value int) (int, error)

func (*Masker) Mask

func (m *Masker) Mask(target any) (any, error)

Mask returns a deep masked copy. Calls are serialized when the wrapped dependency's reflection cache is enabled because that cache reuses mutable destinations. Cache-disabled calls may execute concurrently.

func (*Masker) MaskChar

func (m *Masker) MaskChar() string

MaskChar returns the current mask character.

func (*Masker) MaskFilledString

func (m *Masker) MaskFilledString(arg, value string) (string, error)

func (*Masker) MaskFixedString

func (m *Masker) MaskFixedString(arg, value string) (string, error)

func (*Masker) MaskHashString

func (m *Masker) MaskHashString(arg, value string) (string, error)

func (*Masker) MaskRandomFloat64

func (m *Masker) MaskRandomFloat64(arg string, value float64) (float64, error)

func (*Masker) MaskRandomInt

func (m *Masker) MaskRandomInt(arg string, value int) (int, error)

func (*Masker) MaskZero

func (m *Masker) MaskZero(arg string, value any) (any, error)

func (*Masker) RegisterMaskAnyFunc

func (m *Masker) RegisterMaskAnyFunc(maskType string, maskFunc MaskAnyFunc) error

func (*Masker) RegisterMaskField

func (m *Masker) RegisterMaskField(fieldName, maskType string) error

RegisterMaskField registers a rule for common naming variants of fieldName.

func (*Masker) RegisterMaskFloat64Func

func (m *Masker) RegisterMaskFloat64Func(maskType string, maskFunc MaskFloat64Func) error

func (*Masker) RegisterMaskIntFunc

func (m *Masker) RegisterMaskIntFunc(maskType string, maskFunc MaskIntFunc) error

func (*Masker) RegisterMaskStringFunc

func (m *Masker) RegisterMaskStringFunc(maskType string, maskFunc MaskStringFunc) error

func (*Masker) RegisterMaskUintFunc

func (m *Masker) RegisterMaskUintFunc(maskType string, maskFunc MaskUintFunc) error

func (*Masker) SetMaskChar

func (m *Masker) SetMaskChar(char string) error

SetMaskChar changes the character used for masking.

func (*Masker) SetTagName

func (m *Masker) SetTagName(name string) error

SetTagName changes the struct tag name used for masking.

func (*Masker) String

func (m *Masker) String(tag, value string) (string, error)

func (*Masker) Uint

func (m *Masker) Uint(tag string, value uint) (uint, error)

type Option added in v0.2.0

type Option func(*config) error

Option configures a newly constructed Masker.

func WithCache added in v0.2.0

func WithCache(enabled bool) Option

WithCache enables or disables the wrapped masker's reflection cache.

func WithMaskAnyFunc added in v0.2.0

func WithMaskAnyFunc(maskType string, maskFunc MaskAnyFunc) Option

WithMaskAnyFunc registers a custom masking function for any supported value.

func WithMaskChar added in v0.2.0

func WithMaskChar(char string) Option

WithMaskChar changes the character used by filled and preserve-ends masks.

func WithMaskField added in v0.2.0

func WithMaskField(fieldName, maskType string) Option

WithMaskField registers a masking rule for a struct field or string map key.

func WithMaskFloat64Func added in v0.2.0

func WithMaskFloat64Func(maskType string, maskFunc MaskFloat64Func) Option

WithMaskFloat64Func registers a custom float64 masking function.

func WithMaskIntFunc added in v0.2.0

func WithMaskIntFunc(maskType string, maskFunc MaskIntFunc) Option

WithMaskIntFunc registers a custom int masking function.

func WithMaskStringFunc added in v0.2.0

func WithMaskStringFunc(maskType string, maskFunc MaskStringFunc) Option

WithMaskStringFunc registers a custom string masking function.

func WithMaskUintFunc added in v0.2.0

func WithMaskUintFunc(maskType string, maskFunc MaskUintFunc) Option

WithMaskUintFunc registers a custom uint masking function.

func WithProfile added in v0.2.0

func WithProfile(profile Profile) Option

WithProfile selects a set of preconfigured field rules.

func WithTagName added in v0.2.0

func WithTagName(name string) Option

WithTagName changes the struct tag used for masking rules.

type Profile added in v0.2.0

type Profile string

Profile selects the preconfigured field rules installed by New.

const (
	// ProfileDefault preserves the package's historical field behavior.
	ProfileDefault Profile = "default"
	// ProfileSecure fully redacts credential-bearing fields with a fixed marker.
	ProfileSecure Profile = "secure"
	// ProfileNone installs no field-name rules. Built-in masking functions remain available.
	ProfileNone Profile = "none"
)

Jump to

Keyboard shortcuts

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