diff --git a/cmd/secret/generate/masterpassphrase.go b/cmd/secret/generate/encryptionkey/encryptionkey.go similarity index 53% rename from cmd/secret/generate/masterpassphrase.go rename to cmd/secret/generate/encryptionkey/encryptionkey.go index 3bfd59c38..5c50f7504 100644 --- a/cmd/secret/generate/masterpassphrase.go +++ b/cmd/secret/generate/encryptionkey/encryptionkey.go @@ -12,28 +12,27 @@ limitations under the License. */ -package generate +package encryptionkey import ( "fmt" "github.com/spf13/cobra" - "opendev.org/airship/airshipctl/pkg/secret" + "opendev.org/airship/airshipctl/pkg/secret/generate" ) -// NewGenerateMasterPassphraseCommand creates a new command for generating secret information -func NewGenerateMasterPassphraseCommand() *cobra.Command { - masterPassphraseCmd := &cobra.Command{ - Use: "masterpassphrase", - // TODO(howell): Make this more expressive - Short: "Generates a secure master passphrase", +// NewGenerateEncryptionKeyCommand creates a new command for generating secret information +func NewGenerateEncryptionKeyCommand() *cobra.Command { + encryptionKeyCmd := &cobra.Command{ + Use: "encryptionkey", + Short: "Generates a secure encryption key or passphrase", Run: func(cmd *cobra.Command, args []string) { - engine := secret.NewPassphraseEngine(nil) - masterPassphrase := engine.GeneratePassphrase() - fmt.Fprintln(cmd.OutOrStdout(), masterPassphrase) + engine := generate.NewEncryptionKeyEngine(nil) + encryptionKey := engine.GenerateEncryptionKey() + fmt.Fprintln(cmd.OutOrStdout(), encryptionKey) }, } - return masterPassphraseCmd + return encryptionKeyCmd } diff --git a/cmd/secret/generate/encryptionkey/encryptionkey_test.go b/cmd/secret/generate/encryptionkey/encryptionkey_test.go new file mode 100644 index 000000000..362e62797 --- /dev/null +++ b/cmd/secret/generate/encryptionkey/encryptionkey_test.go @@ -0,0 +1,36 @@ +/* + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package encryptionkey_test + +import ( + "testing" + + "opendev.org/airship/airshipctl/cmd/secret/generate/encryptionkey" + "opendev.org/airship/airshipctl/testutil" +) + +func TestGenerateEncryptionKey(t *testing.T) { + cmdTests := []*testutil.CmdTest{ + { + Name: "generate-encryptionkey-cmd-with-help", + CmdLine: "--help", + Cmd: encryptionkey.NewGenerateEncryptionKeyCommand(), + }, + } + + for _, tt := range cmdTests { + testutil.RunTest(t, tt) + } +} diff --git a/cmd/secret/generate/encryptionkey/testdata/TestGenerateEncryptionKeyGoldenOutput/generate-encryptionkey-cmd-with-help.golden b/cmd/secret/generate/encryptionkey/testdata/TestGenerateEncryptionKeyGoldenOutput/generate-encryptionkey-cmd-with-help.golden new file mode 100644 index 000000000..2c154a0a6 --- /dev/null +++ b/cmd/secret/generate/encryptionkey/testdata/TestGenerateEncryptionKeyGoldenOutput/generate-encryptionkey-cmd-with-help.golden @@ -0,0 +1,7 @@ +Generates a secure encryption key or passphrase + +Usage: + encryptionkey [flags] + +Flags: + -h, --help help for encryptionkey diff --git a/cmd/secret/generate/generate.go b/cmd/secret/generate/generate.go index 0c37886e2..1612525c8 100644 --- a/cmd/secret/generate/generate.go +++ b/cmd/secret/generate/generate.go @@ -14,7 +14,11 @@ package generate -import "github.com/spf13/cobra" +import ( + "github.com/spf13/cobra" + + "opendev.org/airship/airshipctl/cmd/secret/generate/encryptionkey" +) // NewGenerateCommand creates a new command for generating secret information func NewGenerateCommand() *cobra.Command { @@ -24,7 +28,7 @@ func NewGenerateCommand() *cobra.Command { Short: "Generate various secrets", } - generateRootCmd.AddCommand(NewGenerateMasterPassphraseCommand()) + generateRootCmd.AddCommand(encryptionkey.NewGenerateEncryptionKeyCommand()) return generateRootCmd } diff --git a/docs/source/cli/airshipctl_secret_generate.md b/docs/source/cli/airshipctl_secret_generate.md index 144eee7a8..c507a65b4 100644 --- a/docs/source/cli/airshipctl_secret_generate.md +++ b/docs/source/cli/airshipctl_secret_generate.md @@ -22,5 +22,5 @@ Generate various secrets ### SEE ALSO * [airshipctl secret](airshipctl_secret.md) - Manage secrets -* [airshipctl secret generate masterpassphrase](airshipctl_secret_generate_masterpassphrase.md) - Generates a secure master passphrase +* [airshipctl secret generate encryptionkey](airshipctl_secret_generate_encryptionkey.md) - Generates a secure encryption key or passphrase diff --git a/docs/source/cli/airshipctl_secret_generate_masterpassphrase.md b/docs/source/cli/airshipctl_secret_generate_encryptionkey.md similarity index 61% rename from docs/source/cli/airshipctl_secret_generate_masterpassphrase.md rename to docs/source/cli/airshipctl_secret_generate_encryptionkey.md index d4ae880ff..8b903b7e4 100644 --- a/docs/source/cli/airshipctl_secret_generate_masterpassphrase.md +++ b/docs/source/cli/airshipctl_secret_generate_encryptionkey.md @@ -1,19 +1,19 @@ -## airshipctl secret generate masterpassphrase +## airshipctl secret generate encryptionkey -Generates a secure master passphrase +Generates a secure encryption key or passphrase ### Synopsis -Generates a secure master passphrase +Generates a secure encryption key or passphrase ``` -airshipctl secret generate masterpassphrase [flags] +airshipctl secret generate encryptionkey [flags] ``` ### Options ``` - -h, --help help for masterpassphrase + -h, --help help for encryptionkey ``` ### Options inherited from parent commands diff --git a/pkg/secret/passphrases.go b/pkg/secret/generate/encryptionkey.go similarity index 66% rename from pkg/secret/passphrases.go rename to pkg/secret/generate/encryptionkey.go index e41f115ae..5bda84b72 100644 --- a/pkg/secret/passphrases.go +++ b/pkg/secret/generate/encryptionkey.go @@ -12,7 +12,7 @@ limitations under the License. */ -package secret +package generate import ( "math/rand" @@ -41,59 +41,59 @@ func init() { pool = append(pool, []byte(asciiSymbols)...) } -// PassphraseEngine is used to generate secure random passphrases -type PassphraseEngine struct { +// EncryptionKeyEngine is used to generate secure random passphrases +type EncryptionKeyEngine struct { rng *rand.Rand pool []byte } -// NewPassphraseEngine creates an PassphraseEngine using src. If src is nil, +// NewEncryptionKeyEngine creates an PassphraseEngine using src. If src is nil, // the returned PassphraseEngine will use the default Source -func NewPassphraseEngine(src rand.Source) *PassphraseEngine { +func NewEncryptionKeyEngine(src rand.Source) *EncryptionKeyEngine { if src == nil { src = &Source{} } - return &PassphraseEngine{ + return &EncryptionKeyEngine{ rng: rand.New(src), pool: pool, } } -// GeneratePassphrase returns a secure random string of length 24, +// GenerateEncryptionKey returns a secure random string of length 24, // containing at least one of each from the following sets: // [0-9] // [a-z] // [A-Z] // [@#&-+=?] -func (e *PassphraseEngine) GeneratePassphrase() string { - return e.GeneratePassphraseN(defaultLength) +func (e *EncryptionKeyEngine) GenerateEncryptionKey() string { + return e.GenerateEncryptionKeyN(defaultLength) } -// GeneratePassphraseN returns a secure random string containing at least +// GenerateEncryptionKeyN returns a secure random string containing at least // one of each from the following sets. Its length will be max(length, 24) // [0-9] // [a-z] // [A-Z] // [@#&-+=?] -func (e *PassphraseEngine) GeneratePassphraseN(length int) string { +func (e *EncryptionKeyEngine) GenerateEncryptionKeyN(length int) string { if length < defaultLength { length = defaultLength } - var passPhrase string - for !e.isValidPassphrase(passPhrase) { + var encryptionkey string + for !e.isValidEncryptionKey(encryptionkey) { var sb strings.Builder for i := 0; i < length; i++ { randIndex := e.rng.Intn(len(e.pool)) randChar := e.pool[randIndex] sb.WriteString(string(randChar)) } - passPhrase = sb.String() + encryptionkey = sb.String() } - return passPhrase + return encryptionkey } -func (e *PassphraseEngine) isValidPassphrase(passPhrase string) bool { - if len(passPhrase) < defaultLength { +func (e *EncryptionKeyEngine) isValidEncryptionKey(encryptionkey string) bool { + if len(encryptionkey) < defaultLength { return false } @@ -104,7 +104,7 @@ func (e *PassphraseEngine) isValidPassphrase(passPhrase string) bool { asciiSymbols, } for _, charSet := range charSets { - if !strings.ContainsAny(passPhrase, charSet) { + if !strings.ContainsAny(encryptionkey, charSet) { return false } } diff --git a/pkg/secret/passphrases_test.go b/pkg/secret/generate/encryptionkey_test.go similarity index 78% rename from pkg/secret/passphrases_test.go rename to pkg/secret/generate/encryptionkey_test.go index 8fbc9156a..1ab66de2b 100644 --- a/pkg/secret/passphrases_test.go +++ b/pkg/secret/generate/encryptionkey_test.go @@ -12,7 +12,7 @@ limitations under the License. */ -package secret_test +package generate_test import ( "math/rand" @@ -21,7 +21,7 @@ import ( "github.com/stretchr/testify/assert" - "opendev.org/airship/airshipctl/pkg/secret" + "opendev.org/airship/airshipctl/pkg/secret/generate" ) const ( @@ -33,13 +33,13 @@ const ( defaultLength = 24 ) -func TestDeterministicGenerateValidPassphrase(t *testing.T) { +func TestDeterministicGenerateValidEncryptionKey(t *testing.T) { assert := assert.New(t) testSource := rand.NewSource(42) - engine := secret.NewPassphraseEngine(testSource) + engine := generate.NewEncryptionKeyEngine(testSource) // pre-calculated for rand.NewSource(42) - expectedPassphrases := []string{ + expectedEncryptionKey := []string{ "erx&97vfqd7LN3HJ?t@oPhds", "##Xeuvf5Njy@hNWSaRoleFkf", "jB=kirg7acIt-=fx1Fb-tZ+7", @@ -52,13 +52,13 @@ func TestDeterministicGenerateValidPassphrase(t *testing.T) { "XC?bDaHTa3mrBYLMG@#B=Q0B", } - for i, expected := range expectedPassphrases { - actual := engine.GeneratePassphrase() + for i, expected := range expectedEncryptionKey { + actual := engine.GenerateEncryptionKey() assert.Equal(expected, actual, "Test #%d failed", i) } } -func TestNondeterministicGenerateValidPassphrase(t *testing.T) { +func TestNondeterministicGenerateValidEncryptionKey(t *testing.T) { assert := assert.New(t) // Due to the nondeterminism of random number generators, this // functionality is impossible to fully test. Let's just generate @@ -72,9 +72,9 @@ func TestNondeterministicGenerateValidPassphrase(t *testing.T) { asciiSymbols, } - engine := secret.NewPassphraseEngine(nil) + engine := generate.NewEncryptionKeyEngine(nil) for i := 0; i < 10000; i++ { - passphrase := engine.GeneratePassphrase() + passphrase := engine.GenerateEncryptionKey() assert.Truef(len(passphrase) >= defaultLength, "%s does not meet the length requirement", passphrase) @@ -86,10 +86,10 @@ func TestNondeterministicGenerateValidPassphrase(t *testing.T) { } } -func TestGenerateValidPassphraseN(t *testing.T) { +func TestGenerateValidEncryptionKeyN(t *testing.T) { assert := assert.New(t) testSource := rand.NewSource(42) - engine := secret.NewPassphraseEngine(testSource) + engine := generate.NewEncryptionKeyEngine(testSource) tests := []struct { inputLegth int expectedLength int @@ -109,7 +109,7 @@ func TestGenerateValidPassphraseN(t *testing.T) { } for _, tt := range tests { - passphrase := engine.GeneratePassphraseN(tt.inputLegth) + passphrase := engine.GenerateEncryptionKeyN(tt.inputLegth) assert.Len(passphrase, tt.expectedLength) } } diff --git a/pkg/secret/rngsource.go b/pkg/secret/generate/rngsource.go similarity index 98% rename from pkg/secret/rngsource.go rename to pkg/secret/generate/rngsource.go index 38ea9bac3..b2fecaf6b 100644 --- a/pkg/secret/rngsource.go +++ b/pkg/secret/generate/rngsource.go @@ -12,7 +12,7 @@ limitations under the License. */ -package secret +package generate import ( crypto "crypto/rand"