-
Notifications
You must be signed in to change notification settings - Fork 361
/
client_login.go
103 lines (85 loc) · 2.91 KB
/
client_login.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
package login
import (
"context"
"fmt"
"os"
"github.com/briandowns/spinner"
"github.com/stripe/stripe-cli/pkg/ansi"
"github.com/stripe/stripe-cli/pkg/login/keys"
"github.com/stripe/stripe-cli/pkg/open"
"github.com/stripe/stripe-cli/pkg/stripe"
)
var openBrowser = open.Browser
var canOpenBrowser = open.CanOpenBrowser
const stripeCLIAuthPath = "/stripecli/auth"
// TODO
/*
4. Observability and associated alerting? Business metrics (how many users use this flow)?
5. Rate limiting for each operation?
6. Audit trail for key generation
7. Move configuration changes to profile package
*/
// Authenticator handles the login flow
type Authenticator struct {
keytransfer keys.KeyTransfer
asyncInputReader AsyncInputReader
}
// NewAuthenticator creates a new authenticator object
func NewAuthenticator(keytransfer keys.KeyTransfer) *Authenticator {
return &Authenticator{
keytransfer: keytransfer,
asyncInputReader: AsyncStdinReader{},
}
}
// Login function is used to obtain credentials via stripe dashboard.
func (a *Authenticator) Login(ctx context.Context, links *Links) error {
color := ansi.Color(os.Stdout)
fmt.Printf("Your pairing code is: %s\n", color.Bold(links.VerificationCode))
fmt.Println(ansi.Faint("This pairing code verifies your authentication with Stripe."))
var s *spinner.Spinner
pollResultCh := make(chan keys.AsyncPollResult)
inputCh := make(chan int)
if isSSH() || !canOpenBrowser() {
fmt.Printf("To authenticate with Stripe, please go to: %s\n", links.BrowserURL)
s = ansi.StartNewSpinner("Waiting for confirmation...", os.Stdout)
go a.keytransfer.AsyncPollKey(ctx, links.PollURL, 0, 0, pollResultCh)
} else {
fmt.Printf("Press Enter to open the browser or visit %s (^C to quit)", links.BrowserURL)
go a.asyncInputReader.scanln(inputCh)
go a.keytransfer.AsyncPollKey(ctx, links.PollURL, 0, 0, pollResultCh)
}
for {
select {
case <-inputCh:
s = ansi.StartNewSpinner("Waiting for confirmation...", os.Stdout)
err := openBrowser(links.BrowserURL)
if err != nil {
msg := fmt.Sprintf("Failed to open browser, please go to %s manually.", links.BrowserURL)
ansi.StopSpinner(s, msg, os.Stdout)
s = ansi.StartNewSpinner("Waiting for confirmation...", os.Stdout)
}
case res := <-pollResultCh:
if res.Err != nil {
return res.Err
}
message, err := SuccessMessage(ctx, res.Account, stripe.DefaultAPIBaseURL, res.TestModeAPIKey)
if err != nil {
fmt.Printf("> Error verifying the CLI was set up successfully: %s\n", err)
return err
}
if s == nil {
fmt.Printf("\n> %s\n", message)
} else {
ansi.StopSpinner(s, message, os.Stdout)
}
fmt.Println(ansi.Italic("Please note: this key will expire after 90 days, at which point you'll need to re-authenticate."))
return nil
}
}
}
func isSSH() bool {
if os.Getenv("SSH_TTY") != "" || os.Getenv("SSH_CONNECTION") != "" || os.Getenv("SSH_CLIENT") != "" {
return true
}
return false
}