79d94b1679
Honour issue and merge request visibility in their respective finders This MR fixes a security issue with the IssuesFinder and MergeRequestFinder where they would return items the user did not have permission to see. This was most visible on the issue and merge requests page for a group containing projects that had set their issues or merge requests to "private". Closes https://gitlab.com/gitlab-org/gitlab-ce/issues/22481 See merge request !2000
95 lines
2.8 KiB
Ruby
95 lines
2.8 KiB
Ruby
class ProjectFeature < ActiveRecord::Base
|
|
# == Project features permissions
|
|
#
|
|
# Grants access level to project tools
|
|
#
|
|
# Tools can be enabled only for users, everyone or disabled
|
|
# Access control is made only for non private projects
|
|
#
|
|
# levels:
|
|
#
|
|
# Disabled: not enabled for anyone
|
|
# Private: enabled only for team members
|
|
# Enabled: enabled for everyone able to access the project
|
|
#
|
|
|
|
# Permission levels
|
|
DISABLED = 0
|
|
PRIVATE = 10
|
|
ENABLED = 20
|
|
|
|
FEATURES = %i(issues merge_requests wiki snippets builds repository)
|
|
|
|
class << self
|
|
def access_level_attribute(feature)
|
|
feature = feature.model_name.plural.to_sym if feature.respond_to?(:model_name)
|
|
raise ArgumentError, "invalid project feature: #{feature}" unless FEATURES.include?(feature)
|
|
|
|
"#{feature}_access_level".to_sym
|
|
end
|
|
end
|
|
|
|
# Default scopes force us to unscope here since a service may need to check
|
|
# permissions for a project in pending_delete
|
|
# http://stackoverflow.com/questions/1540645/how-to-disable-default-scope-for-a-belongs-to
|
|
belongs_to :project, -> { unscope(where: :pending_delete) }
|
|
|
|
validate :repository_children_level
|
|
|
|
default_value_for :builds_access_level, value: ENABLED, allows_nil: false
|
|
default_value_for :issues_access_level, value: ENABLED, allows_nil: false
|
|
default_value_for :merge_requests_access_level, value: ENABLED, allows_nil: false
|
|
default_value_for :snippets_access_level, value: ENABLED, allows_nil: false
|
|
default_value_for :wiki_access_level, value: ENABLED, allows_nil: false
|
|
default_value_for :repository_access_level, value: ENABLED, allows_nil: false
|
|
|
|
def feature_available?(feature, user)
|
|
access_level = public_send(ProjectFeature.access_level_attribute(feature))
|
|
get_permission(user, access_level)
|
|
end
|
|
|
|
def builds_enabled?
|
|
return true unless builds_access_level
|
|
|
|
builds_access_level > DISABLED
|
|
end
|
|
|
|
def wiki_enabled?
|
|
return true unless wiki_access_level
|
|
|
|
wiki_access_level > DISABLED
|
|
end
|
|
|
|
def merge_requests_enabled?
|
|
return true unless merge_requests_access_level
|
|
|
|
merge_requests_access_level > DISABLED
|
|
end
|
|
|
|
private
|
|
|
|
# Validates builds and merge requests access level
|
|
# which cannot be higher than repository access level
|
|
def repository_children_level
|
|
validator = lambda do |field|
|
|
level = public_send(field) || ProjectFeature::ENABLED
|
|
not_allowed = level > repository_access_level
|
|
self.errors.add(field, "cannot have higher visibility level than repository access level") if not_allowed
|
|
end
|
|
|
|
%i(merge_requests_access_level builds_access_level).each(&validator)
|
|
end
|
|
|
|
def get_permission(user, level)
|
|
case level
|
|
when DISABLED
|
|
false
|
|
when PRIVATE
|
|
user && (project.team.member?(user) || user.admin?)
|
|
when ENABLED
|
|
true
|
|
else
|
|
true
|
|
end
|
|
end
|
|
end
|