| 321 | } |
| 322 | |
| 323 | func (h oauthHandler) viewOauthCallback(app *App, w http.ResponseWriter, r *http.Request) error { |
| 324 | ctx := r.Context() |
| 325 | |
| 326 | code := r.FormValue("code") |
| 327 | state := r.FormValue("state") |
| 328 | |
| 329 | provider, clientID, attachUserID, inviteCode, err := h.DB.ValidateOAuthState(ctx, state) |
| 330 | if err != nil { |
| 331 | log.Error("Unable to ValidateOAuthState: %s", err) |
| 332 | return impart.HTTPError{http.StatusInternalServerError, err.Error()} |
| 333 | } |
| 334 | |
| 335 | tokenResponse, err := h.oauthClient.exchangeOauthCode(ctx, code) |
| 336 | if err != nil { |
| 337 | log.Error("Unable to exchangeOauthCode: %s", err) |
| 338 | // TODO: show user friendly message if needed |
| 339 | // TODO: show NO message for cases like user pressing "Cancel" on authorize step |
| 340 | addSessionFlash(app, w, r, err.Error(), nil) |
| 341 | if attachUserID > 0 { |
| 342 | return impart.HTTPError{http.StatusFound, "/me/settings"} |
| 343 | } |
| 344 | return impart.HTTPError{http.StatusInternalServerError, err.Error()} |
| 345 | } |
| 346 | |
| 347 | // Now that we have the access token, let's use it real quick to make sure |
| 348 | // it really really works. |
| 349 | tokenInfo, err := h.oauthClient.inspectOauthAccessToken(ctx, tokenResponse.AccessToken) |
| 350 | if err != nil { |
| 351 | log.Error("Unable to inspectOauthAccessToken: %s", err) |
| 352 | return impart.HTTPError{http.StatusInternalServerError, err.Error()} |
| 353 | } |
| 354 | |
| 355 | localUserID, err := h.DB.GetIDForRemoteUser(ctx, tokenInfo.UserID, provider, clientID) |
| 356 | if err != nil { |
| 357 | log.Error("Unable to GetIDForRemoteUser: %s", err) |
| 358 | return impart.HTTPError{http.StatusInternalServerError, err.Error()} |
| 359 | } |
| 360 | |
| 361 | if localUserID != -1 && attachUserID > 0 { |
| 362 | if err = addSessionFlash(app, w, r, "This OAuth account is already attached to another user.", nil); err != nil { |
| 363 | return impart.HTTPError{Status: http.StatusInternalServerError, Message: err.Error()} |
| 364 | } |
| 365 | return impart.HTTPError{http.StatusFound, "/me/settings"} |
| 366 | } |
| 367 | |
| 368 | if localUserID != -1 { |
| 369 | // Existing user, so log in now |
| 370 | user, err := h.DB.GetUserByID(localUserID) |
| 371 | if err != nil { |
| 372 | log.Error("Unable to GetUserByID %d: %s", localUserID, err) |
| 373 | return impart.HTTPError{http.StatusInternalServerError, err.Error()} |
| 374 | } |
| 375 | if err = loginOrFail(h.Store, w, r, user); err != nil { |
| 376 | log.Error("Unable to loginOrFail %d: %s", localUserID, err) |
| 377 | return impart.HTTPError{http.StatusInternalServerError, err.Error()} |
| 378 | } |
| 379 | return nil |
| 380 | } |