diff --git a/cli/packages/cmd/login.go b/cli/packages/cmd/login.go index c93af44f5..2a4729abe 100644 --- a/cli/packages/cmd/login.go +++ b/cli/packages/cmd/login.go @@ -48,14 +48,24 @@ var loginCmd = &cobra.Command{ util.HandleError(err) } - if currentLoggedInUserDetails.IsUserLoggedIn && !currentLoggedInUserDetails.LoginExpired && len(currentLoggedInUserDetails.UserCredentials.PrivateKey) != 0 { - shouldOverride, err := shouldOverrideLoginPrompt(currentLoggedInUserDetails.UserCredentials.Email) + addUser := false + if currentLoggedInUserDetails.UserCredentials.Email != "" { + addUser, err = addNewUserPrompt() if err != nil { util.HandleError(err) } + } - if !shouldOverride { - return + if !addUser { + if currentLoggedInUserDetails.IsUserLoggedIn && !currentLoggedInUserDetails.LoginExpired && len(currentLoggedInUserDetails.UserCredentials.PrivateKey) != 0 { + shouldOverride, err := shouldOverrideLoginPrompt(currentLoggedInUserDetails.UserCredentials.Email) + if err != nil { + util.HandleError(err) + } + + if !shouldOverride { + return + } } } @@ -342,6 +352,19 @@ func getFreshUserCredentials(email string, password string) (*api.GetLoginOneV2R return &loginOneResponseResult, &loginTwoResponseResult, nil } +func addNewUserPrompt() (bool, error) { + prompt := promptui.Select{ + Label: "Infisical detects previous logged in users. Would you like to add a new user? Select[Yes/No]", + Items: []string{"No", "Yes"}, + } + + _, result, err := prompt.Run() + if err != nil { + return false, err + } + return result == "Yes", err +} + func shouldOverrideLoginPrompt(currentLoggedInUserEmail string) (bool, error) { prompt := promptui.Select{ Label: fmt.Sprintf("There seems to be a user already logged in with the email: %s. Would you like to override that login? Select[Yes/No]", currentLoggedInUserEmail), diff --git a/cli/packages/cmd/switch.go b/cli/packages/cmd/switch.go new file mode 100644 index 000000000..e32338765 --- /dev/null +++ b/cli/packages/cmd/switch.go @@ -0,0 +1,93 @@ +package cmd + +import ( + "errors" + + "github.com/Infisical/infisical-merge/packages/util" + "github.com/manifoldco/promptui" + "github.com/spf13/cobra" +) + +var switchCmd = &cobra.Command{ + Use: "switch", + Short: "Used to switch between Infisical profiles", + DisableFlagsInUseLine: true, + Example: "infisical switch", + Args: cobra.ExactArgs(0), + PreRun: func(cmd *cobra.Command, args []string) { + util.RequireLogin() + }, + Run: func(cmd *cobra.Command, args []string) { + //get previous logged in profiles + loggedInProfiles, err := getLoggedInUsers() + if err != nil { + util.HandleError(err, "[infisical switch]: Unable to get logged Profiles") + } + + //prompt user + profile, err := LoggedInUsersPrompt(loggedInProfiles) + if err != nil { + util.HandleError(err, "[infisical switch]: Prompt error") + } + + //write to config file + configFile, err := util.GetConfigFile() + if err != nil { + util.HandleError(err, "[infisical switch]: Unable to get config file") + } + + configFile.LoggedInUserEmail = profile + ok := util.Contains(configFile.LoggedInUsersEmail, profile) + if !ok { + configFile.LoggedInUsersEmail = append(configFile.LoggedInUsersEmail, profile) + } + + err = util.WriteConfigFile(&configFile) + if err != nil { + util.HandleError(err, "") + } + }, +} + +func init() { + rootCmd.AddCommand(switchCmd) +} + +func getLoggedInUsers() ([]string, error) { + loggedInProfiles := []string{} + + if util.ConfigFileExists() { + configFile, err := util.GetConfigFile() + if err != nil { + return loggedInProfiles, err + } + + //get logged in profiles + // + if configFile.LoggedInUsersEmail == nil { + loggedInProfiles = append(loggedInProfiles, configFile.LoggedInUserEmail) + } else { + if len(configFile.LoggedInUsersEmail) > 0 { + loggedInProfiles = append(loggedInProfiles, configFile.LoggedInUsersEmail...) + } + } + return loggedInProfiles, nil + } else { + //empty + return loggedInProfiles, errors.New("couldn't retrieve config file") + } +} + +func LoggedInUsersPrompt(profiles []string) (string, error) { + prompt := promptui.Select{Label: "Which of your Infisical profiles would you like to use", + Items: profiles, + Size: 7, + } + + idx, _, err := prompt.Run() + if err != nil { + return "", err + } + + return profiles[idx], nil +} diff --git a/cli/packages/models/cli.go b/cli/packages/models/cli.go index 5e969a9c0..ce5838f43 100644 --- a/cli/packages/models/cli.go +++ b/cli/packages/models/cli.go @@ -12,8 +12,9 @@ type UserCredentials struct { // The file struct for Infisical config file type ConfigFile struct { - LoggedInUserEmail string `json:"loggedInUserEmail"` - VaultBackendType keyring.BackendType `json:"vaultBackendType"` + LoggedInUserEmail string `json:"loggedInUserEmail"` + VaultBackendType keyring.BackendType `json:"vaultBackendType"` + LoggedInUsersEmail []string `json:"loggedInUsersEmail,omitempty"` } type SingleEnvironmentVariable struct { diff --git a/cli/packages/util/common.go b/cli/packages/util/common.go index 13e76046d..2b57383ef 100644 --- a/cli/packages/util/common.go +++ b/cli/packages/util/common.go @@ -23,8 +23,5 @@ func WriteToFile(fileName string, dataToWrite []byte, filePerm os.FileMode) erro func CheckIsConnectedToInternet() (ok bool) { _, err := http.Get("http://clients3.google.com/generate_204") - if err != nil { - return false - } - return true + return err == nil } diff --git a/cli/packages/util/config.go b/cli/packages/util/config.go index e7b6c8d97..f23d24d8a 100644 --- a/cli/packages/util/config.go +++ b/cli/packages/util/config.go @@ -31,9 +31,25 @@ func WriteInitalConfig(userCredentials *models.UserCredentials) error { return fmt.Errorf("writeInitalConfig: unable to write config file because [err=%s]", err) } + //if empty + if existingConfigFile.LoggedInUsersEmail == nil { + existingConfigFile.LoggedInUsersEmail = []string{} + } + + //if profile exists + if len(existingConfigFile.LoggedInUsersEmail) > 0 { + ok := Contains(existingConfigFile.LoggedInUsersEmail, userCredentials.Email) + if !ok { + existingConfigFile.LoggedInUsersEmail = append(existingConfigFile.LoggedInUsersEmail, userCredentials.Email) + } + } else { + existingConfigFile.LoggedInUsersEmail = append(existingConfigFile.LoggedInUsersEmail, userCredentials.Email) + } + configFile := models.ConfigFile{ - LoggedInUserEmail: userCredentials.Email, - VaultBackendType: existingConfigFile.VaultBackendType, + LoggedInUserEmail: userCredentials.Email, + VaultBackendType: existingConfigFile.VaultBackendType, + LoggedInUsersEmail: existingConfigFile.LoggedInUsersEmail, } configFileMarshalled, err := json.Marshal(configFile) @@ -176,7 +192,7 @@ func GetConfigFile() (models.ConfigFile, error) { return configFile, nil } -// Write a ConfigFile to disk. Raise error if unable to save the model to ask +// Write a ConfigFile to disk. Raise error if unable to save the model to disk func WriteConfigFile(configFile *models.ConfigFile) error { fullConfigFilePath, fullConfigFileDirPath, err := GetFullConfigFilePath() if err != nil { diff --git a/cli/packages/util/helper.go b/cli/packages/util/helper.go index 76b6e3e46..336b368df 100644 --- a/cli/packages/util/helper.go +++ b/cli/packages/util/helper.go @@ -61,6 +61,15 @@ func IsSecretTypeValid(s string) bool { return false } +func Contains(iter []string, elem string) bool { + for _, value := range iter { + if value == elem { + return true + } + } + return false +} + func RequireLogin() { currentUserDetails, err := GetCurrentLoggedInUserDetails()