first commit

This commit is contained in:
Awuqing
2026-03-17 13:29:09 +08:00
commit eadd3f8961
219 changed files with 22394 additions and 0 deletions

View File

@@ -0,0 +1,155 @@
package codec
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"crypto/sha256"
"encoding/base64"
"encoding/json"
"fmt"
"io"
)
const maskedValue = "********"
type ConfigCipher struct {
key []byte
}
type Cipher = ConfigCipher
func New(secret string) *ConfigCipher {
hash := sha256.Sum256([]byte(secret))
return &ConfigCipher{key: hash[:]}
}
func NewConfigCipher(secret string) *ConfigCipher {
return New(secret)
}
func (c *ConfigCipher) Key() []byte {
copyKey := make([]byte, len(c.key))
copy(copyKey, c.key)
return copyKey
}
func (c *ConfigCipher) Encrypt(raw []byte) (string, error) {
block, err := aes.NewCipher(c.key)
if err != nil {
return "", fmt.Errorf("create cipher: %w", err)
}
gcm, err := cipher.NewGCM(block)
if err != nil {
return "", fmt.Errorf("create gcm: %w", err)
}
nonce := make([]byte, gcm.NonceSize())
if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
return "", fmt.Errorf("generate nonce: %w", err)
}
sealed := gcm.Seal(nonce, nonce, raw, nil)
return base64.RawURLEncoding.EncodeToString(sealed), nil
}
func (c *ConfigCipher) Decrypt(encoded string) ([]byte, error) {
payload, err := base64.RawURLEncoding.DecodeString(encoded)
if err != nil {
return nil, fmt.Errorf("decode ciphertext: %w", err)
}
block, err := aes.NewCipher(c.key)
if err != nil {
return nil, fmt.Errorf("create cipher: %w", err)
}
gcm, err := cipher.NewGCM(block)
if err != nil {
return nil, fmt.Errorf("create gcm: %w", err)
}
if len(payload) < gcm.NonceSize() {
return nil, fmt.Errorf("ciphertext too short")
}
nonce, ciphertext := payload[:gcm.NonceSize()], payload[gcm.NonceSize():]
plain, err := gcm.Open(nil, nonce, ciphertext, nil)
if err != nil {
return nil, fmt.Errorf("decrypt ciphertext: %w", err)
}
return plain, nil
}
func (c *ConfigCipher) EncryptJSON(value any) (string, error) {
plain, err := json.Marshal(value)
if err != nil {
return "", fmt.Errorf("marshal plaintext: %w", err)
}
return c.Encrypt(plain)
}
func (c *ConfigCipher) DecryptJSON(encoded string, out any) error {
plain, err := c.Decrypt(encoded)
if err != nil {
return err
}
if err := json.Unmarshal(plain, out); err != nil {
return fmt.Errorf("unmarshal plaintext: %w", err)
}
return nil
}
func (c *ConfigCipher) EncryptValue(value any) (string, error) {
return c.EncryptJSON(value)
}
func (c *ConfigCipher) DecryptValue(encoded string, out any) error {
return c.DecryptJSON(encoded, out)
}
func MaskConfig(raw map[string]any, sensitiveFields []string) map[string]any {
masked := cloneMap(raw)
for _, field := range sensitiveFields {
value, ok := masked[field]
if !ok {
continue
}
switch actual := value.(type) {
case string:
if actual != "" {
masked[field] = maskedValue
}
default:
masked[field] = maskedValue
}
}
return masked
}
func MergeMaskedConfig(next map[string]any, existing map[string]any, sensitiveFields []string) map[string]any {
merged := cloneMap(existing)
for key, value := range next {
merged[key] = value
}
for _, field := range sensitiveFields {
value, ok := merged[field]
if !ok {
continue
}
switch actual := value.(type) {
case string:
if actual == "" || actual == maskedValue {
merged[field] = existing[field]
}
}
}
return merged
}
func IsMaskedString(value string) bool {
return bytes.Equal([]byte(value), []byte(maskedValue))
}
func cloneMap(source map[string]any) map[string]any {
result := make(map[string]any, len(source))
for key, value := range source {
result[key] = value
}
return result
}

View File

@@ -0,0 +1,64 @@
package codec
import (
"bytes"
"testing"
)
func TestCipherEncryptAndDecrypt(t *testing.T) {
cipher := New("encryption-secret")
input := map[string]any{
"endpoint": "https://example.com",
"secret": "top-secret",
}
encoded, err := cipher.EncryptValue(input)
if err != nil {
t.Fatalf("EncryptValue returned error: %v", err)
}
var output map[string]any
if err := cipher.DecryptValue(encoded, &output); err != nil {
t.Fatalf("DecryptValue returned error: %v", err)
}
if output["secret"] != "top-secret" {
t.Fatalf("expected decrypted secret, got %#v", output["secret"])
}
}
func TestConfigCipherEncryptAndDecryptBytes(t *testing.T) {
cipher := NewConfigCipher("encryption-secret")
encoded, err := cipher.Encrypt([]byte(`{"bucket":"demo"}`))
if err != nil {
t.Fatalf("Encrypt returned error: %v", err)
}
decoded, err := cipher.Decrypt(encoded)
if err != nil {
t.Fatalf("Decrypt returned error: %v", err)
}
if !bytes.Equal(decoded, []byte(`{"bucket":"demo"}`)) {
t.Fatalf("expected decrypted payload to match, got %s", string(decoded))
}
}
func TestMaskConfig(t *testing.T) {
masked := MaskConfig(map[string]any{"secret": "abc", "bucket": "demo"}, []string{"secret"})
if masked["secret"] != "********" {
t.Fatalf("expected masked secret, got %#v", masked["secret"])
}
if masked["bucket"] != "demo" {
t.Fatalf("expected bucket to remain unchanged")
}
}
func TestMergeMaskedConfig(t *testing.T) {
merged := MergeMaskedConfig(
map[string]any{"bucket": "changed", "secret": "********"},
map[string]any{"bucket": "demo", "secret": "top-secret"},
[]string{"secret"},
)
if merged["bucket"] != "changed" {
t.Fatalf("expected bucket to use new value, got %#v", merged["bucket"])
}
if merged["secret"] != "top-secret" {
t.Fatalf("expected masked secret to reuse stored value, got %#v", merged["secret"])
}
}