-
Notifications
You must be signed in to change notification settings - Fork 361
/
client_login.go
123 lines (98 loc) · 2.96 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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package login
import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"
"os"
"github.com/stripe/stripe-cli/pkg/ansi"
"github.com/stripe/stripe-cli/pkg/config"
"github.com/stripe/stripe-cli/pkg/open"
"github.com/stripe/stripe-cli/pkg/stripe"
"github.com/stripe/stripe-cli/pkg/validators"
)
var openBrowser = open.Browser
const stripeCLIAuthPath = "/stripecli/auth"
// Links provides the URLs for the CLI to continue the login flow
type Links struct {
BrowserURL string `json:"browser_url"`
PollURL string `json:"poll_url"`
VerificationCode string `json:"verification_code"`
}
//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
*/
// Login function is used to obtain credentials via stripe dashboard.
func Login(baseURL string, config *config.Config, input io.Reader) error {
links, err := getLinks(baseURL, config.Profile.DeviceName)
if err != nil {
return err
}
color := ansi.Color(os.Stdout)
fmt.Printf("Your pairing code is: %s\n", color.Bold(links.VerificationCode))
fmt.Printf("Press Enter to open up the browser (^C to quit)")
fmt.Fscanln(input)
s := ansi.StartSpinner("Waiting for confirmation...", os.Stdout)
urlErr := openBrowser(links.BrowserURL)
if urlErr != nil {
return urlErr
}
//Call poll function
response, account, err := PollForKey(links.PollURL, 0, 0)
if err != nil {
return err
}
validateErr := validators.APIKey(response.TestModeAPIKey)
if validateErr != nil {
return validateErr
}
config.Profile.TestModeAPIKey = response.TestModeAPIKey
config.Profile.TestModePublishableKey = response.TestModePublishableKey
profileErr := config.Profile.CreateProfile()
if profileErr != nil {
return profileErr
}
message, err := SuccessMessage(account, stripe.DefaultAPIBaseURL, response.TestModeAPIKey)
if err != nil {
fmt.Println(fmt.Sprintf("> Error verifying the CLI was set up successfully: %s", err))
} 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 getLinks(baseURL string, deviceName string) (*Links, error) {
parsedBaseURL, err := url.Parse(baseURL)
if err != nil {
return nil, err
}
client := &stripe.Client{
BaseURL: parsedBaseURL,
}
data := url.Values{}
data.Set("device_name", deviceName)
res, err := client.PerformRequest(http.MethodPost, stripeCLIAuthPath, data.Encode(), nil)
if err != nil {
return nil, err
}
defer res.Body.Close()
bodyBytes, err := ioutil.ReadAll(res.Body)
if err != nil {
return nil, err
}
if res.StatusCode != http.StatusOK {
return nil, fmt.Errorf("unexpected http status code: %d %s", res.StatusCode, string(bodyBytes))
}
var links Links
err = json.Unmarshal(bodyBytes, &links)
if err != nil {
return nil, err
}
return &links, nil
}