Skip to content

Instantly share code, notes, and snippets.

@hosszukalman
Created February 14, 2020 11:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hosszukalman/0a6b9226a3bf380fc6bf8a1e7b96a937 to your computer and use it in GitHub Desktop.
Save hosszukalman/0a6b9226a3bf380fc6bf8a1e7b96a937 to your computer and use it in GitHub Desktop.
A POC for permission based field writing in Golang
package main
import (
"encoding/json"
"fmt"
"reflect"
)
type User struct {
Permissions []string
}
func (u User) HasPermission(perm string) bool {
for _, p := range u.Permissions {
if p == perm {
return true
}
}
return false
}
type WriteTest struct {
PublicField string `json:"public_field"`
LimitedWrite string `json:"limited_write" writepermission:"limited.write"`
WriteEmbed WriteEmbed
}
type WriteEmbed struct {
PublicField string
LimitedWrite string `json:"limited_write" writepermission:"limited.write"`
}
type WriteEmbedEmbed struct {
PublicField string
LimitedWrite string `json:"limited_write" writepermission:"limited.write"`
}
func MergeStructs(mergeTo interface{}, mergeFrom map[string]interface{}, u User, tag string) {
var typ reflect.Type
var val reflect.Value
if reflect.TypeOf(mergeTo).Kind() == reflect.Ptr {
typ = reflect.TypeOf(mergeTo).Elem()
val = reflect.ValueOf(mergeTo).Elem()
} else {
typ = reflect.TypeOf(mergeTo)
val = reflect.ValueOf(mergeTo)
}
var mergeData func(t reflect.Type, v reflect.Value, mergeFrom map[string]interface{}, u User, tag string)
mergeData = func(t reflect.Type, v reflect.Value, mergeFrom map[string]interface{}, u User, tag string) {
for i := 0; i < v.NumField(); i++ {
fieldVal := v.Field(i)
fieldTyp := t.Field(i)
if fieldVal.CanSet() {
mapString := fieldTyp.Name
if byTag := fieldTyp.Tag.Get(tag); tag != "" && byTag != "" {
mapString = byTag
}
if mapVal, found := mergeFrom[mapString]; found {
if fieldVal.Kind() == reflect.Struct {
if mapInterface, ok := mapVal.(map[string]interface{}); ok {
mergeData(fieldTyp.Type, fieldVal, mapInterface, u, tag)
}
} else if perm := fieldTyp.Tag.Get("writepermission"); perm == "" || (perm != "" && u.HasPermission(perm)) {
fieldVal.Set(reflect.ValueOf(mapVal))
}
}
}
}
}
mergeData(typ, val, mergeFrom, u, tag)
}
func main() {
wt := WriteTest{
PublicField: "This is public",
LimitedWrite: "This is limited write",
}
wstring := []byte(`{
"public_field": "public",
"limited_write": "limited",
"WriteEmbed": {
"PublicField": "This is public",
"limited_write": "limited",
"WriteEmbedEmbed": {
"PublicField": "This is public",
"limited_write": "limited"
}
}
}`)
var mapInterface map[string]interface{}
if err := json.Unmarshal(wstring, &mapInterface); err != nil {
panic(err)
}
u4 := User{}
u5 := User{[]string{"limited.write"}}
fmt.Printf("Original: %#v\n", wt)
fmt.Printf("Map: %#v\n", mapInterface)
MergeStructs(&wt, mapInterface, u4, "json")
fmt.Printf("\nAfter merge with no permission: %#v\n\n", wt)
MergeStructs(&wt, mapInterface, u5, "json")
fmt.Printf("After merge with write permission: %#v\n\n", wt)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment