@@ -2,10 +2,11 @@ package gitlabop
2
2
3
3
import (
4
4
"context"
5
+ "embed"
5
6
"encoding/json"
6
7
"fmt"
8
+ "html/template"
7
9
"io"
8
- "io/ioutil"
9
10
"math/rand"
10
11
"net/http"
11
12
"net/url"
@@ -103,7 +104,7 @@ func NewOAuth2Support(c *OAuth2Config) IGitlabOauth2Support {
103
104
tokenC : make (chan struct {}),
104
105
}
105
106
106
- go g ._proc ()
107
+ go g .serve ()
107
108
108
109
return g
109
110
}
@@ -144,55 +145,84 @@ func (g *gitlabOAuth2Support) Load() (accessToken, refreshToken string) {
144
145
return g .oc .AccessToken , g .oc .RefreshToken
145
146
}
146
147
147
- // _proc serving a backend HTTP server process to receive redirect requests from gitlab.
148
- func (g * gitlabOAuth2Support ) _proc () {
149
- var err error
150
- defer func () {
151
- if err != nil {
152
- log .Errorf ("gitlabOAuth2Support _proc quit: %v" , err )
153
- }
154
- }()
148
+ //go:embed callback.tmpl
149
+ var callbackTmpl embed.FS
155
150
156
- http . HandleFunc ( "/callback" , func (w http.ResponseWriter , r * http.Request ) {
157
- _ = r .ParseForm ()
158
- code := r .Form .Get ("code" )
159
- state := r .Form .Get ("state" )
160
- _error := r .Form .Get ("_error" )
161
- errorDescription := r .Form .Get ("error_description" )
151
+ func ( g * gitlabOAuth2Support ) callbackHandl (w http.ResponseWriter , r * http.Request ) {
152
+ _ = r .ParseForm ()
153
+ code := r .Form .Get ("code" )
154
+ state := r .Form .Get ("state" )
155
+ _error := r .Form .Get ("_error" )
156
+ errorDescription := r .Form .Get ("error_description" )
162
157
163
- log .
164
- WithFields (log.Fields {
165
- "code" : code ,
166
- "state" : state ,
167
- "_error" : _error ,
168
- "errorDescription" : errorDescription ,
169
- }).
170
- Debug ("gitlabOAuth2Support _proc gets a callback request" )
171
-
172
- if len (_error ) != 0 {
173
- w .WriteHeader (http .StatusInternalServerError )
174
- _ , _ = fmt .Fprint (w , _error , errorDescription )
175
- return
176
- }
158
+ log .WithFields (log.Fields {
159
+ "code" : code ,
160
+ "state" : state ,
161
+ "_error" : _error ,
162
+ "errorDescription" : errorDescription ,
163
+ }).Debug ("gitlabOAuth2Support serve gets a callback request" )
177
164
178
- if code != "" && state != "" {
179
- // authorization callback
180
- if err2 := g .requestToken (r .Context (), code , false ); err2 != nil {
181
- log .Errorf ("gitlabOAuth2Support _proc failed to get requestToken: %v" , err2 )
182
- w .WriteHeader (http .StatusInternalServerError )
183
- _ , _ = fmt .Fprint (w , err2 .Error ())
184
- return
185
- }
165
+ tmpl , err := template .ParseFS (callbackTmpl , "callback.tmpl" )
166
+ if err != nil {
167
+ log .Errorf ("gitlabOAuth2Support.callbackHandl parse FS failed: %v" , err )
168
+ }
169
+
170
+ var (
171
+ status = http .StatusOK
172
+ data = struct {
173
+ Error bool
174
+ ErrorMessage string
175
+ Now string
176
+ }{
177
+ Error : false ,
178
+ ErrorMessage : "" ,
179
+ Now : time .Now ().Format (time .RFC1123 ),
186
180
}
181
+ )
182
+
183
+ // error check and parameters validation check.
184
+ if len (_error ) != 0 {
185
+ data .Error = true
186
+ data .ErrorMessage = fmt .Sprintf ("%s (%s)" , _error , errorDescription )
187
+ status = http .StatusInternalServerError
188
+ goto render
189
+ }
190
+ if code == "" || state == "" {
191
+ data .Error = true
192
+ data .ErrorMessage = fmt .Sprintf ("Invalid Parameter(code:%s empty or state:%s is empty)" , code , state )
193
+ status = http .StatusBadRequest
194
+ goto render
195
+ }
196
+
197
+ // authorization callback is in line with forecast.
198
+ if err := g .requestToken (r .Context (), code , false ); err != nil {
199
+ log .Errorf ("gitlabOAuth2Support callbackHandl failed to requestToken: %v" , err )
200
+ data .Error = true
201
+ data .ErrorMessage = fmt .Sprintf ("Request Token Failed (%s)" , err .Error ())
202
+ status = http .StatusInternalServerError
203
+ goto render
204
+ }
205
+
206
+ log .Info ("gitlab-flow oauth authorization succeeded!" )
187
207
188
- w .WriteHeader (http .StatusOK )
189
- _ , _ = fmt .Fprint (w , "gitlab-flow oauth authorization succeeded!" )
190
- })
208
+ render:
209
+ w .WriteHeader (status )
210
+ if err := tmpl .Execute (w , & data ); err != nil {
211
+ log .Errorf ("gitlabOAuth2Support.callbackHandl failed to render: %v" , err )
212
+ }
213
+ }
191
214
192
- err = http .ListenAndServe (g .oc .ServeAddr , nil )
215
+ // serve is serving a backend HTTP server process to
216
+ // receive redirect requests from gitlab.
217
+ func (g * gitlabOAuth2Support ) serve () {
218
+ http .HandleFunc ("/callback" , g .callbackHandl )
219
+ err := http .ListenAndServe (g .oc .ServeAddr , nil )
220
+ if err != nil {
221
+ log .Errorf ("gitlabOAuth2Support serve quit: %v" , err )
222
+ }
193
223
}
194
224
195
- func (g * gitlabOAuth2Support ) calcState () string {
225
+ func (g * gitlabOAuth2Support ) generateState () string {
196
226
// DONE(@yeqown): replace state calculation with random int
197
227
g .state = strconv .Itoa (rand .Intn (int (time .Now ().UnixNano ())))
198
228
return g .state
@@ -204,7 +234,7 @@ func (g *gitlabOAuth2Support) triggerAuthorize(ctx context.Context) {
204
234
form .Add ("client_id" , OAuth2AppID )
205
235
form .Add ("redirect_uri" , fmt .Sprintf ("http://%s/callback" , g .oc .ServeAddr ))
206
236
form .Add ("response_type" , "code" )
207
- form .Add ("state" , g .calcState ())
237
+ form .Add ("state" , g .generateState ())
208
238
form .Add ("scope" , defaultScope )
209
239
210
240
fmt .Println ("Your access token is invalid or expired, please click following link to authorize:" )
@@ -299,7 +329,7 @@ func (g *gitlabOAuth2Support) _execPost(ctx context.Context, uri string, form ur
299
329
_ = Body .Close ()
300
330
}(r .Body )
301
331
302
- data , err := ioutil .ReadAll (r .Body )
332
+ data , err := io .ReadAll (r .Body )
303
333
if err != nil {
304
334
return errors .Wrap (err , "failed to read" )
305
335
}
0 commit comments