githubConnectCallback is called after a Github App authorization flow initiated by githubConnect has completed. This call can originate from users who are not logged in in cases like admin user accepting installation request, removing existing installation etc. It's implemented as a non-gRPC endpoin
(w http.ResponseWriter, r *http.Request)
| 574 | // - Save user's github username in the users table |
| 575 | // - navigate to request page |
| 576 | func (s *Server) githubConnectCallback(w http.ResponseWriter, r *http.Request) { |
| 577 | ctx := r.Context() |
| 578 | |
| 579 | // Extract info from query string |
| 580 | qry := r.URL.Query() |
| 581 | setupAction := qry.Get("setup_action") |
| 582 | if setupAction != "install" && setupAction != "update" && setupAction != "request" { |
| 583 | http.Error(w, fmt.Sprintf("unexpected setup_action=%q", setupAction), http.StatusBadRequest) |
| 584 | return |
| 585 | } |
| 586 | |
| 587 | claims := auth.GetClaims(r.Context()) |
| 588 | if claims.OwnerType() != auth.OwnerTypeUser { |
| 589 | s.redirectLogin(w, r) |
| 590 | return |
| 591 | } |
| 592 | |
| 593 | code := qry.Get("code") |
| 594 | if code == "" { |
| 595 | if setupAction == "install" || !qry.Has("state") { |
| 596 | http.Error(w, "unable to verify user's identity", http.StatusInternalServerError) |
| 597 | return |
| 598 | } |
| 599 | |
| 600 | remoteURL := qry.Get("state") |
| 601 | remoteURL = normalizeGitRemote(remoteURL) // Backwards compatibility |
| 602 | redirectURL := s.admin.URLs.GithubConnectRequestUI(remoteURL) |
| 603 | http.Redirect(w, r, redirectURL, http.StatusTemporaryRedirect) |
| 604 | return |
| 605 | } |
| 606 | |
| 607 | // exchange code to get an auth token and create a github client with user auth |
| 608 | githubClient, githubToken, err := s.userAuthGithubClient(ctx, code) |
| 609 | if err != nil { |
| 610 | http.Error(w, "unauthorised user", http.StatusUnauthorized) |
| 611 | return |
| 612 | } |
| 613 | |
| 614 | githubUser, _, err := githubClient.Users.Get(ctx, "") |
| 615 | if err != nil { |
| 616 | // todo :: can this throw Requires authentication error ?? |
| 617 | http.Error(w, "unauthorised user", http.StatusUnauthorized) |
| 618 | return |
| 619 | } |
| 620 | |
| 621 | // save github user name |
| 622 | user, err := s.admin.DB.FindUser(ctx, claims.OwnerID()) |
| 623 | if err != nil { |
| 624 | // user is always guaranteed to exist if it reaches here |
| 625 | http.Error(w, "internal error", http.StatusInternalServerError) |
| 626 | return |
| 627 | } |
| 628 | |
| 629 | user, err = s.admin.DB.UpdateUser(ctx, user.ID, &database.UpdateUserOptions{ |
| 630 | DisplayName: user.DisplayName, |
| 631 | PhotoURL: user.PhotoURL, |
| 632 | GithubUsername: githubUser.GetLogin(), |
| 633 | GithubToken: githubToken.AccessToken, |
nothing calls this directly
no test coverage detected