Add example and small CLI

Signed-off-by: jolheiser <john.olheiser@gmail.com>
main v0.0.2
jolheiser 2022-09-26 13:37:53 -05:00
parent fcfe79244f
commit eb0d378523
Signed by: jolheiser
GPG Key ID: B853ADA5DA7BBF7A
4 changed files with 147 additions and 27 deletions

View File

@ -0,0 +1,23 @@
package main
import (
"flag"
"fmt"
"os"
"go.jolheiser.com/confage"
)
func main() {
fs := flag.NewFlagSet("confage", flag.ExitOnError)
secretKeyFlag := fs.String("secret-key", "", "Age secret key")
fs.StringVar(secretKeyFlag, "s", *secretKeyFlag, "--secret-key")
if err := fs.Parse(os.Args[1:]); err != nil {
panic(err)
}
t := confage.MustNew(*secretKeyFlag, fs.Arg(0))
fmt.Println(t.String())
}

View File

@ -38,8 +38,7 @@ func New[T any](key string, val T) (v Type[T], err error) {
if err != nil {
return v, err
}
i = ii
r = ii.Recipient()
i, r = ii, ii.Recipient()
default:
i, err = age.NewScryptIdentity(key)
if err != nil {
@ -65,40 +64,47 @@ func (t Type[T]) String() string {
}
// MarshalText implements encoding.MarshalText
func (v Type[T]) MarshalText() ([]byte, error) {
func (t Type[T]) MarshalText() ([]byte, error) {
var b bytes.Buffer
w, err := age.Encrypt(&b, v.r)
w, err := age.Encrypt(&b, t.r)
if err != nil {
return nil, err
}
if err := json.NewEncoder(w).Encode(v.Value); err != nil {
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 (v *Type[T]) UnmarshalText(text []byte) error {
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), v.i)
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
}
(*v).Value = val
(*t).Value = val
return nil
}

View File

@ -0,0 +1,38 @@
package confage_test
import (
"encoding/json"
"fmt"
"go.jolheiser.com/confage"
)
func Example_config() {
const secretKey = "AGE-SECRET-KEY-1AN83H8JECDKHSD2RN70WU8RQYYH3C309UUYQQ0EPQNJR3ZXRDHESTUCCM4" // age1ynmpzgvrqj3r6z39kp3p852afe3nkc3neem80vgq96jt2zhesezq8yhn02
cfg := &Config{
Password: confage.MustNew(secretKey, ""),
}
if err := json.Unmarshal(config, &cfg); err != nil {
panic(err)
}
fmt.Println(cfg.Password.Value)
// Output:
// bar
}
// Example config struct
type Config struct {
Username string
Password confage.Type[string]
}
// config.json living on disk
var config = []byte(`{
"username": "foo",
"password": "YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB0b3pzdTVtcnBBUFV3bnNsa2RIYlhTVGVYeXlHcHpIbEpMR3ZwcWxHMmtjClc5ald4MHZhdFFKY3NmS0R5bFpXY1VGa1RKeWxHaGVzR3FhS1B1NHgydUkKLS0tIEJYRnhMNm12aE14bUU5bGNPVFBJcHBWZDJBeWFMMVdMUGdyVXErOVFuaWsK3F0DfPH+Ud50XIBoDR2D/+/PMoqNp9O2R6BdBLTLyiENJYrxGxo="
}`)

View File

@ -7,29 +7,82 @@ import (
"github.com/matryer/is"
)
func TestTypeScrypt(t *testing.T) {
assert := is.New(t)
const (
passphrase = "passphrase"
secretKey = "AGE-SECRET-KEY-1F7SU7MXLVHU0SWQ3L2ZMW7G2NN2YTH88NLU6LVDHENTZLMCT3M5S799RDK"
)
enc := MustNew("passphrase", 0)
enc.Value = 100
type Struct struct {
String string
Int int
Bool bool
}
func TestType(t *testing.T) {
t.Run("string", func(t *testing.T) {
assert := is.New(t)
val := "foo"
testEncryption(assert, passphrase, val)
testEncryption(assert, secretKey, val)
})
t.Run("int", func(t *testing.T) {
assert := is.New(t)
val := 123
testEncryption(assert, passphrase, val)
testEncryption(assert, secretKey, val)
})
t.Run("bool", func(t *testing.T) {
assert := is.New(t)
val := true
testEncryption(assert, passphrase, val)
testEncryption(assert, secretKey, val)
})
t.Run("map", func(t *testing.T) {
assert := is.New(t)
val := map[string]any{
"foo": "bar",
"baz": 123.0,
"bux": false,
}
testEncryption(assert, passphrase, val)
testEncryption(assert, secretKey, val)
})
t.Run("struct", func(t *testing.T) {
assert := is.New(t)
val := Struct{
String: "string",
Int: 123,
Bool: true,
}
testEncryption(assert, passphrase, val)
testEncryption(assert, secretKey, val)
})
t.Run("pointer", func(t *testing.T) {
assert := is.New(t)
val := &Struct{
String: "string",
Int: 123,
Bool: true,
}
testEncryption(assert, passphrase, val)
testEncryption(assert, secretKey, val)
})
}
func testEncryption[T any](assert *is.I, key string, value T) {
assert.Helper()
enc := MustNew(key, value)
payload, err := json.Marshal(enc)
assert.NoErr(err) // Should be able to marshal JSON
dec := MustNew("passphrase", 0)
err = json.Unmarshal(payload, &dec)
assert.NoErr(err) // Should be able to unmarshal JSON
assert.Equal(enc.Value, dec.Value) // Values should match
}
func TestTypeX25519(t *testing.T) {
assert := is.New(t)
enc := MustNew("AGE-SECRET-KEY-1F7SU7MXLVHU0SWQ3L2ZMW7G2NN2YTH88NLU6LVDHENTZLMCT3M5S799RDK", 100)
payload, err := json.Marshal(enc)
assert.NoErr(err) // Should be able to marshal JSON
dec := MustNew("AGE-SECRET-KEY-1F7SU7MXLVHU0SWQ3L2ZMW7G2NN2YTH88NLU6LVDHENTZLMCT3M5S799RDK", 0)
var t T
dec := MustNew(key, t)
err = json.Unmarshal(payload, &dec)
assert.NoErr(err) // Should be able to unmarshal JSON