diff --git a/modules/lagoon/README.md b/modules/lagoon/README.md index 74036f6..deba1c0 100644 --- a/modules/lagoon/README.md +++ b/modules/lagoon/README.md @@ -148,6 +148,7 @@ func (p *Plugin) Migrations() []*gormigrate.Migration { | `lagoon.FrameworkSchedule` | The framework's scheduled commands for conga: the daily `deferred:purge` at `database.deferred_bindings.purge_at`, or none when it is empty. | | `lagoon.FrameworkScheduleID` | Plugin id the framework's schedule entries are listed under, `summercms.lagoon`. | | `lagoon.KeyGenerateCommand` | Returns the key:generate command on its own. | +| `lagoon.GenerateAppKey` | Returns a fresh 32-byte base64 `app.key`, the value key:generate prints, for tools that write it into a file. | | `lagoon.LoadAppKey` | Decodes `app.key` and `app.previous_keys`. | | `lagoon.PublishEncryptionKeys` | Installs the keys used by `lagoon.Encrypted` columns. | | `lagoon.Encrypted` | Encrypted text column; `lagoon.Encrypted.Reveal` is the only plaintext accessor. | diff --git a/modules/lagoon/keygen.go b/modules/lagoon/keygen.go index e575cbe..a37ae6e 100644 --- a/modules/lagoon/keygen.go +++ b/modules/lagoon/keygen.go @@ -8,6 +8,17 @@ import ( "git.golem15.com/golem15/summercms/modules/bonfire" ) +// GenerateAppKey returns a fresh app.key: 32 random bytes from crypto/rand, +// base64 (standard encoding) encoded, 44 characters. It is the value +// key:generate prints, without the output decoration. +func GenerateAppKey() (string, error) { + key := make([]byte, encryptedKeySize) + if _, err := rand.Read(key); err != nil { + return "", err + } + return base64.StdEncoding.EncodeToString(key), nil +} + // KeyGenerateCommand prints a fresh 32-byte base64 app.key and performs no // other side effect (D-11). func KeyGenerateCommand() bonfire.Command { @@ -15,11 +26,11 @@ func KeyGenerateCommand() bonfire.Command { Name: "key:generate", Description: "Print a fresh 32-byte base64 app.key", Run: func(ctx context.Context, in bonfire.Input, out bonfire.Output) error { - key := make([]byte, encryptedKeySize) - if _, err := rand.Read(key); err != nil { + key, err := GenerateAppKey() + if err != nil { return err } - out.Success(base64.StdEncoding.EncodeToString(key)) + out.Success(key) return nil }, } diff --git a/modules/lagoon/keygen_test.go b/modules/lagoon/keygen_test.go index a25e7cc..6ba334c 100644 --- a/modules/lagoon/keygen_test.go +++ b/modules/lagoon/keygen_test.go @@ -38,3 +38,21 @@ func TestEncryptedKeyGeneratePrints32ByteBase64(t *testing.T) { t.Fatalf("decoded key length = %d, want 32", len(raw)) } } + +func TestGenerateAppKeyIs32ByteBase64(t *testing.T) { + a, err := GenerateAppKey() + if err != nil { + t.Fatal(err) + } + b, err := GenerateAppKey() + if err != nil { + t.Fatal(err) + } + if len(a) != 44 || a == b { + t.Fatalf("keys %q and %q: want two distinct 44-character values", a, b) + } + raw, err := base64.StdEncoding.DecodeString(a) + if err != nil || len(raw) != 32 { + t.Fatalf("key %q decodes to %d bytes, err %v", a, len(raw), err) + } +}