@@ -3,9 +3,8 @@ package auth
3
3
import (
4
4
"context"
5
5
"encoding/json"
6
- "errors"
7
6
"fmt"
8
- "log"
7
+ "log/slog "
9
8
"net"
10
9
"net/http"
11
10
"net/url"
@@ -20,6 +19,17 @@ import (
20
19
)
21
20
22
21
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
+
23
33
cacheTokenFile = "youtube.token.json"
24
34
credentialFile = "client_secret.json"
25
35
manualInputHint = `
@@ -33,16 +43,7 @@ ONLY 'COPY-THIS' part is the code you need to enter on command line.
33
43
)
34
44
35
45
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 ()
46
47
scope = []string {
47
48
youtube .YoutubeScope ,
48
49
youtube .YoutubeForceSslScope ,
@@ -54,7 +55,8 @@ func (s *svc) GetService() *youtube.Service {
54
55
client := s .refreshClient ()
55
56
service , err := youtube .NewService (s .ctx , option .WithHTTPClient (client ))
56
57
if err != nil {
57
- log .Fatalln (errors .Join (errCreateSvc , err ))
58
+ slog .Error (createSvcFailed , "error" , err )
59
+ os .Exit (1 )
58
60
}
59
61
s .service = service
60
62
@@ -81,7 +83,8 @@ func (s *svc) refreshClient() (client *http.Client) {
81
83
s .saveToken (cacheTokenFile , authedToken )
82
84
return client
83
85
} else if err != nil {
84
- log .Fatalln (errors .Join (errRefreshToken , err ))
86
+ slog .Error (refreshTokenFailed , "error" , err )
87
+ os .Exit (1 )
85
88
}
86
89
87
90
if authedToken != nil && s .Cacheable {
@@ -106,7 +109,8 @@ func (s *svc) newClient(config *oauth2.Config) (
106
109
func (s * svc ) getConfig () * oauth2.Config {
107
110
config , err := google .ConfigFromJSON ([]byte (s .Credential ), scope ... )
108
111
if err != nil {
109
- log .Fatalln (errors .Join (errParseSecret , err ))
112
+ slog .Error (parseSecretFailed , "error" , err )
113
+ os .Exit (1 )
110
114
}
111
115
112
116
return config
@@ -115,35 +119,45 @@ func (s *svc) getConfig() *oauth2.Config {
115
119
func (s * svc ) startWebServer (redirectURL string ) chan string {
116
120
u , err := url .Parse (redirectURL )
117
121
if err != nil {
118
- log .Fatalln (errors .Join (errStartWeb , err ))
122
+ slog .Error (parseUrlFailed , "url" , redirectURL , "error" , err )
123
+ os .Exit (1 )
119
124
}
120
125
121
126
listener , err := net .Listen ("tcp" , u .Host )
122
127
if err != nil {
123
- log .Fatalln (errors .Join (errStartWeb , err ))
128
+ slog .Error (listenFailed , "host" , u .Host , "error" , err )
129
+ os .Exit (1 )
124
130
}
125
131
126
132
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 \n You 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 \n You can now safely close this window." ,
155
+ code ,
156
+ )
157
+ },
158
+ ),
159
+ )
160
+ }()
147
161
148
162
return codeCh
149
163
}
@@ -156,7 +170,8 @@ func (s *svc) getCodeFromPrompt(authURL string) (code string) {
156
170
fmt .Print (manualInputHint )
157
171
_ , err := fmt .Scan (& code )
158
172
if err != nil {
159
- log .Fatalln (errors .Join (errReadPrompt , err ))
173
+ slog .Error (readPromptFailed , "error" , err )
174
+ os .Exit (1 )
160
175
}
161
176
162
177
if strings .HasPrefix (code , "4%2F" ) {
@@ -187,7 +202,8 @@ func (s *svc) getTokenFromWeb(
187
202
fmt .Printf ("Authorization code generated: %s\n " , code )
188
203
token , err := config .Exchange (context .TODO (), code )
189
204
if err != nil {
190
- log .Fatalln (errors .Join (errExchange , err ))
205
+ slog .Error (exchangeFailed , "error" , err )
206
+ os .Exit (1 )
191
207
}
192
208
193
209
return token
@@ -196,12 +212,16 @@ func (s *svc) getTokenFromWeb(
196
212
func (s * svc ) saveToken (file string , token * oauth2.Token ) {
197
213
f , err := os .OpenFile (file , os .O_RDWR | os .O_CREATE | os .O_TRUNC , 0600 )
198
214
if err != nil {
199
- log .Fatalln (errors .Join (errCacheToken , err ))
215
+ slog .Error (cacheTokenFailed , "file" , file , "error" , err )
216
+ os .Exit (1 )
200
217
}
201
218
202
- defer f .Close ()
219
+ defer func () {
220
+ _ = f .Close ()
221
+ }()
203
222
err = json .NewEncoder (f ).Encode (token )
204
223
if err != nil {
205
- log .Fatalln (errors .Join (errCacheToken , err ))
224
+ slog .Error (cacheTokenFailed , "error" , err )
225
+ os .Exit (1 )
206
226
}
207
227
}
0 commit comments