Merge "Refactoring masterpassphrase cmd to encryptionkey"

This commit is contained in:
Zuul 2020-11-12 23:43:32 +00:00 committed by Gerrit Code Review
commit e14314b624
9 changed files with 98 additions and 52 deletions

@ -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
}

@ -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)
}
}

@ -0,0 +1,7 @@
Generates a secure encryption key or passphrase
Usage:
encryptionkey [flags]
Flags:
-h, --help help for encryptionkey

@ -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
}

@ -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

@ -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

@ -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
}
}

@ -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)
}
}

@ -12,7 +12,7 @@
limitations under the License.
*/
package secret
package generate
import (
crypto "crypto/rand"