Welcome to mirror list, hosted at ThFree Co, Russian Federation.

lfs_api_controller.rb « projects « controllers « app - gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 1273c55b83a91ee13dd483839632c739bf8e6952 (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
135
136
137
138
139
140
# frozen_string_literal: true

class Projects::LfsApiController < Projects::GitHttpClientController
  include LfsRequest
  include Gitlab::Utils::StrongMemoize

  LFS_TRANSFER_CONTENT_TYPE = 'application/octet-stream'

  skip_before_action :lfs_check_access!, only: [:deprecated]
  before_action :lfs_check_batch_operation!, only: [:batch]

  def batch
    unless objects.present?
      render_lfs_not_found
      return
    end

    if download_request?
      render json: { objects: download_objects! }
    elsif upload_request?
      render json: { objects: upload_objects! }
    else
      raise "Never reached"
    end
  end

  def deprecated
    render(
      json: {
        message: _('Server supports batch API only, please update your Git LFS client to version 1.0.1 and up.'),
        documentation_url: "#{Gitlab.config.gitlab.url}/help"
      },
      status: :not_implemented
    )
  end

  private

  def download_request?
    params[:operation] == 'download'
  end

  def upload_request?
    params[:operation] == 'upload'
  end

  # rubocop: disable CodeReuse/ActiveRecord
  def existing_oids
    @existing_oids ||= begin
      project.all_lfs_objects.where(oid: objects.map { |o| o['oid'].to_s }).pluck(:oid)
    end
  end
  # rubocop: enable CodeReuse/ActiveRecord

  def download_objects!
    objects.each do |object|
      if existing_oids.include?(object[:oid])
        object[:actions] = download_actions(object)

        if Guest.can?(:download_code, project)
          object[:authenticated] = true
        end
      else
        object[:error] = {
          code: 404,
          message: _("Object does not exist on the server or you don't have permissions to access it")
        }
      end
    end
    objects
  end

  def upload_objects!
    objects.each do |object|
      object[:actions] = upload_actions(object) unless existing_oids.include?(object[:oid])
    end
    objects
  end

  def download_actions(object)
    {
      download: {
        href: "#{project.http_url_to_repo}/gitlab-lfs/objects/#{object[:oid]}",
        header: {
          Authorization: authorization_header
        }.compact
      }
    }
  end

  def upload_actions(object)
    {
      upload: {
        href: "#{project.http_url_to_repo}/gitlab-lfs/objects/#{object[:oid]}/#{object[:size]}",
        header: {
          Authorization: authorization_header,
          # git-lfs v2.5.0 sets the Content-Type based on the uploaded file. This
          # ensures that Workhorse can intercept the request.
          'Content-Type': LFS_TRANSFER_CONTENT_TYPE
        }.compact
      }
    }
  end

  def lfs_check_batch_operation!
    if batch_operation_disallowed?
      render(
        json: {
          message: lfs_read_only_message
        },
        content_type: LfsRequest::CONTENT_TYPE,
        status: :forbidden
      )
    end
  end

  # Overridden in EE
  def batch_operation_disallowed?
    upload_request? && Gitlab::Database.read_only?
  end

  # Overridden in EE
  def lfs_read_only_message
    _('You cannot write to this read-only GitLab instance.')
  end

  def authorization_header
    strong_memoize(:authorization_header) do
      lfs_auth_header || request.headers['Authorization']
    end
  end

  def lfs_auth_header
    return unless user.is_a?(User)

    Gitlab::LfsToken.new(user).basic_encoding
  end
end

Projects::LfsApiController.prepend_if_ee('EE::Projects::LfsApiController')