github.com/secman-team/gh-api@v1.8.2/pkg/cmd/auth/status/status.go (about) 1 package status 2 3 import ( 4 "errors" 5 "fmt" 6 "net/http" 7 8 "github.com/MakeNowJust/heredoc" 9 "github.com/secman-team/gh-api/api" 10 "github.com/secman-team/gh-api/core/config" 11 "github.com/secman-team/gh-api/pkg/cmd/auth/shared" 12 "github.com/secman-team/gh-api/pkg/cmdutil" 13 "github.com/secman-team/gh-api/pkg/iostreams" 14 "github.com/spf13/cobra" 15 ) 16 17 type StatusOptions struct { 18 HttpClient func() (*http.Client, error) 19 IO *iostreams.IOStreams 20 Config func() (config.Config, error) 21 22 Hostname string 23 ShowToken bool 24 } 25 26 func NewCmdStatus(f *cmdutil.Factory, runF func(*StatusOptions) error) *cobra.Command { 27 opts := &StatusOptions{ 28 HttpClient: f.HttpClient, 29 IO: f.IOStreams, 30 Config: f.Config, 31 } 32 33 cmd := &cobra.Command{ 34 Use: "status", 35 Args: cobra.ExactArgs(0), 36 Short: "View authentication status", 37 Long: heredoc.Doc(`Verifies and displays information about your authentication state. 38 39 This command will test your authentication state for each GitHub host that gh knows about and 40 report on any issues. 41 `), 42 RunE: func(cmd *cobra.Command, args []string) error { 43 if runF != nil { 44 return runF(opts) 45 } 46 47 return statusRun(opts) 48 }, 49 } 50 51 cmd.Flags().StringVarP(&opts.Hostname, "hostname", "h", "", "Check a specific hostname's auth status") 52 cmd.Flags().BoolVarP(&opts.ShowToken, "show-token", "t", false, "Display the auth token") 53 54 return cmd 55 } 56 57 func statusRun(opts *StatusOptions) error { 58 cfg, err := opts.Config() 59 if err != nil { 60 return err 61 } 62 63 // TODO check tty 64 65 stderr := opts.IO.ErrOut 66 67 cs := opts.IO.ColorScheme() 68 69 statusInfo := map[string][]string{} 70 71 hostnames, err := cfg.Hosts() 72 if len(hostnames) == 0 || err != nil { 73 fmt.Fprintf(stderr, 74 "You are not logged into any GitHub hosts. Run %s to authenticate.\n", cs.Bold("gh auth login")) 75 return cmdutil.SilentError 76 } 77 78 httpClient, err := opts.HttpClient() 79 if err != nil { 80 return err 81 } 82 83 var failed bool 84 var isHostnameFound bool 85 86 for _, hostname := range hostnames { 87 if opts.Hostname != "" && opts.Hostname != hostname { 88 continue 89 } 90 isHostnameFound = true 91 92 token, tokenSource, _ := cfg.GetWithSource(hostname, "oauth_token") 93 tokenIsWriteable := cfg.CheckWriteable(hostname, "oauth_token") == nil 94 95 statusInfo[hostname] = []string{} 96 addMsg := func(x string, ys ...interface{}) { 97 statusInfo[hostname] = append(statusInfo[hostname], fmt.Sprintf(x, ys...)) 98 } 99 100 if err := shared.HasMinimumScopes(httpClient, hostname, token); err != nil { 101 var missingScopes *shared.MissingScopesError 102 if errors.As(err, &missingScopes) { 103 addMsg("%s %s: the token in %s is %s", cs.Red("X"), hostname, tokenSource, err) 104 if tokenIsWriteable { 105 addMsg("- To request missing scopes, run: %s %s\n", 106 cs.Bold("gh auth refresh -h"), 107 cs.Bold(hostname)) 108 } 109 } else { 110 addMsg("%s %s: authentication failed", cs.Red("X"), hostname) 111 addMsg("- The %s token in %s is no longer valid.", cs.Bold(hostname), tokenSource) 112 if tokenIsWriteable { 113 addMsg("- To re-authenticate, run: %s %s", 114 cs.Bold("gh auth login -h"), cs.Bold(hostname)) 115 addMsg("- To forget about this host, run: %s %s", 116 cs.Bold("gh auth logout -h"), cs.Bold(hostname)) 117 } 118 } 119 failed = true 120 } else { 121 apiClient := api.NewClientFromHTTP(httpClient) 122 username, err := api.CurrentLoginName(apiClient, hostname) 123 if err != nil { 124 addMsg("%s %s: api call failed: %s", cs.Red("X"), hostname, err) 125 } 126 addMsg("%s Logged in to %s as %s (%s)", cs.SuccessIcon(), hostname, cs.Bold(username), tokenSource) 127 proto, _ := cfg.Get(hostname, "git_protocol") 128 if proto != "" { 129 addMsg("%s Git operations for %s configured to use %s protocol.", 130 cs.SuccessIcon(), hostname, cs.Bold(proto)) 131 } 132 tokenDisplay := "*******************" 133 if opts.ShowToken { 134 tokenDisplay = token 135 } 136 addMsg("%s Token: %s", cs.SuccessIcon(), tokenDisplay) 137 } 138 addMsg("") 139 140 // NB we could take this opportunity to add or fix the "user" key in the hosts config. I chose 141 // not to since I wanted this command to be read-only. 142 } 143 144 if !isHostnameFound { 145 fmt.Fprintf(stderr, 146 "Hostname %q not found among authenticated GitHub hosts\n", opts.Hostname) 147 return cmdutil.SilentError 148 } 149 150 for _, hostname := range hostnames { 151 lines, ok := statusInfo[hostname] 152 if !ok { 153 continue 154 } 155 fmt.Fprintf(stderr, "%s\n", cs.Bold(hostname)) 156 for _, line := range lines { 157 fmt.Fprintf(stderr, " %s\n", line) 158 } 159 } 160 161 if failed { 162 return cmdutil.SilentError 163 } 164 165 return nil 166 }