forked from railwayapp/cli
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathuser.go
More file actions
148 lines (136 loc) · 3.41 KB
/
Copy pathuser.go
File metadata and controls
148 lines (136 loc) · 3.41 KB
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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
package controller
import (
"context"
b64 "encoding/base64"
"encoding/json"
"errors"
"fmt"
"net/http"
"strconv"
"sync"
"github.com/pkg/browser"
configs "github.com/railwayapp/cli/configs"
"github.com/railwayapp/cli/entity"
)
const (
baseRailwayURL string = "https://railway.app"
baseLocalhostURL string = "http://localhost:3000"
)
const (
loginInvalidResponse string = "Invalid code"
loginSuccessResponse string = "Ok"
)
type LoginResponse struct {
Status string `json:"status,omitempty"`
Error string `json:"error,omitempty"`
}
func (c *Controller) GetUser(ctx context.Context) (*entity.User, error) {
userCfg, err := c.cfg.GetUserConfigs()
if err != nil {
return nil, err
}
if userCfg.Token == "" {
return nil, errors.New("Not logged in")
}
return c.gtwy.GetUser(ctx)
}
func (c *Controller) Login(ctx context.Context) (*entity.User, error) {
var token string
var returnedCode string
port, err := c.randomizer.Port()
if err != nil {
return nil, err
}
code := c.randomizer.Code()
wg := &sync.WaitGroup{}
wg.Add(1)
go func() {
ctx := context.Background()
srv := &http.Server{Addr: strconv.Itoa(port)}
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", getAPIURL())
if r.Method == http.MethodGet {
w.Header().Set("Content-Type", "application/json")
token = r.URL.Query().Get("token")
returnedCode = r.URL.Query().Get("code")
if code != returnedCode {
res := LoginResponse{Error: loginInvalidResponse}
byteRes, err := json.Marshal(&res)
if err != nil {
fmt.Println(err)
}
w.WriteHeader(400)
w.Write(byteRes)
return
}
res := LoginResponse{Status: loginSuccessResponse}
byteRes, err := json.Marshal(&res)
if err != nil {
fmt.Println(err)
}
w.WriteHeader(200)
w.Write(byteRes)
} else if r.Method == http.MethodOptions {
w.Header().Set("Access-Control-Allow-Methods", "GET, HEAD, PUT, PATCH, POST, DELETE")
w.Header().Set("Access-Control-Allow-Headers", "authorization")
w.Header().Set("Content-Length", "0")
w.WriteHeader(204)
return
}
wg.Done()
if err := srv.Shutdown(ctx); err != nil {
fmt.Println(err)
}
})
http.ListenAndServe(fmt.Sprintf("localhost:%d", port), nil)
}()
url := getLoginURL(port, code)
browser.OpenURL(url)
wg.Wait()
err = c.cfg.SetUserConfigs(&entity.UserConfig{
Token: token,
})
if err != nil {
return nil, err
}
if code == returnedCode {
return c.gtwy.GetUser(ctx)
}
return nil, nil
}
func (c *Controller) Logout(ctx context.Context) error {
// Logout by wiping user configs
userCfg, err := c.cfg.GetUserConfigs()
if err != nil {
return err
}
if userCfg.Token == "" {
fmt.Println("Already logged out")
return nil
}
err = c.cfg.SetUserConfigs(&entity.UserConfig{})
if err != nil {
return err
}
fmt.Println("Successfully logged out")
return nil
}
func (c *Controller) IsLoggedIn(ctx context.Context) (bool, error) {
userCfg, err := c.cfg.GetUserConfigs()
if err != nil {
return false, err
}
isLoggedIn := userCfg.Token != ""
return isLoggedIn, nil
}
func getAPIURL() string {
if configs.IsDevMode() {
return baseLocalhostURL
}
return baseRailwayURL
}
func getLoginURL(port int, code string) string {
buffer := b64.URLEncoding.EncodeToString([]byte(fmt.Sprintf("port=%d&code=%s", port, code)))
url := fmt.Sprintf("%s/cli-login?d=%s", getAPIURL(), buffer)
return url
}