Skip to content

Commit 432dfd4

Browse files
committed
♻️ Refactor auth flow
1 parent 20a6544 commit 432dfd4

File tree

3 files changed

+38
-37
lines changed

3 files changed

+38
-37
lines changed

cmd/auth.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ var authCmd = &cobra.Command{
2626
auth.NewY2BService(
2727
auth.WithCredential(credential, pkg.Fsys),
2828
auth.WithCacheToken(cacheToken, pkg.Fsys),
29-
)
29+
).GetService()
3030
},
3131
}
3232

pkg/auth/auth.go

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"net/http"
1010
"net/url"
1111
"os"
12+
"path/filepath"
1213
"strings"
1314

1415
"github.com/eat-pray-ai/yutu/pkg/utils"
@@ -30,9 +31,9 @@ const (
3031
refreshTokenFailed = "failed to refresh token, please re-authenticate in cli"
3132
parseSecretFailed = "failed to parse client secret"
3233

33-
cacheTokenFile = "youtube.token.json"
34-
credentialFile = "client_secret.json"
35-
manualInputHint = `
34+
browserOpenedHint = "Your browser has been opened to an authorization URL. yutu will resume once authorization has been provided.\n%s\n"
35+
openBrowserHint = "It seems that your browser is not open. Go to the following link in your browser:\n%s\n"
36+
manualInputHint = `
3637
After completing the authorization flow, enter the authorization code on command line.
3738
3839
If you end up in an error page after completing the authorization flow,
@@ -69,26 +70,26 @@ func (s *svc) refreshClient() (client *http.Client) {
6970
err := json.Unmarshal([]byte(s.CacheToken), authedToken)
7071
if err != nil {
7172
client, authedToken = s.newClient(config)
72-
if s.Cacheable {
73-
s.saveToken(cacheTokenFile, authedToken)
73+
if s.tokenFile != "" {
74+
s.saveToken(authedToken)
7475
}
7576
return client
7677
}
7778

7879
if !authedToken.Valid() {
7980
tokenSource := config.TokenSource(s.ctx, authedToken)
8081
authedToken, err = tokenSource.Token()
81-
if err != nil && s.Cacheable {
82+
if err != nil && s.tokenFile != "" {
8283
client, authedToken = s.newClient(config)
83-
s.saveToken(cacheTokenFile, authedToken)
84+
s.saveToken(authedToken)
8485
return client
8586
} else if err != nil {
8687
slog.Error(refreshTokenFailed, "error", err)
8788
os.Exit(1)
8889
}
8990

90-
if authedToken != nil && s.Cacheable {
91-
s.saveToken(cacheTokenFile, authedToken)
91+
if authedToken != nil && s.tokenFile != "" {
92+
s.saveToken(authedToken)
9293
}
9394
return config.Client(s.ctx, authedToken)
9495
}
@@ -163,10 +164,7 @@ func (s *svc) startWebServer(redirectURL string) chan string {
163164
}
164165

165166
func (s *svc) getCodeFromPrompt(authURL string) (code string) {
166-
fmt.Printf(
167-
"It seems that your browser is not open. Go to the following "+
168-
"link in your browser:\n%s\n", authURL,
169-
)
167+
fmt.Printf(openBrowserHint, authURL)
170168
fmt.Print(manualInputHint)
171169
_, err := fmt.Scan(&code)
172170
if err != nil {
@@ -187,19 +185,15 @@ func (s *svc) getTokenFromWeb(
187185

188186
var code string
189187
if err := utils.OpenURL(authURL); err == nil {
190-
fmt.Printf(
191-
"Your browser has been opened to an authorization URL. This "+
192-
"program will resume once authorization has been provided.\n%s\n",
193-
authURL,
194-
)
188+
fmt.Printf(browserOpenedHint, authURL)
195189
code = <-codeCh
196190
}
197191

198192
if code == "" {
199193
code = s.getCodeFromPrompt(authURL)
200194
}
201195

202-
fmt.Printf("Authorization code generated: %s\n", code)
196+
slog.Debug("Authorization code generated", "code", code)
203197
token, err := config.Exchange(context.TODO(), code)
204198
if err != nil {
205199
slog.Error(exchangeFailed, "error", err)
@@ -209,10 +203,16 @@ func (s *svc) getTokenFromWeb(
209203
return token
210204
}
211205

212-
func (s *svc) saveToken(file string, token *oauth2.Token) {
213-
f, err := os.OpenFile(file, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
206+
func (s *svc) saveToken(token *oauth2.Token) {
207+
dir := filepath.Dir(s.tokenFile)
208+
if err := os.MkdirAll(dir, 0755); err != nil {
209+
slog.Error(cacheTokenFailed, "dir", dir, "error", err)
210+
os.Exit(1)
211+
}
212+
213+
f, err := os.OpenFile(s.tokenFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
214214
if err != nil {
215-
slog.Error(cacheTokenFailed, "file", file, "error", err)
215+
slog.Error(cacheTokenFailed, "file", s.tokenFile, "error", err)
216216
os.Exit(1)
217217
}
218218

@@ -224,4 +224,5 @@ func (s *svc) saveToken(file string, token *oauth2.Token) {
224224
slog.Error(cacheTokenFailed, "error", err)
225225
os.Exit(1)
226226
}
227+
slog.Info("Token cached to file", "file", s.tokenFile)
227228
}

pkg/auth/service.go

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,13 @@ const (
2222
)
2323

2424
type svc struct {
25-
Cacheable bool `yaml:"cacheable" json:"cacheable"`
2625
Credential string `yaml:"credential" json:"credential"`
2726
CacheToken string `yaml:"cache_token" json:"cache_token"`
28-
service *youtube.Service
29-
ctx context.Context
27+
credFile string
28+
tokenFile string
29+
30+
service *youtube.Service
31+
ctx context.Context
3032
}
3133

3234
type Svc interface {
@@ -37,14 +39,15 @@ type Svc interface {
3739
startWebServer(string) chan string
3840
getTokenFromWeb(*oauth2.Config, string) *oauth2.Token
3941
getCodeFromPrompt(string) string
40-
saveToken(string, *oauth2.Token)
42+
saveToken(*oauth2.Token)
4143
}
4244

4345
type Option func(*svc)
4446

4547
func NewY2BService(opts ...Option) Svc {
4648
s := &svc{}
4749
s.ctx = context.Background()
50+
s.credFile = "client_secret.json"
4851

4952
for _, opt := range opts {
5053
opt(s)
@@ -59,7 +62,7 @@ func WithCredential(cred string, fsys fs.FS) Option {
5962
if cred == "" && ok {
6063
cred = envCred
6164
} else if cred == "" {
62-
cred = credentialFile
65+
cred = s.credFile
6366
}
6467
// 1. cred is a file path
6568
// 2. cred is a base64 encoded string
@@ -68,7 +71,7 @@ func WithCredential(cred string, fsys fs.FS) Option {
6871
relCred, _ := filepath.Rel("/", absCred)
6972

7073
if _, err := fs.Stat(fsys, relCred); err == nil {
71-
// credBytes, err := yfs.ReadFile(cred)
74+
s.credFile = absCred
7275
credBytes, err := fs.ReadFile(fsys, relCred)
7376
if err != nil {
7477
slog.Error(
@@ -98,7 +101,7 @@ func WithCacheToken(token string, fsys fs.FS) Option {
98101
if token == "" && ok {
99102
token = envToken
100103
} else if token == "" {
101-
token = cacheTokenFile
104+
token = "youtube.token.json"
102105
}
103106

104107
// 1. token is a file path
@@ -110,15 +113,13 @@ func WithCacheToken(token string, fsys fs.FS) Option {
110113
if _, err := fs.Stat(fsys, relToken); err == nil {
111114
tokenBytes, err := fs.ReadFile(fsys, relToken)
112115
if err != nil {
113-
slog.Error(readTokenFailed, "path", absToken, "error", err)
114-
os.Exit(1)
116+
slog.Warn(readTokenFailed, "path", absToken, "error", err)
115117
}
118+
s.tokenFile = absToken
116119
s.CacheToken = string(tokenBytes)
117-
s.Cacheable = true
118120
return
119121
} else if os.IsNotExist(err) && strings.HasSuffix(token, ".json") {
120-
s.CacheToken = token
121-
s.Cacheable = true
122+
s.tokenFile = absToken
122123
return
123124
}
124125

@@ -127,8 +128,7 @@ func WithCacheToken(token string, fsys fs.FS) Option {
127128
} else if utils.IsJson(token) {
128129
s.CacheToken = token
129130
} else {
130-
slog.Error(parseTokenFailed, "error", err)
131-
os.Exit(1)
131+
slog.Warn(parseTokenFailed, "error", err)
132132
}
133133
}
134134
}

0 commit comments

Comments
 (0)