main
rb 68 lines 2.51 KB
Raw
1 # frozen_string_literal: true
2
3 # Connects a user's GitHub account for repository imports via our own GitHub
4 # OAuth app (separate from smbCloud sign-in). The resulting token is stored
5 # encrypted in GithubConnection and never leaves the server.
6 class GithubConnectionsController < ApplicationController
7 before_action :require_sign_in!
8 before_action :noindex!
9
10 # GET /import/github/connect
11 # Kicks off the OAuth dance. `visibility=public` narrows the scope to public
12 # repos only; the default requests `repo` so private repos can be imported.
13 def connect
14 unless GithubOauthService.configured?
15 return redirect_to new_import_path, alert: "GitHub import isn't configured on this server yet."
16 end
17
18 state = GithubOauthService.generate_state
19 session[:github_import_state] = state
20
21 include_private = params[:visibility] != "public"
22 redirect_to GithubOauthService.authorize_url(
23 redirect_uri: github_import_callback_url,
24 state: state,
25 include_private: include_private
26 ), allow_other_host: true
27 end
28
29 # GET /import/github/callback
30 def callback
31 if params[:error].present?
32 return redirect_to new_import_path, alert: "GitHub connection was cancelled."
33 end
34
35 # CSRF: the state we set must round-trip back unchanged.
36 expected = session.delete(:github_import_state)
37 if expected.blank? || !ActiveSupport::SecurityUtils.secure_compare(params[:state].to_s, expected)
38 return redirect_to new_import_path, alert: "GitHub connection failed a security check. Please try again."
39 end
40
41 token = GithubOauthService.exchange_code(
42 code: params[:code].to_s,
43 redirect_uri: github_import_callback_url
44 )
45
46 login = GithubApiClient.new(token[:access_token]).login
47
48 connection = current_user.github_connection || current_user.build_github_connection
49 connection.update!(
50 access_token: token[:access_token],
51 scope: token[:scope],
52 token_type: token[:token_type],
53 github_login: login,
54 connected_at: Time.current
55 )
56
57 redirect_to new_import_path, notice: "Connected to GitHub#{login ? " as @#{login}" : ''}."
58 rescue GithubOauthService::ExchangeError, GithubOauthService::ConfigurationError => e
59 Rails.logger.warn("GitHub import connect failed: #{e.class}")
60 redirect_to new_import_path, alert: "Couldn't connect to GitHub. Please try again."
61 end
62
63 # DELETE /import/github/disconnect
64 def disconnect
65 current_user.github_connection&.destroy
66 redirect_to new_import_path, notice: "Disconnected from GitHub."
67 end
68 end