From 33b398847bc11c0e8d9147c8bb11817fd4564e2c Mon Sep 17 00:00:00 2001
From: Anton Sattarov <dirty.mew@gmail.com>
Date: Thu, 9 Nov 2023 08:40:05 +0100
Subject: [PATCH] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=BB?=
 =?UTF-8?q?=D0=B5=D0=BD=D0=B0=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BA=D0=B0=20?=
 =?UTF-8?q?=D0=BF=D1=80=D0=B8=20=D0=BA=D0=BE=D1=82=D0=BE=D1=80=D0=BE=D0=B9?=
 =?UTF-8?q?=20=D0=BF=D0=BE=D0=BB=D0=B5=20=D0=BD=D0=B5=20=D0=BF=D0=B5=D1=80?=
 =?UTF-8?q?=D0=B5=D0=B4=D0=B0=D0=B2=D0=B0=D0=BB=D0=B0=D1=81=D1=8C=20=D0=B2?=
 =?UTF-8?q?=20=D0=B4=D0=B0=D0=BD=D0=BD=D1=8B=D1=85=20=D0=B5=D1=81=D0=BB?=
 =?UTF-8?q?=D0=B8=20=D0=B2=20=D1=80=D0=BE=D0=BB=D0=B8=20=D0=BF=D0=BE=D0=BB?=
 =?UTF-8?q?=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D0=B5=D0=BB=D1=8F=20=D0=B4?=
 =?UTF-8?q?=D0=BB=D1=8F=20=D0=BD=D0=B5=D0=B3=D0=BE=20=D1=81=D1=83=D1=89?=
 =?UTF-8?q?=D0=B5=D1=81=D1=82=D0=B2=D0=BE=D0=B2=D0=B0=D0=BB=D0=B8=20=D0=BE?=
 =?UTF-8?q?=D0=B4=D0=BD=D0=BE=D0=B2=D1=80=D0=B5=D0=BC=D0=B5=D0=BD=D0=BD?=
 =?UTF-8?q?=D0=BE=20=D0=BF=D1=80=D0=B0=D0=B2=D0=B8=D0=BB=D0=B0=20=D0=BD?=
 =?UTF-8?q?=D0=B0=20=D0=B5=D0=B3=D0=BE=20=D1=87=D1=82=D0=B5=D0=BD=D0=B8?=
 =?UTF-8?q?=D0=B5=20=D0=B8=20=D0=B7=D0=B0=D0=BF=D0=B8=D1=81=D1=8C?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 pkg/permission/permission.go      | 10 ++----
 pkg/permission/permission_test.go | 60 +++++++++++++++++++++++++++++++
 pkg/permission/ruleset.go         |  6 ++--
 pkg/permission/ruleset_test.go    | 41 +++++++++++++++++++++
 4 files changed, 107 insertions(+), 10 deletions(-)
 create mode 100644 pkg/permission/permission_test.go

diff --git a/pkg/permission/permission.go b/pkg/permission/permission.go
index 7a90e507..e08579e9 100644
--- a/pkg/permission/permission.go
+++ b/pkg/permission/permission.go
@@ -53,12 +53,6 @@ func (p Permission) RemoveFields(in map[string]interface{}) map[string]interface
 	if in == nil {
 		return nil
 	}
-	out := make(map[string]interface{})
-	for k, v := range in {
-		if data.Contains(k, p.UnallowedFields) {
-			continue
-		}
-		out[k] = v
-	}
-	return out
+	data.DeleteMany(p.UnallowedFields, in)
+	return in
 }
diff --git a/pkg/permission/permission_test.go b/pkg/permission/permission_test.go
new file mode 100644
index 00000000..96f05ef5
--- /dev/null
+++ b/pkg/permission/permission_test.go
@@ -0,0 +1,60 @@
+package permission
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestPermission_RemoveFields(t *testing.T) {
+
+	tests := []struct {
+		name            string
+		unallowedFields []string
+		in              map[string]interface{}
+		want            map[string]interface{}
+	}{
+		{
+			name: "nil",
+			in:   nil,
+			want: nil,
+		},
+		{
+			name: "empty",
+			in:   map[string]interface{}{},
+			want: map[string]interface{}{},
+		},
+		{
+			name:            "empty unallowedFields",
+			in:              map[string]interface{}{"f": "v"},
+			want:            map[string]interface{}{"f": "v"},
+			unallowedFields: nil,
+		},
+		{
+			name:            "remove fields",
+			in:              map[string]interface{}{"f": "v", "f1": "v"},
+			want:            map[string]interface{}{"f": "v"},
+			unallowedFields: []string{"f1"},
+		},
+		{
+			name:            "no fields",
+			in:              map[string]interface{}{"f": "v", "f1": "v"},
+			want:            map[string]interface{}{"f": "v", "f1": "v"},
+			unallowedFields: []string{"f2"},
+		},
+		{
+			name:            "obj fields",
+			in:              map[string]interface{}{"obj": map[string]interface{}{"f": "v", "f1": "v"}},
+			want:            map[string]interface{}{"obj": map[string]interface{}{"f": "v"}},
+			unallowedFields: []string{"obj.f1"},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			p := Permission{
+				UnallowedFields: tt.unallowedFields,
+			}
+			assert.Equal(t, tt.want, p.RemoveFields(tt.in))
+		})
+	}
+}
diff --git a/pkg/permission/ruleset.go b/pkg/permission/ruleset.go
index b9a84f37..a915a055 100644
--- a/pkg/permission/ruleset.go
+++ b/pkg/permission/ruleset.go
@@ -127,12 +127,14 @@ func (r Rule) GetPermission(action Action) *Permission {
 			case ActionRead:
 				p.Filter = r.ReadFilter
 				p.UnallowedFields = append(p.UnallowedFields, r.HiddenFields...)
-				p.UnallowedFields = append(p.UnallowedFields, r.WriteonlyFields...)
+				p.UnallowedFields = append(p.UnallowedFields, data.Difference(r.WriteonlyFields, r.ReadonlyFields)...)
 			case ActionCreate, ActionUpdate, ActionDelete:
 				p.Filter = r.WriteFilter
-				p.UnallowedFields = append(p.UnallowedFields, r.ReadonlyFields...)
+				p.UnallowedFields = append(p.UnallowedFields, data.Difference(r.ReadonlyFields, r.WriteonlyFields)...)
 			}
 
+			p.UnallowedFields = data.SetFromSlice(p.UnallowedFields)
+
 			return p
 		}
 	}
diff --git a/pkg/permission/ruleset_test.go b/pkg/permission/ruleset_test.go
index 47c1f076..a0575384 100644
--- a/pkg/permission/ruleset_test.go
+++ b/pkg/permission/ruleset_test.go
@@ -49,3 +49,44 @@ func TestMerge(t *testing.T) {
 		})
 	}
 }
+
+func TestRule_GetPermission(t *testing.T) {
+	tests := []struct {
+		name            string
+		action          Action
+		rule            Rule
+		unallowedFields []string
+		want            *Permission
+	}{
+		{
+			name:            "ActionRead",
+			action:          ActionRead,
+			rule:            Rule{Actions: []Action{ActionRead, ActionUpdate}, ReadonlyFields: []string{"f1"}, HiddenFields: []string{"f2"}, WriteonlyFields: []string{"f3"}},
+			unallowedFields: []string{"f2", "f3"},
+		},
+		{
+			name:            "ActionRead readonly&writeonly",
+			action:          ActionRead,
+			rule:            Rule{Actions: []Action{ActionRead, ActionUpdate}, ReadonlyFields: []string{"f1"}, HiddenFields: []string{"f2"}, WriteonlyFields: []string{"f1"}},
+			unallowedFields: []string{"f2"},
+		},
+		{
+			name:            "ActionUpdate",
+			action:          ActionUpdate,
+			rule:            Rule{Actions: []Action{ActionRead, ActionUpdate}, ReadonlyFields: []string{"f1"}, HiddenFields: []string{"f2"}, WriteonlyFields: []string{"f3"}},
+			unallowedFields: []string{"f1"},
+		},
+		{
+			name:            "ActionUpdate readonly&writeonly",
+			action:          ActionUpdate,
+			rule:            Rule{Actions: []Action{ActionRead, ActionUpdate}, ReadonlyFields: []string{"f1"}, HiddenFields: []string{"f2"}, WriteonlyFields: []string{"f1"}},
+			unallowedFields: []string{},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			p := tt.rule.GetPermission(tt.action)
+			assert.ElementsMatch(t, tt.unallowedFields, p.UnallowedFields)
+		})
+	}
+}
-- 
GitLab