111 lines
2.0 KiB
Go
111 lines
2.0 KiB
Go
package confage
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/base64"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"strings"
|
|
|
|
"filippo.io/age"
|
|
)
|
|
|
|
// Type is a config type
|
|
type Type[T any] struct {
|
|
i age.Identity
|
|
r age.Recipient
|
|
Value T
|
|
}
|
|
|
|
// MustNew returns a new Type, panicking on error
|
|
func MustNew[T any](key string, val T) Type[T] {
|
|
t, err := New(key, val)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return t
|
|
}
|
|
|
|
// New returns a new Type
|
|
func New[T any](key string, val T) (v Type[T], err error) {
|
|
v.Value = val
|
|
var i age.Identity
|
|
var r age.Recipient
|
|
switch {
|
|
case strings.HasPrefix(key, "AGE-SECRET-KEY-1"):
|
|
ii, err := age.ParseX25519Identity(key)
|
|
if err != nil {
|
|
return v, err
|
|
}
|
|
i, r = ii, ii.Recipient()
|
|
default:
|
|
i, err = age.NewScryptIdentity(key)
|
|
if err != nil {
|
|
return v, err
|
|
}
|
|
r, err = age.NewScryptRecipient(key)
|
|
if err != nil {
|
|
return v, err
|
|
}
|
|
}
|
|
v.i, v.r = i, r
|
|
return v, nil
|
|
}
|
|
|
|
// String implements fmt.Stringer
|
|
// It simply returns MarshalText
|
|
func (t Type[T]) String() string {
|
|
b, err := t.MarshalText()
|
|
if err != nil {
|
|
return fmt.Sprintf("string error: %v", err)
|
|
}
|
|
return string(b)
|
|
}
|
|
|
|
// MarshalText implements encoding.MarshalText
|
|
func (t Type[T]) MarshalText() ([]byte, error) {
|
|
var b bytes.Buffer
|
|
w, err := age.Encrypt(&b, t.r)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if err := json.NewEncoder(w).Encode(t.Value); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if err := w.Close(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
out := base64.StdEncoding.EncodeToString(b.Bytes())
|
|
return []byte(out), nil
|
|
}
|
|
|
|
// UnmarshalText implements encoding.UnmarshalText
|
|
func (t *Type[T]) UnmarshalText(text []byte) error {
|
|
b, err := base64.StdEncoding.DecodeString(string(text))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
r, err := age.Decrypt(bytes.NewBuffer(b), t.i)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
var out bytes.Buffer
|
|
if _, err := io.Copy(&out, r); err != nil {
|
|
return err
|
|
}
|
|
|
|
var val T
|
|
if err := json.Unmarshal(out.Bytes(), &val); err != nil {
|
|
return err
|
|
}
|
|
|
|
(*t).Value = val
|
|
return nil
|
|
}
|