Skip to content
This repository has been archived by the owner on Feb 16, 2023. It is now read-only.

secrethub init with setup code #332

Merged
merged 29 commits into from
Sep 7, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
b864b27
Point client to commit containing setup code functionality
Marton6 Aug 7, 2020
7870a58
Factor out start repo creation and org creation from signup command
Marton6 Aug 7, 2020
c716eb5
Implement init --setup-code flag
Marton6 Aug 7, 2020
0e6359b
Update go client version and fix client creation in init command
Marton6 Aug 10, 2020
1413687
Update creating client with setup code
Marton6 Aug 10, 2020
03a3ccd
Rename client constructor functions in init command
SimonBarendse Aug 12, 2020
89197ac
Update secrethub-go
SimonBarendse Aug 12, 2020
6c51f89
Suggestions from code review
SimonBarendse Aug 12, 2020
ea32ad2
Update secrethub-go to develop
SimonBarendse Aug 12, 2020
8ba5ff0
Rephrase setup code entry in init command options prompt
SimonBarendse Aug 13, 2020
0ca8067
Fix godoc
Marton6 Aug 14, 2020
9e2ae0b
Deduplicate credential writing
Marton6 Aug 14, 2020
541410b
Stop progress printer on error
Marton6 Aug 14, 2020
77afc35
Deduplicate credential creation message
Marton6 Aug 14, 2020
9d142c5
Add device name prompt to init with setup code and deduplicate device…
Marton6 Aug 14, 2020
5c020c2
Factor out asking for passphrase
Marton6 Aug 14, 2020
702e2f9
Remove with setup code option and make setup code a credential provider
Marton6 Aug 14, 2020
ac08b03
Deduplicate passphrase prompt
jpcoenen Sep 7, 2020
465b8da
Remove prompt for setup code
jpcoenen Sep 7, 2020
6b89e82
Remove signup from `secrethub init` prompt
jpcoenen Sep 7, 2020
6afcad1
Add an option to secrethub init to clarify signup
jpcoenen Sep 7, 2020
552354e
Refer to web signup in CLI help text
jpcoenen Sep 7, 2020
953c408
Hide signup command
jpcoenen Sep 7, 2020
0418d9f
Refer to web signup in missing credential errror
jpcoenen Sep 7, 2020
d477369
Rephrase to be more consistent with other options
jpcoenen Sep 7, 2020
f726593
Do not list setup code option
jpcoenen Sep 7, 2020
6c3a6bb
Merge pull request #341 from secrethub/feature/remove-setup-code-prompt
florisvdg Sep 7, 2020
22c2756
Merge branch 'feature/init-with-setup-code' into feature/refer-to-web…
jpcoenen Sep 7, 2020
2b4a6c9
Merge pull request #342 from secrethub/feature/refer-to-web-signup
jpcoenen Sep 7, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,12 @@ require (
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7
github.com/pkg/errors v0.9.1 // indirect
github.com/secrethub/demo-app v0.1.0
github.com/secrethub/secrethub-go v0.30.0
github.com/secrethub/secrethub-go v0.30.1-0.20200814123323-7aac428a99e4
github.com/zalando/go-keyring v0.0.0-20190208082241-fbe81aec3a07
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e
golang.org/x/text v0.3.2
google.golang.org/api v0.26.0
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84
gopkg.in/yaml.v2 v2.2.2
gotest.tools v2.2.0+incompatible
)
24 changes: 8 additions & 16 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -162,22 +162,14 @@ github.com/secrethub/demo-app v0.1.0 h1:HwPPxuiSvx4TBE7Qppzu3A9eHqmsBrIz4Ko8u8pq
github.com/secrethub/demo-app v0.1.0/go.mod h1:ymjm8+WXTSDTFqsGVBNVmHSnwtZMYi7KptHvpo/fLH4=
github.com/secrethub/secrethub-cli v0.30.0/go.mod h1:dC0wd40v+iQdV83/0rUrOa01LYq+8Yj2AtJB1vzh2ao=
github.com/secrethub/secrethub-go v0.21.0/go.mod h1:rc2IfKKBJ4L0wGec0u4XnF5/pe0FFPE4Q1MWfrFso7s=
github.com/secrethub/secrethub-go v0.29.1-0.20200626075900-f7c68f70dc36 h1:kRVdL7PRfR80xjpOxFy1O0JROVpILWc2FZWE7Ni2Z2M=
github.com/secrethub/secrethub-go v0.29.1-0.20200626075900-f7c68f70dc36/go.mod h1:tDeBtyjfFQX3UqgaZfY+H4dYkcGfiVzrwLDf0XtfOrw=
github.com/secrethub/secrethub-go v0.29.1-0.20200630121846-9adfc0eb3add h1:+DzHsSjht15ycb7GFmyfmQ39gy8ZtA7FjWfJbWUPIYk=
github.com/secrethub/secrethub-go v0.29.1-0.20200630121846-9adfc0eb3add/go.mod h1:tDeBtyjfFQX3UqgaZfY+H4dYkcGfiVzrwLDf0XtfOrw=
github.com/secrethub/secrethub-go v0.29.1-0.20200702094400-d465926a4a6a h1:rtFQLsSWGkdqd6LQFbgHsG/be60Cpqv8tc1w4XoKgKM=
github.com/secrethub/secrethub-go v0.29.1-0.20200702094400-d465926a4a6a/go.mod h1:tDeBtyjfFQX3UqgaZfY+H4dYkcGfiVzrwLDf0XtfOrw=
github.com/secrethub/secrethub-go v0.29.1-0.20200702114848-1a3657310d91 h1:10KZJ3o7hodrTO1xAP1uNhDWSlLV9Bh9RqRFtiNCYJ4=
github.com/secrethub/secrethub-go v0.29.1-0.20200702114848-1a3657310d91/go.mod h1:tDeBtyjfFQX3UqgaZfY+H4dYkcGfiVzrwLDf0XtfOrw=
github.com/secrethub/secrethub-go v0.29.1-0.20200703092019-9f5d3de9b0e4 h1:TszZ+u/DRpPjaAGwEFSQNHkWhG4QR3KBxQJ66NfTAMk=
github.com/secrethub/secrethub-go v0.29.1-0.20200703092019-9f5d3de9b0e4/go.mod h1:tDeBtyjfFQX3UqgaZfY+H4dYkcGfiVzrwLDf0XtfOrw=
github.com/secrethub/secrethub-go v0.29.1-0.20200703150346-411544a71e9d h1:tADItWP+YXaGLD1ZMFocxDaKKVcu8wXgEulbcUmX4Ec=
github.com/secrethub/secrethub-go v0.29.1-0.20200703150346-411544a71e9d/go.mod h1:tDeBtyjfFQX3UqgaZfY+H4dYkcGfiVzrwLDf0XtfOrw=
github.com/secrethub/secrethub-go v0.29.1-0.20200707154958-5e5602145597 h1:uC9ODMKaqBo1k8fxmFSWGkLr05TgEd3t4mHqJ8Jo9Gc=
github.com/secrethub/secrethub-go v0.29.1-0.20200707154958-5e5602145597/go.mod h1:tDeBtyjfFQX3UqgaZfY+H4dYkcGfiVzrwLDf0XtfOrw=
github.com/secrethub/secrethub-go v0.30.0 h1:Nh1twPDwPbYQj/cYc1NG+j7sv76LZiXLPovyV83tZj0=
github.com/secrethub/secrethub-go v0.30.0/go.mod h1:tDeBtyjfFQX3UqgaZfY+H4dYkcGfiVzrwLDf0XtfOrw=
github.com/secrethub/secrethub-go v0.30.1-0.20200807145938-681a4665c550 h1:CBeQpW1CYfaXgGgC3CtxmYqZq5YLlG/HknE3UD8zsms=
github.com/secrethub/secrethub-go v0.30.1-0.20200807145938-681a4665c550/go.mod h1:ZIco8Y0G0Pi0Vb7pQROjvEKgSreZiRMLhAbzWUneUSQ=
github.com/secrethub/secrethub-go v0.30.1-0.20200812113929-edff110cddfc h1:dN6YUlRQ3MwHc1QGWsMMazzFPWxWSOlp1afIzs4ycQo=
github.com/secrethub/secrethub-go v0.30.1-0.20200812113929-edff110cddfc/go.mod h1:ZIco8Y0G0Pi0Vb7pQROjvEKgSreZiRMLhAbzWUneUSQ=
github.com/secrethub/secrethub-go v0.30.1-0.20200812121649-846d80e97296 h1:IsbGXusKlVYSThYYepv80H0S9dXYOWMHDSNgoEamt1c=
github.com/secrethub/secrethub-go v0.30.1-0.20200812121649-846d80e97296/go.mod h1:ZIco8Y0G0Pi0Vb7pQROjvEKgSreZiRMLhAbzWUneUSQ=
github.com/secrethub/secrethub-go v0.30.1-0.20200814123323-7aac428a99e4 h1:zIOs8q0BK5pI55Fa8y3MMuxIfD7nAv9sh+3GbOiT6hM=
github.com/secrethub/secrethub-go v0.30.1-0.20200814123323-7aac428a99e4/go.mod h1:ZIco8Y0G0Pi0Vb7pQROjvEKgSreZiRMLhAbzWUneUSQ=
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
Expand Down
2 changes: 2 additions & 0 deletions internals/secrethub/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ func NewApp() *App {
io := ui.NewUserIO()
store := NewCredentialConfig(io)
help := "The SecretHub command-line interface is a unified tool to manage your infrastructure secrets with SecretHub.\n\n" +
"If you do not yet have a SecretHub account, go here to create one:\n\n" +
" https://signup.secrethub.io/\n\n" +
"For a step-by-step introduction, check out:\n\n" +
" https://secrethub.io/docs/getting-started/\n\n" +
"To get help, see:\n\n" +
Expand Down
2 changes: 1 addition & 1 deletion internals/secrethub/credential_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (

// Errors
var (
ErrCredentialNotExist = errMain.Code("credential_not_exist").Error("could not find credential file. Run `secrethub signup` to create an account.")
ErrCredentialNotExist = errMain.Code("credential_not_exist").Error("could not find credential file. Go to https://signup.secrethub.io/ to create an account or run `secrethub init` to use an already existing account on this machine.")
)

// CredentialConfig handles the configuration necessary for local credentials.
Expand Down
154 changes: 122 additions & 32 deletions internals/secrethub/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,30 +16,32 @@ import (

// InitCommand configures the user's SecretHub account for use on this machine.
type InitCommand struct {
backupCode string
force bool
io ui.IO
newClient newClientFunc
newClientWithoutCredentials func(credentials.Provider) (secrethub.ClientInterface, error)
credentialStore CredentialConfig
progressPrinter progress.Printer
backupCode string
setupCode string
force bool
io ui.IO
newUnauthenticatedClient newClientFunc
newClientWithCredentials func(credentials.Provider) (secrethub.ClientInterface, error)
credentialStore CredentialConfig
progressPrinter progress.Printer
}

// NewInitCommand creates a new InitCommand.
func NewInitCommand(io ui.IO, newClient newClientFunc, newClientWithoutCredentials func(credentials.Provider) (secrethub.ClientInterface, error), credentialStore CredentialConfig) *InitCommand {
func NewInitCommand(io ui.IO, newUnauthenticatedClient newClientFunc, newClientWithCredentials func(credentials.Provider) (secrethub.ClientInterface, error), credentialStore CredentialConfig) *InitCommand {
return &InitCommand{
io: io,
newClient: newClient,
newClientWithoutCredentials: newClientWithoutCredentials,
credentialStore: credentialStore,
progressPrinter: progress.NewPrinter(io.Output(), 500*time.Millisecond),
io: io,
newUnauthenticatedClient: newUnauthenticatedClient,
newClientWithCredentials: newClientWithCredentials,
credentialStore: credentialStore,
progressPrinter: progress.NewPrinter(io.Output(), 500*time.Millisecond),
}
}

// Register registers the command, arguments and flags on the provided Registerer.
func (cmd *InitCommand) Register(r command.Registerer) {
clause := r.Command("init", "Initialize the SecretHub client for first use on this device.")
clause.Flag("backup-code", "The backup code used to restore an existing account to this device.").StringVar(&cmd.backupCode)
clause.Flag("setup-code", "The setup code used to configure the CLI to use an account created on the website.").StringVar(&cmd.setupCode)
registerForceFlag(clause).BoolVar(&cmd.force)

command.BindAction(clause, cmd.Run)
Expand All @@ -50,11 +52,16 @@ type InitMode int
const (
InitModeSignup InitMode = iota + 1
InitModeBackupCode
InitModeSetupCode
)

// Run configures the user's SecretHub account for use on this machine.
// If an account was already configured, the user is prompted for confirmation to overwrite it.
func (cmd *InitCommand) Run() error {
if cmd.setupCode != "" && cmd.backupCode != "" {
return ErrFlagsConflict("--backup-code and --setup-code")
}

credentialPath := cmd.credentialStore.ConfigDir().Credential().Path()

if cmd.credentialStore.ConfigDir().Credential().Exists() && !cmd.force {
Expand All @@ -76,7 +83,9 @@ func (cmd *InitCommand) Run() error {
}

var mode InitMode
if cmd.backupCode != "" {
if cmd.setupCode != "" {
mode = InitModeSetupCode
} else if cmd.backupCode != "" {
mode = InitModeBackupCode
}

Expand All @@ -86,16 +95,18 @@ func (cmd *InitCommand) Run() error {
}
option, err := ui.Choose(cmd.io, "How do you want to initialize your SecretHub account on this device?",
[]string{
"Signup for a new account",
"Sign up for a new account",
"Use a backup code to recover an existing account",
}, 3)
if err != nil {
return err
}
fmt.Fprintln(cmd.io.Output())

switch option {
case 0:
mode = InitModeSignup
fmt.Fprintln(cmd.io.Output(), "Go to https://signup.secrethub.io/ and follow the steps to create an account and get it set up on this machine.")
return nil
case 1:
mode = InitModeBackupCode
}
Expand All @@ -105,12 +116,83 @@ func (cmd *InitCommand) Run() error {
case InitModeSignup:
signupCommand := SignUpCommand{
io: cmd.io,
newClient: cmd.newClient,
newClient: cmd.newUnauthenticatedClient,
credentialStore: cmd.credentialStore,
progressPrinter: cmd.progressPrinter,
force: cmd.force,
}
return signupCommand.Run()
case InitModeSetupCode:
setupCode := cmd.setupCode

fmt.Fprintf(cmd.io.Output(), credentialCreationMessage, credentialPath)

// Only prompt for a passphrase when the user hasn't used --force.
// Otherwise, we assume the passphrase was intentionally not
// configured to output a plaintext credential.
var passphrase string
if !cmd.credentialStore.IsPassphraseSet() && !cmd.force {
var err error
passphrase, err = askCredentialPassphrase(cmd.io)
if err != nil {
return err
}
}

deviceName, err := promptForDeviceName(cmd.io)
if err != nil {
return err
}

fmt.Fprint(cmd.io.Output(), "Setting up your account...")
cmd.progressPrinter.Start()

client, err := cmd.newClientWithCredentials(credentials.NewSetupCode(setupCode))
if err != nil {
cmd.progressPrinter.Stop()
jpcoenen marked this conversation as resolved.
Show resolved Hide resolved
return err
}

credential := credentials.CreateKey()
_, err = client.Credentials().Create(credential, deviceName)
if err != nil {
cmd.progressPrinter.Stop()
return err
}

err = writeNewCredential(credential, passphrase, cmd.credentialStore.ConfigDir().Credential())
if err != nil {
cmd.progressPrinter.Stop()
return err
}

client, err = cmd.newClientWithCredentials(credential)
if err != nil {
cmd.progressPrinter.Stop()
return err
}

me, err := client.Me().GetUser()
if err != nil {
cmd.progressPrinter.Stop()
return err
}

secretPath, err := createStartRepo(client, me.Username, me.FullName)
if err != nil {
cmd.progressPrinter.Stop()
return err
}
cmd.progressPrinter.Stop()
fmt.Fprint(cmd.io.Output(), "Created your account.\n\n")

err = createWorkspace(client, cmd.io, "", "", cmd.progressPrinter)
if err != nil {
return err
}

fmt.Fprintf(cmd.io.Output(), "Setup complete. To read your first secret, run:\n\n secrethub read %s\n\n", secretPath)
return nil
case InitModeBackupCode:
backupCode := cmd.backupCode

Expand All @@ -122,7 +204,7 @@ func (cmd *InitCommand) Run() error {
}
}

client, err := cmd.newClientWithoutCredentials(credentials.UseBackupCode(backupCode))
client, err := cmd.newClientWithCredentials(credentials.UseBackupCode(backupCode))
if err != nil {
return err
}
Expand All @@ -146,19 +228,9 @@ func (cmd *InitCommand) Run() error {
return nil
}

deviceName := ""
question := "What is the name of this device?"
hostName, err := os.Hostname()
if err == nil {
deviceName, err = ui.AskWithDefault(cmd.io, question, hostName)
if err != nil {
return err
}
} else {
deviceName, err = ui.Ask(cmd.io, question)
if err != nil {
return err
}
deviceName, err := promptForDeviceName(cmd.io)
if err != nil {
return err
}

// Only prompt for a passphrase when the user hasn't used --force.
Expand All @@ -167,7 +239,7 @@ func (cmd *InitCommand) Run() error {
var passphrase string
if !cmd.credentialStore.IsPassphraseSet() && !cmd.force {
var err error
passphrase, err = ui.AskPassphrase(cmd.io, "Please enter a passphrase to protect your local credential (leave empty for no passphrase): ", "Enter the same passphrase again: ", 3)
passphrase, err = askCredentialPassphrase(cmd.io)
if err != nil {
return err
}
Expand Down Expand Up @@ -197,3 +269,21 @@ func (cmd *InitCommand) Run() error {
return errors.New("invalid option")
}
}

func promptForDeviceName(io ui.IO) (string, error) {
deviceName := ""
question := "What is the name of this device?"
hostName, err := os.Hostname()
if err == nil {
deviceName, err = ui.AskWithDefault(io, question, hostName)
if err != nil {
return "", err
}
} else {
deviceName, err = ui.Ask(io, question)
if err != nil {
return "", err
}
}
return deviceName, nil
}
Loading