diff options
author | Michael Muré <batolettre@gmail.com> | 2022-09-10 11:09:19 +0200 |
---|---|---|
committer | Michael Muré <batolettre@gmail.com> | 2022-11-20 17:18:09 +0100 |
commit | acc9a6f3a6df2961c3ae44352216d915cb9b5315 (patch) | |
tree | e159372673104ade1f15ddc1a84aa9da93e93552 /commands/bridge/bridge_auth_addtoken.go | |
parent | a3fa445a9c76631c4cd16f93e1c1c68a954adef7 (diff) | |
download | git-bug-acc9a6f3a6df2961c3ae44352216d915cb9b5315.tar.gz |
commands: reorg into different packages
Diffstat (limited to 'commands/bridge/bridge_auth_addtoken.go')
-rw-r--r-- | commands/bridge/bridge_auth_addtoken.go | 133 |
1 files changed, 133 insertions, 0 deletions
diff --git a/commands/bridge/bridge_auth_addtoken.go b/commands/bridge/bridge_auth_addtoken.go new file mode 100644 index 00000000..bcab7fc3 --- /dev/null +++ b/commands/bridge/bridge_auth_addtoken.go @@ -0,0 +1,133 @@ +package bridgecmd + +import ( + "bufio" + "fmt" + "os" + "strings" + + "github.com/mattn/go-isatty" + "github.com/pkg/errors" + "github.com/spf13/cobra" + + "github.com/MichaelMure/git-bug/bridge" + "github.com/MichaelMure/git-bug/bridge/core" + "github.com/MichaelMure/git-bug/bridge/core/auth" + "github.com/MichaelMure/git-bug/cache" + "github.com/MichaelMure/git-bug/commands/completion" + "github.com/MichaelMure/git-bug/commands/execenv" +) + +type bridgeAuthAddTokenOptions struct { + target string + login string + user string +} + +func newBridgeAuthAddTokenCommand() *cobra.Command { + env := execenv.NewEnv() + options := bridgeAuthAddTokenOptions{} + + cmd := &cobra.Command{ + Use: "add-token [TOKEN]", + Short: "Store a new token", + PreRunE: execenv.LoadBackendEnsureUser(env), + RunE: execenv.CloseBackend(env, func(cmd *cobra.Command, args []string) error { + return runBridgeAuthAddToken(env, options, args) + }), + Args: cobra.MaximumNArgs(1), + } + + flags := cmd.Flags() + flags.SortFlags = false + + flags.StringVarP(&options.target, "target", "t", "", + fmt.Sprintf("The target of the bridge. Valid values are [%s]", strings.Join(bridge.Targets(), ","))) + cmd.RegisterFlagCompletionFunc("target", completion.From(bridge.Targets())) + flags.StringVarP(&options.login, + "login", "l", "", "The login in the remote bug-tracker") + flags.StringVarP(&options.user, + "user", "u", "", "The user to add the token to. Default is the current user") + cmd.RegisterFlagCompletionFunc("user", completion.User(env)) + + return cmd +} + +func runBridgeAuthAddToken(env *execenv.Env, opts bridgeAuthAddTokenOptions, args []string) error { + // Note: as bridgeAuthAddTokenLogin is not checked against the remote bug-tracker, + // it's possible to register a credential with an incorrect login (including bad case). + // The consequence is that it will not get picked later by the bridge. I find that + // checking it would require a cumbersome UX (need to provide a base URL for some bridges, ...) + // so it's probably not worth it, unless we refactor that entirely. + + if opts.target == "" { + return fmt.Errorf("flag --target is required") + } + if opts.login == "" { + return fmt.Errorf("flag --login is required") + } + + if !core.TargetExist(opts.target) { + return fmt.Errorf("unknown target") + } + + var value string + + if len(args) == 1 { + value = args[0] + } else { + // Read from Stdin + if isatty.IsTerminal(os.Stdin.Fd()) { + env.Err.Println("Enter the token:") + } + reader := bufio.NewReader(os.Stdin) + raw, err := reader.ReadString('\n') + if err != nil { + return fmt.Errorf("reading from stdin: %v", err) + } + value = strings.TrimSuffix(raw, "\n") + } + + var user *cache.IdentityCache + var err error + + if opts.user == "" { + user, err = env.Backend.GetUserIdentity() + } else { + user, err = env.Backend.ResolveIdentityPrefix(opts.user) + } + if err != nil { + return err + } + + metaKey, _ := bridge.LoginMetaKey(opts.target) + login, ok := user.ImmutableMetadata()[metaKey] + + switch { + case ok && login == opts.login: + // nothing to do + case ok && login != opts.login: + return fmt.Errorf("this user is already tagged with a different %s login", opts.target) + default: + user.SetMetadata(metaKey, opts.login) + err = user.Commit() + if err != nil { + return err + } + } + + token := auth.NewToken(opts.target, value) + token.SetMetadata(auth.MetaKeyLogin, opts.login) + + if err := token.Validate(); err != nil { + return errors.Wrap(err, "invalid token") + } + + err = auth.Store(env.Repo, token) + if err != nil { + return err + } + + env.Out.Printf("token %s added\n", token.ID()) + return nil +} |