1package commands
  2
  3import (
  4	"bufio"
  5	"fmt"
  6	"os"
  7	"strings"
  8
  9	"github.com/mattn/go-isatty"
 10	"github.com/pkg/errors"
 11	"github.com/spf13/cobra"
 12
 13	"github.com/MichaelMure/git-bug/bridge"
 14	"github.com/MichaelMure/git-bug/bridge/core"
 15	"github.com/MichaelMure/git-bug/bridge/core/auth"
 16	"github.com/MichaelMure/git-bug/cache"
 17	"github.com/MichaelMure/git-bug/util/interrupt"
 18)
 19
 20var (
 21	bridgeAuthAddTokenTarget string
 22	bridgeAuthAddTokenLogin  string
 23	bridgeAuthAddTokenUser   string
 24)
 25
 26func runBridgeTokenAdd(cmd *cobra.Command, args []string) error {
 27	if bridgeAuthAddTokenTarget == "" {
 28		return fmt.Errorf("flag --target is required")
 29	}
 30	if bridgeAuthAddTokenLogin == "" {
 31		return fmt.Errorf("flag --login is required")
 32	}
 33
 34	backend, err := cache.NewRepoCache(repo)
 35	if err != nil {
 36		return err
 37	}
 38	defer backend.Close()
 39	interrupt.RegisterCleaner(backend.Close)
 40
 41	if !core.TargetExist(bridgeAuthAddTokenTarget) {
 42		return fmt.Errorf("unknown target")
 43	}
 44
 45	var value string
 46
 47	if len(args) == 1 {
 48		value = args[0]
 49	} else {
 50		// Read from Stdin
 51		if isatty.IsTerminal(os.Stdin.Fd()) {
 52			fmt.Println("Enter the token:")
 53		}
 54		reader := bufio.NewReader(os.Stdin)
 55		raw, err := reader.ReadString('\n')
 56		if err != nil {
 57			return fmt.Errorf("reading from stdin: %v", err)
 58		}
 59		value = strings.TrimSuffix(raw, "\n")
 60	}
 61
 62	var user *cache.IdentityCache
 63
 64	if bridgeAuthAddTokenUser == "" {
 65		user, err = backend.GetUserIdentity()
 66	} else {
 67		user, err = backend.ResolveIdentityPrefix(bridgeAuthAddTokenUser)
 68	}
 69	if err != nil {
 70		return err
 71	}
 72
 73	metaKey, _ := bridge.LoginMetaKey(bridgeAuthAddTokenTarget)
 74	login, ok := user.ImmutableMetadata()[metaKey]
 75
 76	switch {
 77	case ok && login == bridgeAuthAddTokenLogin:
 78		// nothing to do
 79	case ok && login != bridgeAuthAddTokenLogin:
 80		return fmt.Errorf("this user is already tagged with a different %s login", bridgeAuthAddTokenTarget)
 81	default:
 82		user.SetMetadata(metaKey, bridgeAuthAddTokenLogin)
 83		err = user.Commit()
 84		if err != nil {
 85			return err
 86		}
 87	}
 88
 89	token := auth.NewToken(bridgeAuthAddTokenTarget, value)
 90	token.SetMetadata(auth.MetaKeyLogin, bridgeAuthAddTokenLogin)
 91
 92	if err := token.Validate(); err != nil {
 93		return errors.Wrap(err, "invalid token")
 94	}
 95
 96	err = auth.Store(repo, token)
 97	if err != nil {
 98		return err
 99	}
100
101	fmt.Printf("token %s added\n", token.ID())
102	return nil
103}
104
105var bridgeAuthAddTokenCmd = &cobra.Command{
106	Use:     "add-token [<token>]",
107	Short:   "Store a new token",
108	PreRunE: loadRepoEnsureUser,
109	RunE:    runBridgeTokenAdd,
110	Args:    cobra.MaximumNArgs(1),
111}
112
113func init() {
114	bridgeAuthCmd.AddCommand(bridgeAuthAddTokenCmd)
115	bridgeAuthAddTokenCmd.Flags().StringVarP(&bridgeAuthAddTokenTarget, "target", "t", "",
116		fmt.Sprintf("The target of the bridge. Valid values are [%s]", strings.Join(bridge.Targets(), ",")))
117	bridgeAuthAddTokenCmd.Flags().StringVarP(&bridgeAuthAddTokenLogin,
118		"login", "l", "", "The login in the remote bug-tracker")
119	bridgeAuthAddTokenCmd.Flags().StringVarP(&bridgeAuthAddTokenUser,
120		"user", "u", "", "The user to add the token to. Default is the current user")
121	bridgeAuthAddTokenCmd.Flags().SortFlags = false
122}