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
|
# frozen_string_literal: true
module Gitlab
class GitAccessSnippet < GitAccess
extend ::Gitlab::Utils::Override
ERROR_MESSAGES = {
authentication_mechanism: 'The authentication mechanism is not supported.',
read_snippet: 'You are not allowed to read this snippet.',
update_snippet: 'You are not allowed to update this snippet.',
project_not_found: 'The project you were looking for could not be found.',
snippet_not_found: 'The snippet you were looking for could not be found.',
repository_not_found: 'The snippet repository you were looking for could not be found.'
}.freeze
attr_reader :snippet
def initialize(actor, snippet, protocol, **kwargs)
@snippet = snippet
super(actor, snippet&.project, protocol, **kwargs)
@auth_result_type = nil
@authentication_abilities &= [:download_code, :push_code]
end
def check(cmd, changes)
# TODO: Investigate if expanding actor/authentication types are needed.
# https://gitlab.com/gitlab-org/gitlab/issues/202190
if actor && !actor.is_a?(User) && !actor.instance_of?(Key)
raise ForbiddenError, ERROR_MESSAGES[:authentication_mechanism]
end
unless Feature.enabled?(:version_snippets, user)
raise NotFoundError, ERROR_MESSAGES[:project_not_found]
end
check_snippet_accessibility!
super
end
private
override :check_project!
def check_project!(cmd, changes)
if snippet.is_a?(ProjectSnippet)
check_namespace!
check_project_accessibility!
# TODO add add_project_moved_message! to handle non-project repo https://gitlab.com/gitlab-org/gitlab/issues/205646
end
end
override :check_push_access!
def check_push_access!
raise ForbiddenError, ERROR_MESSAGES[:update_snippet] unless user
check_change_access!
end
override :repository
def repository
snippet&.repository
end
def check_snippet_accessibility!
if snippet.blank?
raise NotFoundError, ERROR_MESSAGES[:snippet_not_found]
end
end
override :check_download_access!
def check_download_access!
passed = guest_can_download_code? || user_can_download_code?
unless passed
raise ForbiddenError, ERROR_MESSAGES[:read_snippet]
end
end
override :guest_can_download_code?
def guest_can_download_code?
Guest.can?(:read_snippet, snippet)
end
override :user_can_download_code?
def user_can_download_code?
authentication_abilities.include?(:download_code) && user_access.can_do_action?(:read_snippet)
end
override :check_change_access!
def check_change_access!
unless user_access.can_do_action?(:update_snippet)
raise ForbiddenError, ERROR_MESSAGES[:update_snippet]
end
changes_list.each do |change|
# If user does not have access to make at least one change, cancel all
# push by allowing the exception to bubble up
check_single_change_access(change)
end
end
def check_single_change_access(change)
change_access = Checks::SnippetCheck.new(change, logger: logger)
change_access.exec
rescue Checks::TimedLogger::TimeoutError
raise TimeoutError, logger.full_message
end
override :check_repository_existence!
def check_repository_existence!
unless repository.exists?
raise NotFoundError, ERROR_MESSAGES[:repository_not_found]
end
end
override :user_access
def user_access
@user_access ||= UserAccessSnippet.new(user, snippet: snippet)
end
# TODO: Implement EE/Geo https://gitlab.com/gitlab-org/gitlab/issues/205629
override :check_custom_action
def check_custom_action(cmd)
nil
end
end
end
|