From eb0d378523031452658bd9577c7ddcf617baaad4 Mon Sep 17 00:00:00 2001 From: jolheiser Date: Mon, 26 Sep 2022 13:37:53 -0500 Subject: [PATCH] Add example and small CLI Signed-off-by: jolheiser --- cmd/confage/main.go | 23 +++++++++++ confage.go | 22 ++++++---- confage_example_test.go | 38 +++++++++++++++++ confage_test.go | 91 ++++++++++++++++++++++++++++++++--------- 4 files changed, 147 insertions(+), 27 deletions(-) create mode 100644 cmd/confage/main.go create mode 100644 confage_example_test.go diff --git a/cmd/confage/main.go b/cmd/confage/main.go new file mode 100644 index 0000000..40f8f76 --- /dev/null +++ b/cmd/confage/main.go @@ -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()) +} diff --git a/confage.go b/confage.go index ff8aafa..f48afb2 100644 --- a/confage.go +++ b/confage.go @@ -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 } diff --git a/confage_example_test.go b/confage_example_test.go new file mode 100644 index 0000000..a7161cb --- /dev/null +++ b/confage_example_test.go @@ -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=" +}`) diff --git a/confage_test.go b/confage_test.go index f78099e..5bb2291 100644 --- a/confage_test.go +++ b/confage_test.go @@ -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