git_http_controller.rb 2.49 KB
Newer Older
Jacob Vosmaer's avatar
Jacob Vosmaer committed
1
class Projects::GitHttpController < Projects::GitHttpClientController
2
  include WorkhorseRequest
3

4 5 6
  # 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
7
    if upload_pack? && upload_pack_allowed?
8 9
      log_user_activity

Jacob Vosmaer's avatar
Jacob Vosmaer committed
10 11 12
      render_ok
    elsif receive_pack? && receive_pack_allowed?
      render_ok
13
    elsif http_blocked?
14
      render_http_not_allowed
Jacob Vosmaer's avatar
Jacob Vosmaer committed
15
    else
16
      render_denied
17 18
    end
  end
Jacob Vosmaer's avatar
Jacob Vosmaer committed
19

20 21 22 23 24
  # POST /foo/bar.git/git-upload-pack (git pull)
  def git_upload_pack
    if upload_pack? && upload_pack_allowed?
      render_ok
    else
25
      render_denied
26 27 28 29 30 31 32 33
    end
  end

  # POST /foo/bar.git/git-receive-pack" (git push)
  def git_receive_pack
    if receive_pack? && receive_pack_allowed?
      render_ok
    else
34
      render_denied
35
    end
36 37 38 39
  end

  private

Jacob Vosmaer's avatar
Jacob Vosmaer committed
40 41
  def download_request?
    upload_pack?
42 43 44
  end

  def upload_pack?
45
    git_command == 'git-upload-pack'
Jacob Vosmaer's avatar
Jacob Vosmaer committed
46 47 48
  end

  def receive_pack?
49
    git_command == 'git-receive-pack'
Jacob Vosmaer's avatar
Jacob Vosmaer committed
50 51
  end

52
  def git_command
53
    if action_name == 'info_refs'
Jacob Vosmaer's avatar
Jacob Vosmaer committed
54
      params[:service]
55
    else
56
      action_name.dasherize
57 58
    end
  end
Jacob Vosmaer's avatar
Jacob Vosmaer committed
59

60
  def render_ok
61
    set_workhorse_internal_api_content_type
62
    render json: Gitlab::Workhorse.git_http_ok(repository, user, action_name)
63
  end
Jacob Vosmaer's avatar
Jacob Vosmaer committed
64

65 66 67 68 69
  def render_http_not_allowed
    render plain: access_check.message, status: :forbidden
  end

  def render_denied
70 71
    if user && can?(user, :read_project, project)
      render plain: access_denied_message, status: :forbidden
72 73 74 75
    else
      # Do not leak information about project existence
      render_not_found
    end
76 77
  end

78
  def access_denied_message
79
    access_check.message || 'Access denied'
80 81
  end

82
  def upload_pack_allowed?
83 84
    return false unless Gitlab.config.gitlab_shell.upload_pack

85
    access_check.allowed? || ci?
86
  end
Jacob Vosmaer's avatar
Jacob Vosmaer committed
87

88
  def access
89
    @access ||= access_klass.new(user, project, 'http', authentication_abilities: authentication_abilities)
90 91
  end

92 93 94 95
  def access_check
    # Use the magic string '_any' to indicate we do not know what the
    # changes are. This is also what gitlab-shell does.
    @access_check ||= access.check(git_command, '_any')
Patricio Cano's avatar
Patricio Cano committed
96 97
  end

98
  def http_blocked?
99
    !access.protocol_allowed?
100 101
  end

Jacob Vosmaer's avatar
Jacob Vosmaer committed
102
  def receive_pack_allowed?
103 104
    return false unless Gitlab.config.gitlab_shell.receive_pack

105
    access_check.allowed?
Jacob Vosmaer's avatar
Jacob Vosmaer committed
106
  end
107 108 109

  def log_user_activity
    Users::ActivityService.new(user, 'pull').execute
Nick Thomas's avatar
Nick Thomas committed
110 111
  end

112 113
  def access_klass
    @access_klass ||= wiki? ? Gitlab::GitAccessWiki : Gitlab::GitAccess
114
  end
115
end