mask

package module
v0.6.1 Latest Latest
Warning

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

Go to latest
Published: Nov 19, 2023 License: MIT Imports: 9 Imported by: 2

README

go-mask

Documentation Go Tests codecov Go Report Card

go-mask is a simple, customizable Go library for masking sensitive information.

Features

  • You can mask any field of a structure using the struct's tags. (example → How to use)
  • It is also possible to mask using field names or map keys without using tags. (example → field name / map key)
  • Users can make use of their own custom-created masking functions. (example → custom mask function)
  • The masked object is a copied object, so it does not overwrite the original data before masking(although it's not perfect...)
    • Private fields are not copied
    • It is moderately fast in performing deep copies.

Installation

go get github.com/showa-93/go-mask

Mask Tags

go-mask does not provide many tags by default.
This is because it is believed that users should create their own necessary masking functions.

tag type description
mask:"filled" string Masks the string with the same number of masking characters.
mask:"filledXXX" string XXX = number of masking characters. Masks with a fixed number of characters. mask:"filled3"***
mask:"fixed" string Masks with a fixed number of characters. *******
mask:"hash" string Masks the string by converting it to a value using sha1.
mask:"randomXXX" int / float64 XXX = numeric value. Masks with a random value in the range of 0 to the XXX.
mask:"zero" any It can be applied to any type, masking it with the zero value of that type.

How to use

string
package main

import (
	"fmt"

	mask "github.com/showa-93/go-mask"
)

func main() {
	{
		maskValue, _ := mask.String(mask.MaskTypeFixed, "Hello World!!")
		fmt.Println(maskValue)
	}
	{
		value := struct {
			Title string   `mask:"filled"`
			Casts []string `mask:"fixed"`
		}{
			Title: "Catch Me If You Can",
			Casts: []string{
				"Thomas Jeffrey \"Tom\" Hanks",
				"Leonardo Wilhelm DiCaprio",
			},
		}
		masker := mask.NewMasker()
		masker.SetMaskChar("-")
		masker.RegisterMaskStringFunc(mask.MaskTypeFilled, masker.MaskFilledString)
		masker.RegisterMaskStringFunc(mask.MaskTypeFixed, masker.MaskFixedString)

		maskValue, _ := mask.Mask(value)
		maskValue2, _ := masker.Mask(value)

		fmt.Printf("%+v\n", value)
		fmt.Printf("%+v\n", maskValue)
		fmt.Printf("%+v\n", maskValue2)
	}
}
********
{Title:Catch Me If You Can Casts:[Thomas Jeffrey "Tom" Hanks Leonardo Wilhelm DiCaprio]}
{Title:******************* Casts:[******** ********]}
{Title:------------------- Casts:[-------- --------]}
int / float64 / uint
package main

import (
	"fmt"

	mask "github.com/showa-93/go-mask"
)

func main() {
	{
		maskValue, _ := mask.Int("random100", 10)
		fmt.Println(maskValue)
	}
	{
		maskValue, _ := mask.Float64("random100.2", 12.3)
		fmt.Println(maskValue)
	}

	{
		value := struct {
			Price   int     `mask:"random1000"`
			Percent float64 `mask:"random1.3"`
		}{
			Price:   300,
			Percent: 0.80,
		}
		masker := mask.NewMasker()
		masker.RegisterMaskIntFunc(mask.MaskTypeRandom, masker.MaskRandomInt)
		masker.RegisterMaskFloat64Func(mask.MaskTypeRandom, masker.MaskRandomFloat64)

		maskValue, _ := mask.Mask(value)
		maskValue2, _ := masker.Mask(value)

		fmt.Printf("%+v\n", maskValue)
		fmt.Printf("%+v\n", maskValue2)
	}
}
29
50.45
{Price:917 Percent:0.183}
{Price:733 Percent:0.241}
slice / array
package main

import (
	"fmt"

	"github.com/showa-93/go-mask"
)

type Value struct {
	Name string `mask:"filled"`
	Type int    `mask:"random10"`
}

func main() {
	values := []Value{
		{
			Name: "Thomas Jeffrey \"Tom\" Hanks",
			Type: 1,
		},
		{
			Name: "Leonardo Wilhelm DiCaprio",
			Type: 2,
		},
	}
	masker := mask.NewMasker()
	masker.SetMaskChar("+")
	masker.RegisterMaskStringFunc(mask.MaskTypeFilled, masker.MaskFilledString)
	masker.RegisterMaskIntFunc(mask.MaskTypeRandom, masker.MaskRandomInt)

	maskValues, _ := mask.Mask(values)
	maskValues2, _ := masker.Mask(values)

	fmt.Printf("%+v\n", values)
	fmt.Printf("%+v\n", maskValues)
	fmt.Printf("%+v\n", maskValues2)
}
[{Name:Thomas Jeffrey "Tom" Hanks Type:1} {Name:Leonardo Wilhelm DiCaprio Type:2}]
[{Name:************************** Type:8} {Name:************************* Type:9}]
[{Name:++++++++++++++++++++++++++ Type:4} {Name:+++++++++++++++++++++++++ Type:8}]
map
package main

import (
	"fmt"

	"github.com/showa-93/go-mask"
)

type Value struct {
	Name string `mask:"filled"`
	Type int    `mask:"random10"`
}

func main() {
	values := map[string]Value{
		"one": {
			Name: "Thomas Jeffrey \"Tom\" Hanks",
			Type: 1,
		},
		"two": {
			Name: "Leonardo Wilhelm DiCaprio",
			Type: 2,
		},
	}
	masker := mask.NewMasker()
	masker.SetMaskChar("")
	masker.RegisterMaskStringFunc(mask.MaskTypeFilled, masker.MaskFilledString)
	masker.RegisterMaskIntFunc(mask.MaskTypeRandom, masker.MaskRandomInt)

	maskValues, _ := mask.Mask(values)
	maskValues2, _ := masker.Mask(values)

	fmt.Printf("%+v\n", values)
	fmt.Printf("%+v\n", maskValues)
	fmt.Printf("%+v\n", maskValues2)
}
map[one:{Name:Thomas Jeffrey "Tom" Hanks Type:1} two:{Name:Leonardo Wilhelm DiCaprio Type:2}]
map[one:{Name:************************** Type:8} two:{Name:************************* Type:6}]
map[one:{Name: Type:6} two:{Name: Type:2}]
JSON
package main

import (
	"encoding/json"
	"fmt"

	mask "github.com/showa-93/go-mask"
)

func main() {
	masker := mask.NewMasker()
	masker.RegisterMaskStringFunc(mask.MaskTypeFilled, masker.MaskFilledString)
	masker.RegisterMaskField("S", "filled4")

	v := `{
		"S": "Hello world",
		"I": 1,
		"O": {
			"S": "Second",
			"S2": "豚汁"
		}
	}`
	var target any
	json.Unmarshal([]byte(v), &target)
	masked, _ := masker.Mask(target)
	mv, _ := json.Marshal(masked)
	fmt.Println(string(mv))
}
{"I":1,"O":{"S":"****","S2":"豚汁"},"S":"****"}
nested struct
package main

import (
	"fmt"

	"github.com/showa-93/go-mask"
)

type Node struct {
	Value string `mask:"filled"`
	Next  *Node
}

func main() {
	node := Node{
		Value: "first",
		Next: &Node{
			Value: "second",
			Next: &Node{
				Value: "third",
			},
		},
	}

	masker := mask.NewMasker()
	masker.SetMaskChar("🤗")
	masker.RegisterMaskStringFunc(mask.MaskTypeFilled, masker.MaskFilledString)

	maskNode, _ := mask.Mask(node)
	maskNode2, _ := masker.Mask(node)

	fmt.Printf("first=%+v,second=%+v,third=%+v\n", node, node.Next, node.Next.Next)
	fmt.Printf("first=%+v,second=%+v,third=%+v\n", maskNode, maskNode.Next, maskNode.Next.Next)
	fmt.Printf("first=%+v,second=%+v,third=%+v\n", maskNode2.(Node), maskNode2.(Node).Next, maskNode2.(Node).Next.Next)
}
first={Value:first Next:0xc000010048},second=&{Value:second Next:0xc000010060},third=&{Value:third Next:<nil>}
first={Value:***** Next:0xc0000100a8},second=&{Value:****** Next:0xc0000100c0},third=&{Value:***** Next:<nil>}
first={Value:🤗🤗🤗🤗🤗 Next:0xc000010120},second=&{Value:🤗🤗🤗🤗🤗🤗 Next:0xc000010138},third=&{Value:🤗🤗🤗🤗🤗 Next:<nil>}
field name / map key
package main

import (
	"fmt"

	mask "github.com/showa-93/go-mask"
)

type User struct {
	ID      string // no tag
	Name    string
	Gender  string
	Age     int
	ExtData map[string]string
}

func main() {
	masker := mask.NewMasker()

	masker.RegisterMaskStringFunc(mask.MaskTypeFilled, masker.MaskFilledString)
	masker.RegisterMaskIntFunc(mask.MaskTypeRandom, masker.MaskRandomInt)

	// registered field name
	masker.RegisterMaskField("Name", "filled4")
	masker.RegisterMaskField("Animal", "filled6")
	masker.RegisterMaskField("Age", mask.MaskTypeRandom+"100")

	u := User{
		ID:     "1",
		Name:   "タマ",
		Gender: "Male",
		Age:    4,
		ExtData: map[string]string{
			"Animal": "Cat",
		},
	}
	maskedUser, _ := masker.Mask(u)
	fmt.Printf("%+v", maskedUser)
}
{ID:1 Name:**** Gender:Male Age:10 ExtData:map[Animal:******]}
custom mask function
package main

import (
	"fmt"
	"regexp"
	"strings"

	mask "github.com/showa-93/go-mask"
)

func init() {
	maskTypeRegExp := "regexp"
	mask.RegisterMaskStringFunc(maskTypeRegExp, MaskRegExp)
}

// MaskRegExp is sample to add a custom mask function
func MaskRegExp(arg, value string) (string, error) {
	var (
		reg *regexp.Regexp
		err error
	)
	reg, err = regexp.Compile(arg)
	if err != nil {
		return "", err
	}

	indexes := reg.FindStringSubmatchIndex(value)
	if len(indexes) >= 4 && indexes[2] >= 0 && indexes[3] >= 0 {
		var sb strings.Builder
		sb.WriteString(value[:indexes[2]])
		sb.WriteString(mask.MaskChar())
		sb.WriteString(value[indexes[3]:])
		return sb.String(), nil
	}

	return value, nil
}

func main() {
	mask.SetMaskChar("cat")
	type Hachiware struct {
		Message string `mask:"regexp(gopher)."`
	}

	input := Hachiware{Message: "I love gopher!"}
	got, _ := mask.Mask(input)
	fmt.Printf("%+v\n", input)
	fmt.Printf("%+v\n", got)

	// The Masker initialized with NewMasker does not have
	// any custom masking functions registered, so no masking will occur
	masker := mask.NewMasker()
	got2, _ := masker.Mask(input)
	fmt.Printf("%+v\n", got2)
}
{Message:I love gopher!}
{Message:I love cat!}
{Message:I love gopher!}

Documentation

Overview

Example
rand.Seed(12345)
type Address struct {
	PostCode string `mask:"zero"`
}
type User struct {
	ID      string
	Name    string `mask:"filled"`
	Age     int    `mask:"random100"`
	Address Address
}

user := User{
	ID:   "123456",
	Name: "Usagi",
	Age:  3,
	Address: Address{
		PostCode: "123-4567",
	},
}
maskUser, err := Mask(user)
if err != nil {
	fmt.Println(err)
	return
}
fmt.Printf("%+v", maskUser)
Output:

{ID:123456 Name:***** Age:83 Address:{PostCode:}}
Example (CustomMaskFunc)
package main

import (
	"fmt"
	"regexp"
	"strings"
	"unicode/utf8"

	mask "github.com/showa-93/go-mask"
)

func init() {
	maskTypeRegExp := "regexp"
	mask.RegisterMaskStringFunc(maskTypeRegExp, MaskRegExp)
}

// MaskRegExp is sample to add a custom mask function
func MaskRegExp(arg, value string) (string, error) {
	var (
		reg *regexp.Regexp
		err error
	)
	reg, err = regexp.Compile(arg)
	if err != nil {
		return "", err
	}

	indexes := reg.FindStringSubmatchIndex(value)
	if len(indexes) >= 4 && indexes[2] >= 0 && indexes[3] >= 0 {
		var sb strings.Builder
		sb.WriteString(value[:indexes[2]])
		sb.WriteString(strings.Repeat(mask.MaskChar(), utf8.RuneCountInString(value[indexes[2]:indexes[3]])))
		sb.WriteString(value[indexes[3]:])
		return sb.String(), nil
	}

	return value, nil
}

func main() {
	mask.SetMaskChar("■")
	type Hachiware struct {
		Message string `mask:"regexp(最高)."`
	}

	input := Hachiware{Message: "これって…最高じゃん"}
	got, _ := mask.Mask(input)
	fmt.Printf("\"%s\", Hachiware says\n", got.Message)

}
Output:

"これって…■■じゃん", Hachiware says

Index

Examples

Constants

View Source
const (
	MaskTypeFilled = "filled"
	MaskTypeFixed  = "fixed"
	MaskTypeRandom = "random"
	MaskTypeHash   = "hash"
	MaskTypeZero   = "zero"
)

Default tag that can be specified as a mask

View Source
const TagName = "mask"

Tag name of the field in the structure when masking

Variables

This section is empty.

Functions

func Float64

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

Float64 masks the given argument float64 from default masker.

func Int

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)

Mask returns an object with the mask applied to any given object. The function's argument can accept any type, including pointer, map, and slice types, in addition to struct. from default masker.

func MaskChar

func MaskChar() string

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

func RegisterMaskAnyFunc

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.4.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.

Example
rand.Seed(12345)
type User2 struct {
	ID      string
	Name    string
	Age     int
	ExtData map[string]string
}
user := User2{
	ID:   "123456",
	Name: "Usagi",
	Age:  3,
	ExtData: map[string]string{
		"ID":       "123456",
		"Favorite": "Cat",
	},
}

RegisterMaskField("ID", "zero")
RegisterMaskField("Age", "random100")
RegisterMaskField("Name", "filled4")
RegisterMaskField("Favorite", "filled6")
maskUser, err := Mask(user)
if err != nil {
	fmt.Println(err)
	return
}
fmt.Printf("%+v", maskUser)
Output:

{ID: Name:**** Age:83 ExtData:map[Favorite:****** ID:]}

func RegisterMaskFloat64Func

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

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

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.5.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

func SetMaskChar(s string)

SetMaskChar changes the character used for masking from default masker.

func String

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

String masks the given argument string from default masker.

func Uint added in v0.5.0

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

Uint masks the given argument int from default masker.

Types

type MaskAnyFunc

type MaskAnyFunc func(arg string, value any) (any, error)

Function type that must be satisfied to add a custom mask

type MaskFloat64Func

type MaskFloat64Func func(arg string, value float64) (float64, error)

Function type that must be satisfied to add a custom mask

type MaskIntFunc

type MaskIntFunc func(arg string, value int) (int, error)

Function type that must be satisfied to add a custom mask

type MaskStringFunc

type MaskStringFunc func(arg string, value string) (string, error)

Function type that must be satisfied to add a custom mask

type MaskUintFunc added in v0.5.0

type MaskUintFunc func(arg string, value uint) (uint, error)

Function type that must be satisfied to add a custom mask

type Masker added in v0.2.0

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

Masker is a struct that defines the masking process.

func NewMasker added in v0.2.0

func NewMasker() *Masker

NewMasker initializes a Masker.

func (*Masker) Cache added in v0.6.0

func (m *Masker) Cache(enable bool)

Cache can be toggled to cache the type information of the struct. default true

func (*Masker) Float64 added in v0.2.0

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

Float64 masks the given argument float64

func (*Masker) Int added in v0.2.0

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

Int masks the given argument int

func (*Masker) Mask added in v0.2.0

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

Mask returns an object with the mask applied to any given object. The function's argument can accept any type, including pointer, map, and slice types, in addition to struct.

func (*Masker) MaskChar added in v0.2.0

func (m *Masker) MaskChar() string

MaskChar returns the current character used for masking.

func (*Masker) MaskFilledString added in v0.3.0

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

MaskFilledString masks the string length of the value with the same length. If you pass a number like "2" to arg, it masks with the length of the number.(**)

func (*Masker) MaskFixedString added in v0.3.0

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

MaskFixedString masks with a fixed length (8 characters).

func (*Masker) MaskHashString added in v0.3.0

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

MaskHashString masks and hashes (sha1) a string.

func (*Masker) MaskRandomFloat64 added in v0.3.0

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

MaskRandomFloat64 converts a float64 to a random number. For example, if you pass "100.3" to arg, it sets a random number in the range of 0.000 to 99.999.

func (*Masker) MaskRandomInt added in v0.3.0

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

MaskRandomInt converts an integer (int) into a random number. For example, if you pass "100" as the arg, it sets a random number in the range of 0-99.

func (*Masker) MaskZero added in v0.3.0

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

MaskZero converts the value to its type's zero value.

func (*Masker) RegisterMaskAnyFunc added in v0.2.0

func (m *Masker) 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.

func (*Masker) RegisterMaskField added in v0.4.0

func (m *Masker) 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.

func (*Masker) RegisterMaskFloat64Func added in v0.2.0

func (m *Masker) 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.

func (*Masker) RegisterMaskIntFunc added in v0.2.0

func (m *Masker) 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.

func (*Masker) RegisterMaskStringFunc added in v0.2.0

func (m *Masker) 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.

func (*Masker) RegisterMaskUintFunc added in v0.5.0

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

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

func (*Masker) SetMaskChar added in v0.2.0

func (m *Masker) SetMaskChar(s string)

SetMaskChar changes the character used for masking

func (*Masker) SetTagName added in v0.4.0

func (m *Masker) SetTagName(s string)

SetTagName allows you to change the tag name from "mask" to something else.

func (*Masker) String added in v0.2.0

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

String masks the given argument string

func (*Masker) Uint added in v0.5.0

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

Uint masks the given argument uint

Jump to

Keyboard shortcuts

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