Skip to content

Commit 20a6544

Browse files
committed
♻️ Refactor logger in auth
1 parent abe4f99 commit 20a6544

File tree

2 files changed

+77
-57
lines changed

2 files changed

+77
-57
lines changed

pkg/auth/auth.go

Lines changed: 62 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,8 @@ package auth
33
import (
44
"context"
55
"encoding/json"
6-
"errors"
76
"fmt"
8-
"log"
7+
"log/slog"
98
"net"
109
"net/http"
1110
"net/url"
@@ -20,6 +19,17 @@ import (
2019
)
2120

2221
const (
22+
createSvcFailed = "failed to create YouTube service"
23+
parseUrlFailed = "failed to parse redirect URL"
24+
stateMatchFailed = "state doesn't match, possible CSRF attack"
25+
readPromptFailed = "failed to read prompt"
26+
exchangeFailed = "failed to exchange token"
27+
listenFailed = "failed to start web server"
28+
cacheTokenFailed = "failed to cache token"
29+
parseTokenFailed = "failed to parse token"
30+
refreshTokenFailed = "failed to refresh token, please re-authenticate in cli"
31+
parseSecretFailed = "failed to parse client secret"
32+
2333
cacheTokenFile = "youtube.token.json"
2434
credentialFile = "client_secret.json"
2535
manualInputHint = `
@@ -33,16 +43,7 @@ ONLY 'COPY-THIS' part is the code you need to enter on command line.
3343
)
3444

3545
var (
36-
state = utils.RandomStage()
37-
errStateMismatch = errors.New("state doesn't match, possible CSRF attack")
38-
errReadPrompt = errors.New("unable to read prompt")
39-
errExchange = errors.New("unable retrieve token from web or prompt")
40-
errStartWeb = errors.New("unable to start web server")
41-
errCacheToken = errors.New("unable to cache token")
42-
errParseToken = errors.New("unable to parse token")
43-
errRefreshToken = errors.New("unable to refresh token, please re-authenticate in cli")
44-
errParseSecret = errors.New("unable to parse client secret")
45-
46+
state = utils.RandomStage()
4647
scope = []string{
4748
youtube.YoutubeScope,
4849
youtube.YoutubeForceSslScope,
@@ -54,7 +55,8 @@ func (s *svc) GetService() *youtube.Service {
5455
client := s.refreshClient()
5556
service, err := youtube.NewService(s.ctx, option.WithHTTPClient(client))
5657
if err != nil {
57-
log.Fatalln(errors.Join(errCreateSvc, err))
58+
slog.Error(createSvcFailed, "error", err)
59+
os.Exit(1)
5860
}
5961
s.service = service
6062

@@ -81,7 +83,8 @@ func (s *svc) refreshClient() (client *http.Client) {
8183
s.saveToken(cacheTokenFile, authedToken)
8284
return client
8385
} else if err != nil {
84-
log.Fatalln(errors.Join(errRefreshToken, err))
86+
slog.Error(refreshTokenFailed, "error", err)
87+
os.Exit(1)
8588
}
8689

8790
if authedToken != nil && s.Cacheable {
@@ -106,7 +109,8 @@ func (s *svc) newClient(config *oauth2.Config) (
106109
func (s *svc) getConfig() *oauth2.Config {
107110
config, err := google.ConfigFromJSON([]byte(s.Credential), scope...)
108111
if err != nil {
109-
log.Fatalln(errors.Join(errParseSecret, err))
112+
slog.Error(parseSecretFailed, "error", err)
113+
os.Exit(1)
110114
}
111115

112116
return config
@@ -115,35 +119,45 @@ func (s *svc) getConfig() *oauth2.Config {
115119
func (s *svc) startWebServer(redirectURL string) chan string {
116120
u, err := url.Parse(redirectURL)
117121
if err != nil {
118-
log.Fatalln(errors.Join(errStartWeb, err))
122+
slog.Error(parseUrlFailed, "url", redirectURL, "error", err)
123+
os.Exit(1)
119124
}
120125

121126
listener, err := net.Listen("tcp", u.Host)
122127
if err != nil {
123-
log.Fatalln(errors.Join(errStartWeb, err))
128+
slog.Error(listenFailed, "host", u.Host, "error", err)
129+
os.Exit(1)
124130
}
125131

126132
codeCh := make(chan string)
127-
go http.Serve(
128-
listener, http.HandlerFunc(
129-
func(w http.ResponseWriter, r *http.Request) {
130-
if r.URL.Path != "/" {
131-
return
132-
}
133-
s := r.FormValue("state")
134-
if s != state {
135-
log.Fatalf("%v: %s != %s\n", errStateMismatch, s, state)
136-
}
137-
code := r.FormValue("code")
138-
codeCh <- code
139-
_ = listener.Close()
140-
w.Header().Set("Content-Type", "text/plain")
141-
_, _ = fmt.Fprintf(
142-
w, "Received code: %s\r\nYou can now safely close this window.", code,
143-
)
144-
},
145-
),
146-
)
133+
go func() {
134+
_ = http.Serve(
135+
listener, http.HandlerFunc(
136+
func(w http.ResponseWriter, r *http.Request) {
137+
if r.URL.Path != "/" {
138+
return
139+
}
140+
s := r.FormValue("state")
141+
if s != state {
142+
slog.Error(
143+
stateMatchFailed,
144+
"actual", s,
145+
"expected", state,
146+
)
147+
os.Exit(1)
148+
}
149+
code := r.FormValue("code")
150+
codeCh <- code
151+
_ = listener.Close()
152+
w.Header().Set("Content-Type", "text/plain")
153+
_, _ = fmt.Fprintf(
154+
w, "Received code: %s\r\nYou can now safely close this window.",
155+
code,
156+
)
157+
},
158+
),
159+
)
160+
}()
147161

148162
return codeCh
149163
}
@@ -156,7 +170,8 @@ func (s *svc) getCodeFromPrompt(authURL string) (code string) {
156170
fmt.Print(manualInputHint)
157171
_, err := fmt.Scan(&code)
158172
if err != nil {
159-
log.Fatalln(errors.Join(errReadPrompt, err))
173+
slog.Error(readPromptFailed, "error", err)
174+
os.Exit(1)
160175
}
161176

162177
if strings.HasPrefix(code, "4%2F") {
@@ -187,7 +202,8 @@ func (s *svc) getTokenFromWeb(
187202
fmt.Printf("Authorization code generated: %s\n", code)
188203
token, err := config.Exchange(context.TODO(), code)
189204
if err != nil {
190-
log.Fatalln(errors.Join(errExchange, err))
205+
slog.Error(exchangeFailed, "error", err)
206+
os.Exit(1)
191207
}
192208

193209
return token
@@ -196,12 +212,16 @@ func (s *svc) getTokenFromWeb(
196212
func (s *svc) saveToken(file string, token *oauth2.Token) {
197213
f, err := os.OpenFile(file, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
198214
if err != nil {
199-
log.Fatalln(errors.Join(errCacheToken, err))
215+
slog.Error(cacheTokenFailed, "file", file, "error", err)
216+
os.Exit(1)
200217
}
201218

202-
defer f.Close()
219+
defer func() {
220+
_ = f.Close()
221+
}()
203222
err = json.NewEncoder(f).Encode(token)
204223
if err != nil {
205-
log.Fatalln(errors.Join(errCacheToken, err))
224+
slog.Error(cacheTokenFailed, "error", err)
225+
os.Exit(1)
206226
}
207227
}

pkg/auth/service.go

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,8 @@ package auth
33
import (
44
"context"
55
"encoding/base64"
6-
"errors"
7-
"fmt"
86
"io/fs"
9-
"log"
7+
"log/slog"
108
"net/http"
119
"os"
1210
"path/filepath"
@@ -17,14 +15,12 @@ import (
1715
"google.golang.org/api/youtube/v3"
1816
)
1917

20-
var (
21-
errCreateSvc = errors.New("unable to create YouTube service")
22-
errReadToken = errors.New("unable to read token")
23-
errReadSecret = errors.New("unable to read client secret")
18+
const (
19+
readTokenFailed = "failed to read token"
20+
readSecretFailed = "failed to read client secret"
21+
authHint = "Please configure client secret as described in https://github.com/eat-pray-ai/yutu#prerequisites"
2422
)
2523

26-
const missingClientSecretsHint string = "Please configure client secrets as described in https://github.com/eat-pray-ai/yutu#prerequisites"
27-
2824
type svc struct {
2925
Cacheable bool `yaml:"cacheable" json:"cacheable"`
3026
Credential string `yaml:"credential" json:"credential"`
@@ -75,8 +71,10 @@ func WithCredential(cred string, fsys fs.FS) Option {
7571
// credBytes, err := yfs.ReadFile(cred)
7672
credBytes, err := fs.ReadFile(fsys, relCred)
7773
if err != nil {
78-
fmt.Println(missingClientSecretsHint)
79-
log.Fatalln(errors.Join(errReadSecret, err))
74+
slog.Error(
75+
readSecretFailed, "hint", authHint, "path", absCred, "error", err,
76+
)
77+
os.Exit(1)
8078
}
8179
s.Credential = string(credBytes)
8280
return
@@ -87,8 +85,8 @@ func WithCredential(cred string, fsys fs.FS) Option {
8785
} else if utils.IsJson(cred) {
8886
s.Credential = cred
8987
} else {
90-
fmt.Println(missingClientSecretsHint)
91-
log.Fatalln(errors.Join(errReadSecret, err))
88+
slog.Error(parseSecretFailed, "hint", authHint, "error", err)
89+
os.Exit(1)
9290
}
9391
}
9492
}
@@ -112,7 +110,8 @@ func WithCacheToken(token string, fsys fs.FS) Option {
112110
if _, err := fs.Stat(fsys, relToken); err == nil {
113111
tokenBytes, err := fs.ReadFile(fsys, relToken)
114112
if err != nil {
115-
log.Fatalln(errors.Join(errReadToken, err))
113+
slog.Error(readTokenFailed, "path", absToken, "error", err)
114+
os.Exit(1)
116115
}
117116
s.CacheToken = string(tokenBytes)
118117
s.Cacheable = true
@@ -128,7 +127,8 @@ func WithCacheToken(token string, fsys fs.FS) Option {
128127
} else if utils.IsJson(token) {
129128
s.CacheToken = token
130129
} else {
131-
log.Fatalln(errors.Join(errReadToken, err))
130+
slog.Error(parseTokenFailed, "error", err)
131+
os.Exit(1)
132132
}
133133
}
134134
}

0 commit comments

Comments
 (0)