From b2d96812c4969a08f9330a3fcba0b352f76e2beb Mon Sep 17 00:00:00 2001
From: Volker Schukai <volker.schukai@schukai.com>
Date: Sun, 16 Oct 2022 13:39:08 +0200
Subject: [PATCH] fix secure access to structure with a constraint

---
 get.go                          | 51 +++++++++++++++++++++++++++++++++
 pathfind.go => set.go           | 42 ++-------------------------
 pathfind_test.go => set_test.go |  0
 3 files changed, 54 insertions(+), 39 deletions(-)
 create mode 100644 get.go
 rename pathfind.go => set.go (75%)
 rename pathfind_test.go => set_test.go (100%)

diff --git a/get.go b/get.go
new file mode 100644
index 0000000..9fbd303
--- /dev/null
+++ b/get.go
@@ -0,0 +1,51 @@
+// Copyright 2022 schukai GmbH
+// SPDX-License-Identifier: AGPL-3.0
+
+package pathfinder
+
+import (
+	"reflect"
+	"strings"
+)
+
+// This function returns the value of a field in a struct, given a path to the field.
+func GetValue[D any](obj D, keyWithDots string) (any, error) {
+	keySlice := strings.Split(keyWithDots, ".")
+	v := reflect.ValueOf(obj)
+
+	for _, key := range keySlice[0 : len(keySlice)-1] {
+		for v.Kind() == reflect.Ptr {
+			if v.Kind() == reflect.Invalid {
+				return nil, newInvalidPathError(keyWithDots)
+			}
+			v = v.Elem()
+		}
+
+		if v.Kind() != reflect.Struct {
+			return nil, newUnsupportedTypePathError(keyWithDots, v.Type())
+		}
+
+		v = v.FieldByName(key)
+	}
+
+	if v.Kind() == reflect.Invalid {
+		return nil, newInvalidPathError(keyWithDots)
+	}
+
+	for v.Kind() == reflect.Ptr {
+		v = v.Elem()
+	}
+
+	// non-supporter type at the top of the path
+	if v.Kind() != reflect.Struct {
+		return nil, newUnsupportedTypeAtTopOfPathError(keyWithDots, v.Type())
+	}
+
+	v = v.FieldByName(keySlice[len(keySlice)-1])
+	if !v.IsValid() {
+		return nil, newInvalidPathError(keyWithDots)
+	}
+
+	return v.Interface(), nil
+
+}
diff --git a/pathfind.go b/set.go
similarity index 75%
rename from pathfind.go
rename to set.go
index 28adede..124f9fa 100644
--- a/pathfind.go
+++ b/set.go
@@ -10,45 +10,6 @@ import (
 	"strings"
 )
 
-// This function returns the value of a field in a struct, given a path to the field.
-func GetValue[D any](obj D, keyWithDots string) (any, error) {
-	keySlice := strings.Split(keyWithDots, ".")
-	v := reflect.ValueOf(obj)
-
-	for _, key := range keySlice[0 : len(keySlice)-1] {
-		for v.Kind() == reflect.Ptr {
-			v = v.Elem()
-		}
-
-		if v.Kind() != reflect.Struct {
-			return nil, newUnsupportedTypePathError(keyWithDots, v.Type())
-		}
-
-		v = v.FieldByName(key)
-	}
-
-	if v.Kind() == reflect.Invalid {
-		return nil, newInvalidPathError(keyWithDots)
-	}
-
-	for v.Kind() == reflect.Ptr {
-		v = v.Elem()
-	}
-
-	// non-supporter type at the top of the path
-	if v.Kind() != reflect.Struct {
-		return nil, newUnsupportedTypeAtTopOfPathError(keyWithDots, v.Type())
-	}
-
-	v = v.FieldByName(keySlice[len(keySlice)-1])
-	if !v.IsValid() {
-		return nil, newInvalidPathError(keyWithDots)
-	}
-
-	return v.Interface(), nil
-
-}
-
 // This function sets the value of a field in a struct, given a path to the field.
 func SetValue[D any](obj D, keyWithDots string, newValue any) error {
 
@@ -57,6 +18,9 @@ func SetValue[D any](obj D, keyWithDots string, newValue any) error {
 
 	for _, key := range keySlice[0 : len(keySlice)-1] {
 		for v.Kind() != reflect.Ptr {
+			if v.Kind() == reflect.Invalid {
+				return newInvalidPathError(keyWithDots)
+			}
 			v = v.Addr()
 		}
 
diff --git a/pathfind_test.go b/set_test.go
similarity index 100%
rename from pathfind_test.go
rename to set_test.go
-- 
GitLab