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
|
# frozen_string_literal: true
module API
module Helpers
module PackagesHelpers
extend ::Gitlab::Utils::Override
MAX_PACKAGE_FILE_SIZE = 50.megabytes.freeze
ALLOWED_REQUIRED_PERMISSIONS = %i[read_package read_group].freeze
def require_packages_enabled!
not_found! unless ::Gitlab.config.packages.enabled
end
def require_dependency_proxy_enabled!
not_found! unless ::Gitlab.config.dependency_proxy.enabled
end
def authorize_read_package!(subject = user_project)
authorize!(:read_package, subject.try(:packages_policy_subject) || subject)
end
def authorize_create_package!(subject = user_project)
authorize!(:create_package, subject)
end
def authorize_destroy_package!(subject = user_project)
authorize!(:destroy_package, subject)
end
def authorize_packages_access!(subject = user_project, required_permission = :read_package)
require_packages_enabled!
return forbidden! unless required_permission.in?(ALLOWED_REQUIRED_PERMISSIONS)
if required_permission == :read_package
authorize_read_package!(subject)
else
authorize!(required_permission, subject)
end
end
def authorize_workhorse!(subject: user_project, has_length: true, maximum_size: MAX_PACKAGE_FILE_SIZE)
authorize_upload!(subject)
Gitlab::Workhorse.verify_api_request!(headers)
status 200
content_type Gitlab::Workhorse::INTERNAL_API_CONTENT_TYPE
params = { has_length: has_length }
params[:maximum_size] = maximum_size unless has_length
::Packages::PackageFileUploader.workhorse_authorize(**params)
end
def authorize_upload!(subject = user_project)
authorize_create_package!(subject)
require_gitlab_workhorse!
end
override :user_project
def user_project(action: :read_project)
case action
when :read_project
super()
when :read_package
user_project_with_read_package
else
raise ArgumentError, "unexpected action: #{action}"
end
end
# This function is similar to the `find_project!` function, but it considers the `read_package` ability.
def user_project_with_read_package
strong_memoize(:user_project_with_read_package) do
project = find_project(params[:id])
next forbidden! unless authorized_project_scope?(project)
next project if can?(current_user, :read_package, project&.packages_policy_subject)
# guest users can have :read_project but not :read_package
next forbidden! if can?(current_user, :read_project, project)
next unauthorized! if authenticate_non_public?
not_found!('Project')
end
end
def track_package_event(action, scope, **args)
service = ::Packages::CreateEventService.new(nil, current_user, event_name: action, scope: scope)
service.execute
category = args.delete(:category) || self.options[:for].name
args[:user] = current_user if current_user
event_name = "i_package_#{scope}_user"
::Gitlab::Tracking.event(
category,
action.to_s,
property: event_name,
label: 'redis_hll_counters.user_packages.user_packages_total_unique_counts_monthly',
context: [Gitlab::Tracking::ServicePingContext.new(data_source: :redis_hll, event: event_name).to_context],
**args
)
return unless Feature.enabled?(:route_hll_to_snowplow_phase3)
if action.to_s == 'push_package' && service.originator_type == :deploy_token
track_snowplow_event("push_package_by_deploy_token", category, args)
elsif action.to_s == 'pull_package' && service.originator_type == :guest
track_snowplow_event("pull_package_by_guest", category, args)
end
end
def present_package_file!(package_file, supports_direct_download: true)
package_file.package.touch_last_downloaded_at
present_carrierwave_file!(package_file.file, supports_direct_download: supports_direct_download)
end
private
def track_snowplow_event(action_name, category, args)
event_name = "i_package_#{action_name}"
key_path = "counts.package_events_i_package_#{action_name}"
service_ping_context = Gitlab::Tracking::ServicePingContext.new(
data_source: :redis,
key_path: key_path
).to_context
Gitlab::Tracking.event(
category,
action_name,
property: event_name,
label: key_path,
context: [service_ping_context],
**args
)
end
end
end
end
|