Skip to content

Instantly share code, notes, and snippets.

@aloftin
Created November 16, 2021 13:33
Show Gist options
  • Select an option

  • Save aloftin/579bf29b0a8a1595fb9c4adb9b07f12a to your computer and use it in GitHub Desktop.

Select an option

Save aloftin/579bf29b0a8a1595fb9c4adb9b07f12a to your computer and use it in GitHub Desktop.
This is a simplified example of how struct tags can be used to mask data.
package main
import (
"encoding/json"
"fmt"
"log"
"os"
"reflect"
)
// Name of the struct tag used in examples
const tagName = "phi"
type User struct {
Id int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
SSN string `json:"ssn" phi:"XXX-XX-XXXX"`
}
func GetUsers() []User {
users := []User{
{Id: 1, Name: "John Smith", Email: "jsmith@test.com", SSN: "987-65-4321"},
{Id: 2, Name: "Jane Doe", Email: "jdoe@test.com", SSN: "123-45-6789"},
}
return users
}
func maskPHI(s interface{}) interface{} {
t := reflect.TypeOf(s)
unmasked := reflect.ValueOf(s)
// Make updatable copy of the struct in reflection land
masked := reflect.New(unmasked.Type()).Elem()
masked.Set(unmasked)
// Iterate over all available fields and read the tag value
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
value := masked.FieldByName(field.Name)
phiTagValue := field.Tag.Get(tagName)
if phiTagValue != "" {
// Overwrite the field value with the tag value
value.SetString(phiTagValue)
}
}
// Return as interface{} instead of struct type
return masked.Interface()
}
func main() {
users := GetUsers()
res := make([]User, 0, len(users))
for _, u := range users {
mu := maskPHI(u).(User) // masking underlying values on the User
res = append(res, mu)
}
out, err := json.MarshalIndent(res, "", " ")
if err != nil {
log.Println(err)
os.Exit(1)
}
fmt.Println(string(out))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment