jsonmask

package module
v0.0.0-...-592613d Latest Latest
Warning

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

Go to latest
Published: Jan 11, 2025 License: MIT Imports: 7 Imported by: 0

README

jsonmask

Build Status Go Report Card GoDoc Coverage Status

The jsonmask package is designed to mask sensitive data in JSON payloads. It allows developers to define masking rules on struct fields using tags, or programmatically, to anonymize or transform data as needed.

Features

  • Customizable Masking Functions: Transform values with predefined or custom masking functions.
  • Field-Level Control: Use struct tags to specify masking rules for individual fields.
  • Nested Data Support: Apply masking to nested objects, arrays, and slices.
  • Built-in Masking Functions:
    • Convert strings to uppercase or lowercase.
    • Truncate strings or replace them with empty values.
    • Mask email addresses.
    • Set numeric values to zero or nullify fields.

Installation

go get github.com/axkit/jsonmask

Usage

1. Define Your Struct

Annotate your struct fields with the mask tag to specify masking rules. Use - to exclude fields from output entirely.

package main

import (
	"encoding/json"
	"fmt"
	"github.com/axkit/jsonmask"
)

type User struct {
	ID        int    `json:"id"`
	FirstName string `json:"firstName" mask:"initialChar"`
	LastName  string `json:"lastName" mask:"first4"`
	Email     string `json:"email" mask:"email"`
	Password  string `json:"password" mask:"-"`
}

func main() {
	user := User{
		ID:        1,
		FirstName: "Robert",
		LastName:  "Egorov",
		Email:     "robert.egorov@example.com",
		Password:  "supersecret",
	}

	jm := jsonmask.New()
	rules := jm.ParseStruct(user)
	jsonData, _ := json.Marshal(user)
	maskedData, _ := jm.Mask(jsonData, rules)

	fmt.Println(string(maskedData))
}

Output:

{
	"id": 1,
	"firstName": "R",
	"lastName": "Egor...",
	"email": "r***********v@e********.com"
}
2. Add Custom Masking Functions

Extend jsonmask with your own masking logic by registering custom functions.

jm.AddFunc("customMask", func(s string) []byte {
	return []byte(`"custom_value"`)
})

Then, use customMask in your struct tags or rules.

3. Use with Arrays and Nested Structures

jsonmask supports arrays, slices, and nested structures.

type Nested struct {
	Key string `json:"key" mask:"upper"`
}

type Parent struct {
	Items []Nested `json:"items"`
}

parent := Parent{
	Items: []Nested{
		{Key: "value1"},
		{Key: "value2"},
	},
}

jsonData, _ := json.Marshal(parent)
rules := jm.ParseStruct(parent)
maskedData, _ := jm.Mask(jsonData, rules)
fmt.Println(string(maskedData))

Output:

{
	"items": [
		{"key": "VALUE1"},
		{"key": "VALUE2"}
	]
}
4. Practical Example: Masking Sensitive Data in Logs

Suppose you have a web server that responds to client requests with JSON payloads. For debugging purposes, each response is logged. To prevent sensitive data from leaking into the logs, you can use the jsonmask package to mask values in sensitive fields before logging.

package main

import (
	"encoding/json"
	"fmt"
	"github.com/axkit/jsonmask"
	"net/http"
)

type ApiResponse struct {
	UserID    int    `json:"userId"`
	UserName  string `json:"userName" mask:"initialChar"`
	Email     string `json:"email" mask:"email"`
	SecretKey string `json:"secretKey" mask:"-"`
}

func handler(w http.ResponseWriter, r *http.Request) {
	response := ApiResponse{
		UserID:    42,
		UserName:  "JohnDoe",
		Email:     "johndoe@example.com",
		SecretKey: "supersecretkey",
	}

	jm := jsonmask.New()
	rules := jm.ParseStruct(response)
	jsonData, _ := json.Marshal(response)
	maskedData, _ := jm.Mask(jsonData, rules)

	// Log the masked response
	fmt.Println("Masked Response for Logs:", string(maskedData))

	// Send the original response to the client
	w.Header().Set("Content-Type", "application/json")
	w.Write(jsonData)
}

func main() {
	http.HandleFunc("/api", handler)
	http.ListenAndServe(":8080", nil)
}

Output in Logs:

{
	"userId": 42,
	"userName": "J",
	"email": "j***e@e********.com"
}

Predefined Masking Functions

  • upper: Converts strings to uppercase.
  • lower: Converts strings to lowercase.
  • initialChar: Extracts the first character in uppercase.
  • truncate: Replaces non-null strings with an empty string.
  • null: Sets the field to null.
  • email: Masks email addresses by anonymizing the local and domain parts.
  • zero: Sets numeric fields to 0.

Testing

Run the provided tests to ensure the package works as expected.

go test ./...

License

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

Documentation

Overview

Package jsonmask provides functionality to mask JSON data based on field metadata.

This file contains default maskers that are used to mask the JSON data. All functions have the same signature: func(string) []byte. The input string is a JSON string that represents a single value (with quotes).

Index

Constants

View Source
const DefaultStructFieldTag = "mask"

DefaultStructFieldTag is a default tag name for struct fields.

Variables

View Source
var (
	ErrInvalidInput = errors.New("input must be a struct")
)

Error definitions

Functions

func Email

func Email(email string) []byte

Email masks the input string holding email address.

func InitialChar

func InitialChar(s string) []byte

InitialChar returns the first character of the input string in uppercase.

func Lower

func Lower(s string) []byte

Lower returns the input string in lowercase.

func Null

func Null(s string) []byte

Null masks the input string to NULL without quotes.

func PrefixFn

func PrefixFn(length int, addEllipsis bool) func(string) []byte

PrefixFn returns a function that prefixes the input string with the specified length.

func Truncate

func Truncate(s string) []byte

Truncate masks the input string to an empty string if it is not NULL.

func Upper

func Upper(s string) []byte

Upper returns the input string in uppercase.

func Zero

func Zero(s string) []byte

Zero masks the input string holding numeric value to 0 without quotes.

Types

type JsonMaskerImpl

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

JsonMaskerImpl provides functionality to mask JSON data based on field metadata and custom masking functions.

func New

func New() *JsonMaskerImpl

New creates a new instance of JsonMaskerImpl.

func NewWithMaskTag

func NewWithMaskTag(tag string) *JsonMaskerImpl

NewWithMaskTag creates a new instance of JsonMaskerImpl with a custom tag name.

func (*JsonMaskerImpl) AddFunc

func (jm *JsonMaskerImpl) AddFunc(name string, f func(string) []byte)

AddFunc adds a masking function associated with a name.

func (*JsonMaskerImpl) Mask

func (jm *JsonMaskerImpl) Mask(data []byte, smr StructMaskRules) ([]byte, error)

Mask applies masking to JSON based on the given rules.

func (*JsonMaskerImpl) ParseStruct

func (jm *JsonMaskerImpl) ParseStruct(src any) StructMaskRules

ParseStruct extracts metadata fields from the given structure based on the provided tag.

type Rule

type Rule struct {
	// Path is a JSON path to the field.
	Path string

	// Action is a value of the mask tag.
	// It can be a name of a custom masking function or "-" to delete the field.
	Action string
	// contains filtered or unexported fields
}

Rule holds metadata for a single field of a structure.

type StructMaskRules

type StructMaskRules struct {
	Rules []Rule
}

StructMaskRules holds metadata for a structure.

Jump to

Keyboard shortcuts

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