|
@@ -1,6 +1,7 @@
|
|
|
package permlib
|
|
package permlib
|
|
|
|
|
|
|
|
import (
|
|
import (
|
|
|
|
|
+ "bytes"
|
|
|
"context"
|
|
"context"
|
|
|
"encoding/json"
|
|
"encoding/json"
|
|
|
"fmt"
|
|
"fmt"
|
|
@@ -89,17 +90,21 @@ func (e *Engine) resolveDataCode(req *http.Request, apiCode string) string {
|
|
|
func (e *Engine) hasRespFilter(req *http.Request) bool {
|
|
func (e *Engine) hasRespFilter(req *http.Request) bool {
|
|
|
key := req.Method + " " + req.URL.Path
|
|
key := req.Method + " " + req.URL.Path
|
|
|
if fm, ok := e.fieldPerms[key]; ok {
|
|
if fm, ok := e.fieldPerms[key]; ok {
|
|
|
- return len(fm.Response) > 0
|
|
|
|
|
|
|
+ return fm.Response != nil && (len(fm.Response.Fields) > 0 || len(fm.Response.Nested) > 0)
|
|
|
}
|
|
}
|
|
|
return false
|
|
return false
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
func (e *Engine) filterRequest(req *http.Request, perms []string) (*http.Request, bool) {
|
|
func (e *Engine) filterRequest(req *http.Request, perms []string) (*http.Request, bool) {
|
|
|
key := req.Method + " " + req.URL.Path
|
|
key := req.Method + " " + req.URL.Path
|
|
|
- if fm, ok := e.fieldPerms[key]; ok && len(fm.Request) > 0 {
|
|
|
|
|
- return filterRequestByMap(req, fm.Request, perms, e.cfg.FieldWriteMode)
|
|
|
|
|
|
|
+ fm, ok := e.fieldPerms[key]
|
|
|
|
|
+ if !ok || fm.Request == nil {
|
|
|
|
|
+ return req, false
|
|
|
}
|
|
}
|
|
|
- return req, false
|
|
|
|
|
|
|
+ if len(fm.Request.Fields) == 0 && len(fm.Request.Nested) == 0 {
|
|
|
|
|
+ return req, false
|
|
|
|
|
+ }
|
|
|
|
|
+ return filterRequestByNode(req, fm.Request, perms, e.cfg.FieldWriteMode)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
func (e *Engine) verifyAndGetUser(ctx context.Context, token string) (*cachedUser, error) {
|
|
func (e *Engine) verifyAndGetUser(ctx context.Context, token string) (*cachedUser, error) {
|
|
@@ -140,7 +145,7 @@ func containsPerm(perms []string, code string) bool {
|
|
|
return false
|
|
return false
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-func filterRequestByMap(req *http.Request, fieldMap map[string]string, perms []string, mode FieldWriteMode) (*http.Request, bool) {
|
|
|
|
|
|
|
+func filterRequestByNode(req *http.Request, node *FieldNode, perms []string, mode FieldWriteMode) (*http.Request, bool) {
|
|
|
if req.Body == nil {
|
|
if req.Body == nil {
|
|
|
return req, false
|
|
return req, false
|
|
|
}
|
|
}
|
|
@@ -157,18 +162,94 @@ func filterRequestByMap(req *http.Request, fieldMap map[string]string, perms []s
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
permSet := toPermSet(perms)
|
|
permSet := toPermSet(perms)
|
|
|
- for jsonField, permCode := range fieldMap {
|
|
|
|
|
- if _, has := obj[jsonField]; has && !permSet[permCode] {
|
|
|
|
|
- if mode == FieldWriteReject {
|
|
|
|
|
- restoreBody(req, body)
|
|
|
|
|
- return req, true
|
|
|
|
|
- }
|
|
|
|
|
- delete(obj, jsonField)
|
|
|
|
|
|
|
+
|
|
|
|
|
+ if mode == FieldWriteReject {
|
|
|
|
|
+ if hasUnauthorizedField(obj, node, permSet) {
|
|
|
|
|
+ restoreBody(req, body)
|
|
|
|
|
+ return req, true
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- filtered, _ := json.Marshal(obj)
|
|
|
|
|
- restoreBody(req, filtered)
|
|
|
|
|
- req.ContentLength = int64(len(filtered))
|
|
|
|
|
|
|
+ filtered := filterRequestObject(obj, node, permSet)
|
|
|
|
|
+ result, _ := json.Marshal(filtered)
|
|
|
|
|
+ restoreBody(req, result)
|
|
|
|
|
+ req.ContentLength = int64(len(result))
|
|
|
return req, false
|
|
return req, false
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+func hasUnauthorizedField(obj map[string]json.RawMessage, node *FieldNode, permSet map[string]bool) bool {
|
|
|
|
|
+ for jsonName, permCode := range node.Fields {
|
|
|
|
|
+ if _, has := obj[jsonName]; has && !permSet[permCode] {
|
|
|
|
|
+ return true
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ for jsonName, child := range node.Nested {
|
|
|
|
|
+ v, ok := obj[jsonName]
|
|
|
|
|
+ if !ok {
|
|
|
|
|
+ continue
|
|
|
|
|
+ }
|
|
|
|
|
+ v = bytes.TrimSpace(v)
|
|
|
|
|
+ if len(v) == 0 {
|
|
|
|
|
+ continue
|
|
|
|
|
+ }
|
|
|
|
|
+ if v[0] == '{' {
|
|
|
|
|
+ var nested map[string]json.RawMessage
|
|
|
|
|
+ if json.Unmarshal(v, &nested) == nil {
|
|
|
|
|
+ if hasUnauthorizedField(nested, child, permSet) {
|
|
|
|
|
+ return true
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ } else if v[0] == '[' {
|
|
|
|
|
+ var arr []json.RawMessage
|
|
|
|
|
+ if json.Unmarshal(v, &arr) == nil {
|
|
|
|
|
+ for _, item := range arr {
|
|
|
|
|
+ var nested map[string]json.RawMessage
|
|
|
|
|
+ if json.Unmarshal(item, &nested) == nil {
|
|
|
|
|
+ if hasUnauthorizedField(nested, child, permSet) {
|
|
|
|
|
+ return true
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return false
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func filterRequestObject(obj map[string]json.RawMessage, node *FieldNode, permSet map[string]bool) map[string]json.RawMessage {
|
|
|
|
|
+ for jsonName, permCode := range node.Fields {
|
|
|
|
|
+ if _, has := obj[jsonName]; has && !permSet[permCode] {
|
|
|
|
|
+ delete(obj, jsonName)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ for jsonName, child := range node.Nested {
|
|
|
|
|
+ v, ok := obj[jsonName]
|
|
|
|
|
+ if !ok {
|
|
|
|
|
+ continue
|
|
|
|
|
+ }
|
|
|
|
|
+ v = bytes.TrimSpace(v)
|
|
|
|
|
+ if len(v) == 0 {
|
|
|
|
|
+ continue
|
|
|
|
|
+ }
|
|
|
|
|
+ if v[0] == '{' {
|
|
|
|
|
+ var nested map[string]json.RawMessage
|
|
|
|
|
+ if json.Unmarshal(v, &nested) == nil {
|
|
|
|
|
+ nested = filterRequestObject(nested, child, permSet)
|
|
|
|
|
+ obj[jsonName], _ = json.Marshal(nested)
|
|
|
|
|
+ }
|
|
|
|
|
+ } else if v[0] == '[' {
|
|
|
|
|
+ var arr []json.RawMessage
|
|
|
|
|
+ if json.Unmarshal(v, &arr) == nil {
|
|
|
|
|
+ for i, item := range arr {
|
|
|
|
|
+ var nested map[string]json.RawMessage
|
|
|
|
|
+ if json.Unmarshal(item, &nested) == nil {
|
|
|
|
|
+ nested = filterRequestObject(nested, child, permSet)
|
|
|
|
|
+ arr[i], _ = json.Marshal(nested)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ obj[jsonName], _ = json.Marshal(arr)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return obj
|
|
|
|
|
+}
|