forked from baron/baron-sso
audit 로그 개선. kratos 코드발급 링크로 전송까지 진행 완료 #104
This commit is contained in:
79
backend/internal/utils/masking.go
Normal file
79
backend/internal/utils/masking.go
Normal file
@@ -0,0 +1,79 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var sensitiveKeys = map[string]struct{}{
|
||||
"password": {},
|
||||
"newpassword": {},
|
||||
"oldpassword": {},
|
||||
"token": {},
|
||||
"accesstoken": {},
|
||||
"access_token": {},
|
||||
"refreshtoken": {},
|
||||
"refresh_token": {},
|
||||
"secret": {},
|
||||
"clientsecret": {},
|
||||
"client_secret": {},
|
||||
"authorization": {},
|
||||
"cookie": {},
|
||||
"set-cookie": {},
|
||||
"verificationcode": {},
|
||||
"verification_code": {},
|
||||
"code": {}, // Auth code (sensitive)
|
||||
}
|
||||
|
||||
// MaskSensitiveJSON parses a JSON byte slice and masks values of sensitive keys.
|
||||
// Returns the original data if it's not valid JSON.
|
||||
func MaskSensitiveJSON(data []byte) []byte {
|
||||
if len(data) == 0 {
|
||||
return data
|
||||
}
|
||||
|
||||
var obj interface{}
|
||||
if err := json.Unmarshal(data, &obj); err != nil {
|
||||
// Not a JSON object/array, return as is
|
||||
return data
|
||||
}
|
||||
|
||||
masked := maskValue(obj)
|
||||
|
||||
result, err := json.Marshal(masked)
|
||||
if err != nil {
|
||||
return data
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func maskValue(v interface{}) interface{} {
|
||||
switch val := v.(type) {
|
||||
case map[string]interface{}:
|
||||
newMap := make(map[string]interface{}, len(val))
|
||||
for k, v := range val {
|
||||
if isSensitive(k) {
|
||||
newMap[k] = "*****"
|
||||
} else {
|
||||
newMap[k] = maskValue(v)
|
||||
}
|
||||
}
|
||||
return newMap
|
||||
case []interface{}:
|
||||
newArr := make([]interface{}, len(val))
|
||||
for i, v := range val {
|
||||
newArr[i] = maskValue(v)
|
||||
}
|
||||
return newArr
|
||||
default:
|
||||
return val
|
||||
}
|
||||
}
|
||||
|
||||
func isSensitive(key string) bool {
|
||||
// Check case-insensitive
|
||||
// Remove common separators for looser matching? No, stick to lowercase check for now.
|
||||
k := strings.ToLower(key)
|
||||
_, ok := sensitiveKeys[k]
|
||||
return ok
|
||||
}
|
||||
59
backend/internal/utils/masking_test.go
Normal file
59
backend/internal/utils/masking_test.go
Normal file
@@ -0,0 +1,59 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestMaskSensitiveJSON(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
expected string // We'll check containment or specific structure
|
||||
}{
|
||||
{
|
||||
name: "Flat object with password",
|
||||
input: `{"username": "user", "password": "secret123"}`,
|
||||
expected: `{"password":"*****","username":"user"}`,
|
||||
},
|
||||
{
|
||||
name: "Nested object with token",
|
||||
input: `{"data": {"token": "abc-def", "id": 123}}`,
|
||||
expected: `{"data":{"id":123,"token":"*****"}}`,
|
||||
},
|
||||
{
|
||||
name: "Case insensitive key",
|
||||
input: `{"NewPassword": "changed"}`,
|
||||
expected: `{"NewPassword":"*****"}`,
|
||||
},
|
||||
{
|
||||
name: "Array of objects",
|
||||
input: `[{"secret": "s1"}, {"secret": "s2"}]`,
|
||||
expected: `[{"secret":"*****"},{"secret":"*****"}]`,
|
||||
},
|
||||
{
|
||||
name: "Invalid JSON",
|
||||
input: `not-json`,
|
||||
expected: `not-json`,
|
||||
},
|
||||
{
|
||||
name: "Empty JSON",
|
||||
input: ``,
|
||||
expected: ``,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := MaskSensitiveJSON([]byte(tt.input))
|
||||
// Since JSON map order is undefined, exact string match might fail if keys are reordered.
|
||||
// Ideally we should unmarshal and compare maps, or use assert.JSONEq
|
||||
if tt.name == "Invalid JSON" || tt.name == "Empty JSON" {
|
||||
assert.Equal(t, tt.expected, string(result))
|
||||
} else {
|
||||
assert.JSONEq(t, tt.expected, string(result))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user