summaryrefslogtreecommitdiff
path: root/app/controllers/repositories/git_http_controller.rb
blob: 118036de230323c7e2b6a4a2238468c4a7c6d431 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# frozen_string_literal: true

module Repositories
  class GitHttpController < Repositories::GitHttpClientController
    include WorkhorseRequest

    before_action :snippet_request_allowed?
    before_action :access_check
    prepend_before_action :deny_head_requests, only: [:info_refs]

    rescue_from Gitlab::GitAccess::ForbiddenError, with: :render_403_with_exception
    rescue_from Gitlab::GitAccess::NotFoundError, with: :render_404_with_exception
    rescue_from Gitlab::GitAccess::ProjectCreationError, with: :render_422_with_exception
    rescue_from Gitlab::GitAccess::TimeoutError, with: :render_503_with_exception

    # GET /foo/bar.git/info/refs?service=git-upload-pack (git pull)
    # GET /foo/bar.git/info/refs?service=git-receive-pack (git push)
    def info_refs
      log_user_activity if upload_pack?

      render_ok
    end

    # POST /foo/bar.git/git-upload-pack (git pull)
    def git_upload_pack
      update_fetch_statistics

      render_ok
    end

    # POST /foo/bar.git/git-receive-pack" (git push)
    def git_receive_pack
      render_ok
    end

    private

    def deny_head_requests
      head :forbidden if request.head?
    end

    def download_request?
      upload_pack?
    end

    def upload_pack?
      git_command == 'git-upload-pack'
    end

    def git_command
      if action_name == 'info_refs'
        params[:service]
      else
        action_name.dasherize
      end
    end

    def render_ok
      set_workhorse_internal_api_content_type
      render json: Gitlab::Workhorse.git_http_ok(repository, repo_type, user, action_name)
    end

    def render_403_with_exception(exception)
      render plain: exception.message, status: :forbidden
    end

    def render_404_with_exception(exception)
      render plain: exception.message, status: :not_found
    end

    def render_422_with_exception(exception)
      render plain: exception.message, status: :unprocessable_entity
    end

    def render_503_with_exception(exception)
      render plain: exception.message, status: :service_unavailable
    end

    def update_fetch_statistics
      return unless project
      return if Gitlab::Database.read_only?
      return unless repo_type.project?

      if Feature.enabled?(:project_statistics_sync, project, default_enabled: true)
        Projects::FetchStatisticsIncrementService.new(project).execute
      else
        ProjectDailyStatisticsWorker.perform_async(project.id) # rubocop:disable CodeReuse/Worker
      end
    end

    def access
      @access ||= access_klass.new(access_actor, container, 'http',
        authentication_abilities: authentication_abilities,
        namespace_path: params[:namespace_id],
        repository_path: repository_path,
        redirected_path: redirected_path,
        auth_result_type: auth_result_type)
    end

    def access_actor
      return user if user
      return :ci if ci?
    end

    def access_check
      access.check(git_command, Gitlab::GitAccess::ANY)

      if repo_type.project? && !container
        @project = @container = access.project
      end
    end

    def access_klass
      @access_klass ||= repo_type.access_checker_class
    end

    def repository_path
      @repository_path ||= params[:repository_id].sub(/\.git$/, '')
    end

    def log_user_activity
      Users::ActivityService.new(user).execute
    end

    def snippet_request_allowed?
      if repo_type.snippet? && Feature.disabled?(:version_snippets, user)
        Gitlab::AppLogger.info('Snippet access attempt with feature disabled')
        render plain: 'Snippet git access is disabled.', status: :forbidden
      end
    end
  end
end

Repositories::GitHttpController.prepend_if_ee('EE::Repositories::GitHttpController')