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(value, bridgeAuthAddTokenTarget)
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}