debian-mirror-gitlab/app/models/ability.rb

633 lines
16 KiB
Ruby
Raw Normal View History

2014-09-02 18:07:02 +05:30
class Ability
class << self
2016-08-24 12:49:21 +05:30
# rubocop: disable Metrics/CyclomaticComplexity
2014-09-02 18:07:02 +05:30
def allowed(user, subject)
2015-11-26 14:37:03 +05:30
return anonymous_abilities(user, subject) if user.nil?
return [] unless user.is_a?(User)
2014-09-02 18:07:02 +05:30
return [] if user.blocked?
2016-09-13 17:45:13 +05:30
abilities_by_subject_class(user: user, subject: subject)
end
def abilities_by_subject_class(user:, subject:)
2016-04-02 18:10:28 +05:30
case subject
when CommitStatus then commit_status_abilities(user, subject)
when Project then project_abilities(user, subject)
when Issue then issue_abilities(user, subject)
when Note then note_abilities(user, subject)
when ProjectSnippet then project_snippet_abilities(user, subject)
when PersonalSnippet then personal_snippet_abilities(user, subject)
when MergeRequest then merge_request_abilities(user, subject)
when Group then group_abilities(user, subject)
when Namespace then namespace_abilities(user, subject)
when GroupMember then group_member_abilities(user, subject)
when ProjectMember then project_member_abilities(user, subject)
2016-06-02 11:05:42 +05:30
when User then user_abilities
when ExternalIssue, Deployment, Environment then project_abilities(user, subject.project)
2016-08-24 12:49:21 +05:30
when Ci::Runner then runner_abilities(user, subject)
2014-09-02 18:07:02 +05:30
else []
end.concat(global_abilities(user))
end
# Given a list of users and a project this method returns the users that can
# read the given project.
def users_that_can_read_project(users, project)
if project.public?
users
else
users.select do |user|
if user.admin?
true
elsif project.internal? && !user.external?
true
elsif project.owner == user
true
elsif project.team.members.include?(user)
true
else
false
end
end
end
end
2016-09-13 17:45:13 +05:30
# Returns an Array of Issues that can be read by the given user.
#
# issues - The issues to reduce down to those readable by the user.
# user - The User for which to check the issues
def issues_readable_by_user(issues, user = nil)
return issues if user && user.admin?
issues.select { |issue| issue.visible_to_user?(user) }
end
2015-11-26 14:37:03 +05:30
# List of possible abilities for anonymous user
def anonymous_abilities(user, subject)
if subject.is_a?(PersonalSnippet)
2015-11-26 14:37:03 +05:30
anonymous_personal_snippet_abilities(subject)
elsif subject.is_a?(ProjectSnippet)
2016-06-02 11:05:42 +05:30
anonymous_project_snippet_abilities(subject)
elsif subject.is_a?(CommitStatus)
2016-04-02 18:10:28 +05:30
anonymous_commit_status_abilities(subject)
elsif subject.is_a?(Project) || subject.respond_to?(:project)
2015-11-26 14:37:03 +05:30
anonymous_project_abilities(subject)
elsif subject.is_a?(Group) || subject.respond_to?(:group)
2015-11-26 14:37:03 +05:30
anonymous_group_abilities(subject)
elsif subject.is_a?(User)
2016-06-02 11:05:42 +05:30
anonymous_user_abilities
2015-11-26 14:37:03 +05:30
else
[]
end
end
def anonymous_project_abilities(subject)
project = if subject.is_a?(Project)
2014-09-02 18:07:02 +05:30
subject
else
2015-11-26 14:37:03 +05:30
subject.project
2014-09-02 18:07:02 +05:30
end
if project && project.public?
2015-09-11 14:41:01 +05:30
rules = [
2014-09-02 18:07:02 +05:30
:read_project,
2016-09-13 17:45:13 +05:30
:read_board,
:read_list,
2014-09-02 18:07:02 +05:30
:read_wiki,
2015-09-11 14:41:01 +05:30
:read_label,
2014-09-02 18:07:02 +05:30
:read_milestone,
:read_project_snippet,
2015-04-26 12:48:37 +05:30
:read_project_member,
2014-09-02 18:07:02 +05:30
:read_merge_request,
:read_note,
2016-06-02 11:05:42 +05:30
:read_pipeline,
2016-04-02 18:10:28 +05:30
:read_commit_status,
2016-06-02 11:05:42 +05:30
:read_container_image,
2014-09-02 18:07:02 +05:30
:download_code
]
2015-09-11 14:41:01 +05:30
2016-04-02 18:10:28 +05:30
# Allow to read builds by anonymous user if guests are allowed
rules << :read_build if project.public_builds?
2016-06-02 11:05:42 +05:30
# Allow to read issues by anonymous user if issue is not confidential
rules << :read_issue unless subject.is_a?(Issue) && subject.confidential?
2015-09-11 14:41:01 +05:30
rules - project_disabled_features_rules(project)
2014-09-02 18:07:02 +05:30
else
2015-11-26 14:37:03 +05:30
[]
end
end
2014-09-02 18:07:02 +05:30
2016-04-02 18:10:28 +05:30
def anonymous_commit_status_abilities(subject)
rules = anonymous_project_abilities(subject.project)
# If subject is Ci::Build which inherits from CommitStatus filter the abilities
rules = filter_build_abilities(rules) if subject.is_a?(Ci::Build)
rules
end
2015-11-26 14:37:03 +05:30
def anonymous_group_abilities(subject)
2016-06-02 11:05:42 +05:30
rules = []
2015-11-26 14:37:03 +05:30
group = if subject.is_a?(Group)
subject
else
subject.group
end
2016-06-02 11:05:42 +05:30
rules << :read_group if group.public?
rules
end
def anonymous_personal_snippet_abilities(snippet)
if snippet.public?
[:read_personal_snippet]
2015-11-26 14:37:03 +05:30
else
[]
end
end
2016-06-02 11:05:42 +05:30
def anonymous_project_snippet_abilities(snippet)
2015-11-26 14:37:03 +05:30
if snippet.public?
2016-06-02 11:05:42 +05:30
[:read_project_snippet]
2015-11-26 14:37:03 +05:30
else
[]
2014-09-02 18:07:02 +05:30
end
end
2016-06-02 11:05:42 +05:30
def anonymous_user_abilities
[:read_user] unless restricted_public_level?
end
2014-09-02 18:07:02 +05:30
def global_abilities(user)
rules = []
rules << :create_group if user.can_create_group
2016-06-02 11:05:42 +05:30
rules << :read_users_list
2014-09-02 18:07:02 +05:30
rules
end
def project_abilities(user, project)
key = "/user/#{user.id}/project/#{project.id}"
2015-09-11 14:41:01 +05:30
2016-09-13 17:45:13 +05:30
if RequestStore.active?
RequestStore.store[key] ||= uncached_project_abilities(user, project)
else
uncached_project_abilities(user, project)
end
end
2014-09-02 18:07:02 +05:30
2016-09-13 17:45:13 +05:30
def uncached_project_abilities(user, project)
rules = []
# Push abilities on the users team role
rules.push(*project_team_rules(project.team, user))
2014-09-02 18:07:02 +05:30
2016-09-13 17:45:13 +05:30
owner = user.admin? ||
project.owner == user ||
(project.group && project.group.has_owner?(user))
2014-09-02 18:07:02 +05:30
2016-09-13 17:45:13 +05:30
if owner
rules.push(*project_owner_rules)
end
2016-04-02 18:10:28 +05:30
2016-09-13 17:45:13 +05:30
if project.public? || (project.internal? && !user.external?)
rules.push(*public_project_rules)
2016-08-24 12:49:21 +05:30
2016-09-13 17:45:13 +05:30
# Allow to read builds for internal projects
rules << :read_build if project.public_builds?
2014-09-02 18:07:02 +05:30
2016-09-13 17:45:13 +05:30
unless owner || project.team.member?(user) || project_group_member?(project, user)
rules << :request_access if project.request_access_enabled
2014-09-02 18:07:02 +05:30
end
2016-09-13 17:45:13 +05:30
end
2014-09-02 18:07:02 +05:30
2016-09-13 17:45:13 +05:30
if project.archived?
rules -= project_archived_rules
2014-09-02 18:07:02 +05:30
end
2016-09-13 17:45:13 +05:30
(rules - project_disabled_features_rules(project)).uniq
2014-09-02 18:07:02 +05:30
end
2016-06-02 11:05:42 +05:30
def project_team_rules(team, user)
# Rules based on role in project
if team.master?(user)
project_master_rules
elsif team.developer?(user)
project_dev_rules
elsif team.reporter?(user)
project_report_rules
elsif team.guest?(user)
project_guest_rules
else
[]
2016-06-02 11:05:42 +05:30
end
end
2014-09-02 18:07:02 +05:30
def public_project_rules
@public_project_rules ||= project_guest_rules + [
2014-09-02 18:07:02 +05:30
:download_code,
2016-04-02 18:10:28 +05:30
:fork_project,
2016-08-24 12:49:21 +05:30
:read_commit_status,
:read_pipeline,
:read_container_image
2014-09-02 18:07:02 +05:30
]
end
def project_guest_rules
@project_guest_rules ||= [
2014-09-02 18:07:02 +05:30
:read_project,
:read_wiki,
:read_issue,
2016-09-13 17:45:13 +05:30
:read_board,
:read_list,
2015-09-11 14:41:01 +05:30
:read_label,
2014-09-02 18:07:02 +05:30
:read_milestone,
:read_project_snippet,
2015-04-26 12:48:37 +05:30
:read_project_member,
2014-09-02 18:07:02 +05:30
:read_merge_request,
:read_note,
2015-09-11 14:41:01 +05:30
:create_project,
:create_issue,
2016-06-02 11:05:42 +05:30
:create_note,
:upload_file
2014-09-02 18:07:02 +05:30
]
end
def project_report_rules
@project_report_rules ||= project_guest_rules + [
2014-09-02 18:07:02 +05:30
:download_code,
:fork_project,
2015-09-11 14:41:01 +05:30
:create_project_snippet,
:update_issue,
:admin_issue,
2016-04-02 18:10:28 +05:30
:admin_label,
2016-09-13 17:45:13 +05:30
:admin_list,
2016-04-02 18:10:28 +05:30
:read_commit_status,
:read_build,
2016-06-02 11:05:42 +05:30
:read_container_image,
:read_pipeline,
:read_environment,
:read_deployment
2014-09-02 18:07:02 +05:30
]
end
def project_dev_rules
@project_dev_rules ||= project_report_rules + [
2015-09-11 14:41:01 +05:30
:admin_merge_request,
2016-06-02 11:05:42 +05:30
:update_merge_request,
2016-04-02 18:10:28 +05:30
:create_commit_status,
:update_commit_status,
:create_build,
:update_build,
2016-06-02 11:05:42 +05:30
:create_pipeline,
:update_pipeline,
2015-09-11 14:41:01 +05:30
:create_merge_request,
:create_wiki,
2016-06-02 11:05:42 +05:30
:push_code,
2016-09-13 17:45:13 +05:30
:resolve_note,
2016-06-02 11:05:42 +05:30
:create_container_image,
:update_container_image,
:create_environment,
:create_deployment
2014-09-02 18:07:02 +05:30
]
end
def project_archived_rules
@project_archived_rules ||= [
2015-09-11 14:41:01 +05:30
:create_merge_request,
2014-09-02 18:07:02 +05:30
:push_code,
:push_code_to_protected_branches,
2015-09-11 14:41:01 +05:30
:update_merge_request,
2014-09-02 18:07:02 +05:30
:admin_merge_request
]
end
def project_master_rules
@project_master_rules ||= project_dev_rules + [
2014-09-02 18:07:02 +05:30
:push_code_to_protected_branches,
2015-09-11 14:41:01 +05:30
:update_project_snippet,
:update_environment,
:update_deployment,
2014-09-02 18:07:02 +05:30
:admin_milestone,
:admin_project_snippet,
2015-04-26 12:48:37 +05:30
:admin_project_member,
2014-09-02 18:07:02 +05:30
:admin_merge_request,
:admin_note,
:admin_wiki,
2016-04-02 18:10:28 +05:30
:admin_project,
:admin_commit_status,
2016-06-02 11:05:42 +05:30
:admin_build,
:admin_container_image,
:admin_pipeline,
:admin_environment,
:admin_deployment
2014-09-02 18:07:02 +05:30
]
end
2016-06-02 11:05:42 +05:30
def project_owner_rules
@project_owner_rules ||= project_master_rules + [
2014-09-02 18:07:02 +05:30
:change_namespace,
:change_visibility_level,
:rename_project,
:remove_project,
2015-11-26 14:37:03 +05:30
:archive_project,
2016-06-02 11:05:42 +05:30
:remove_fork_project,
:destroy_merge_request,
:destroy_issue
2014-09-02 18:07:02 +05:30
]
end
2015-09-11 14:41:01 +05:30
def project_disabled_features_rules(project)
rules = []
unless project.issues_enabled
rules += named_abilities('issue')
end
unless project.merge_requests_enabled
rules += named_abilities('merge_request')
end
unless project.issues_enabled or project.merge_requests_enabled
rules += named_abilities('label')
rules += named_abilities('milestone')
end
unless project.snippets_enabled
rules += named_abilities('project_snippet')
end
unless project.wiki_enabled
rules += named_abilities('wiki')
end
2016-04-02 18:10:28 +05:30
unless project.builds_enabled
rules += named_abilities('build')
2016-06-02 11:05:42 +05:30
rules += named_abilities('pipeline')
rules += named_abilities('environment')
rules += named_abilities('deployment')
2016-06-02 11:05:42 +05:30
end
unless project.container_registry_enabled
rules += named_abilities('container_image')
2016-04-02 18:10:28 +05:30
end
2015-09-11 14:41:01 +05:30
rules
end
2015-04-26 12:48:37 +05:30
def group_abilities(user, group)
2014-09-02 18:07:02 +05:30
rules = []
2016-06-02 11:05:42 +05:30
rules << :read_group if can_read_group?(user, group)
2014-09-02 18:07:02 +05:30
2016-08-24 12:49:21 +05:30
owner = user.admin? || group.has_owner?(user)
master = owner || group.has_master?(user)
2016-06-02 11:05:42 +05:30
# Only group masters and group owners can create new projects
2016-08-24 12:49:21 +05:30
if master
2015-11-26 14:37:03 +05:30
rules += [
2014-09-02 18:07:02 +05:30
:create_projects,
2015-11-26 14:37:03 +05:30
:admin_milestones
]
2014-09-02 18:07:02 +05:30
end
2015-04-26 12:48:37 +05:30
# Only group owner and administrators can admin group
2016-08-24 12:49:21 +05:30
if owner
2015-11-26 14:37:03 +05:30
rules += [
2015-04-26 12:48:37 +05:30
:admin_group,
2015-09-11 14:41:01 +05:30
:admin_namespace,
2016-06-02 11:05:42 +05:30
:admin_group_member,
:change_visibility_level
2015-11-26 14:37:03 +05:30
]
2014-09-02 18:07:02 +05:30
end
2016-08-24 12:49:21 +05:30
if group.public? || (group.internal? && !user.external?)
rules << :request_access if group.request_access_enabled && group.users.exclude?(user)
end
2014-09-02 18:07:02 +05:30
rules.flatten
end
2016-06-02 11:05:42 +05:30
def can_read_group?(user, group)
return true if user.admin?
return true if group.public?
return true if group.internal? && !user.external?
return true if group.users.include?(user)
GroupProjectsFinder.new(group).execute(user).any?
end
2016-09-13 17:45:13 +05:30
def can_edit_note?(user, note)
return false if !note.editable? || !user.present?
return true if note.author == user || user.admin?
if note.project
max_access_level = note.project.team.max_member_access(user.id)
max_access_level >= Gitlab::Access::MASTER
else
false
end
end
2015-04-26 12:48:37 +05:30
def namespace_abilities(user, namespace)
2014-09-02 18:07:02 +05:30
rules = []
2015-04-26 12:48:37 +05:30
# Only namespace owner and administrators can admin it
2014-09-02 18:07:02 +05:30
if namespace.owner == user || user.admin?
2015-11-26 14:37:03 +05:30
rules += [
2014-09-02 18:07:02 +05:30
:create_projects,
2015-04-26 12:48:37 +05:30
:admin_namespace
2015-11-26 14:37:03 +05:30
]
2014-09-02 18:07:02 +05:30
end
rules.flatten
end
2015-09-11 14:41:01 +05:30
[:issue, :merge_request].each do |name|
2014-09-02 18:07:02 +05:30
define_method "#{name}_abilities" do |user, subject|
2015-09-11 14:41:01 +05:30
rules = []
if subject.author == user || (subject.respond_to?(:assignee) && subject.assignee == user)
rules += [
2014-09-02 18:07:02 +05:30
:"read_#{name}",
2015-09-11 14:41:01 +05:30
:"update_#{name}",
2014-09-02 18:07:02 +05:30
]
2015-09-11 14:41:01 +05:30
end
rules += project_abilities(user, subject.project)
2016-06-02 11:05:42 +05:30
rules = filter_confidential_issues_abilities(user, subject, rules) if subject.is_a?(Issue)
2015-09-11 14:41:01 +05:30
rules
end
end
2016-06-02 11:05:42 +05:30
def note_abilities(user, note)
rules = []
2015-09-11 14:41:01 +05:30
2016-06-02 11:05:42 +05:30
if note.author == user
rules += [
:read_note,
:update_note,
2016-09-13 17:45:13 +05:30
:admin_note,
:resolve_note
2016-06-02 11:05:42 +05:30
]
end
2015-09-11 14:41:01 +05:30
2016-06-02 11:05:42 +05:30
if note.respond_to?(:project) && note.project
rules += project_abilities(user, note.project)
2014-09-02 18:07:02 +05:30
end
2016-06-02 11:05:42 +05:30
2016-09-13 17:45:13 +05:30
if note.for_merge_request? && note.noteable.author == user
rules << :resolve_note
end
2016-06-02 11:05:42 +05:30
rules
2014-09-02 18:07:02 +05:30
end
2015-11-26 14:37:03 +05:30
def personal_snippet_abilities(user, snippet)
rules = []
if snippet.author == user
rules += [
:read_personal_snippet,
:update_personal_snippet,
:admin_personal_snippet
]
end
2016-06-02 11:05:42 +05:30
if snippet.public? || (snippet.internal? && !user.external?)
rules << :read_personal_snippet
2015-11-26 14:37:03 +05:30
end
rules
end
2016-06-02 11:05:42 +05:30
def project_snippet_abilities(user, snippet)
rules = []
if snippet.author == user || user.admin?
rules += [
:read_project_snippet,
:update_project_snippet,
:admin_project_snippet
]
end
if snippet.public? || (snippet.internal? && !user.external?) || (snippet.private? && snippet.project.team.member?(user))
rules << :read_project_snippet
end
rules
end
2015-04-26 12:48:37 +05:30
def group_member_abilities(user, subject)
2014-09-02 18:07:02 +05:30
rules = []
target_user = subject.user
group = subject.group
2015-09-11 14:41:01 +05:30
2015-11-26 14:37:03 +05:30
unless group.last_owner?(target_user)
can_manage = group_abilities(user, group).include?(:admin_group_member)
2015-12-23 02:04:40 +05:30
if can_manage
2015-11-26 14:37:03 +05:30
rules << :update_group_member
rules << :destroy_group_member
2015-12-23 02:04:40 +05:30
elsif user == target_user
2015-11-26 14:37:03 +05:30
rules << :destroy_group_member
end
2014-09-02 18:07:02 +05:30
end
2015-09-11 14:41:01 +05:30
2015-11-26 14:37:03 +05:30
rules
end
def project_member_abilities(user, subject)
rules = []
target_user = subject.user
project = subject.project
unless target_user == project.owner
can_manage = project_abilities(user, project).include?(:admin_project_member)
2015-12-23 02:04:40 +05:30
if can_manage
2015-11-26 14:37:03 +05:30
rules << :update_project_member
rules << :destroy_project_member
2015-12-23 02:04:40 +05:30
elsif user == target_user
2015-11-26 14:37:03 +05:30
rules << :destroy_project_member
end
2014-09-02 18:07:02 +05:30
end
2015-09-11 14:41:01 +05:30
2014-09-02 18:07:02 +05:30
rules
end
2015-04-26 12:48:37 +05:30
2016-04-02 18:10:28 +05:30
def commit_status_abilities(user, subject)
rules = project_abilities(user, subject.project)
# If subject is Ci::Build which inherits from CommitStatus filter the abilities
rules = filter_build_abilities(rules) if subject.is_a?(Ci::Build)
rules
end
def filter_build_abilities(rules)
# If we can't read build we should also not have that
# ability when looking at this in context of commit_status
%w(read create update admin).each do |rule|
rules.delete(:"#{rule}_commit_status") unless rules.include?(:"#{rule}_build")
end
rules
end
2016-08-24 12:49:21 +05:30
def runner_abilities(user, runner)
if user.is_admin?
[:assign_runner]
elsif runner.is_shared? || runner.locked?
[]
elsif user.ci_authorized_runners.include?(runner)
[:assign_runner]
else
[]
end
end
2016-06-02 11:05:42 +05:30
def user_abilities
[:read_user]
end
2015-04-26 12:48:37 +05:30
def abilities
@abilities ||= begin
2015-11-26 14:37:03 +05:30
abilities = Six.new
abilities << self
abilities
end
2015-04-26 12:48:37 +05:30
end
2015-09-11 14:41:01 +05:30
private
2016-06-02 11:05:42 +05:30
def restricted_public_level?
current_application_settings.restricted_visibility_levels.include?(Gitlab::VisibilityLevel::PUBLIC)
end
2015-09-11 14:41:01 +05:30
def named_abilities(name)
[
:"read_#{name}",
:"create_#{name}",
:"update_#{name}",
:"admin_#{name}"
]
end
2016-06-02 11:05:42 +05:30
def filter_confidential_issues_abilities(user, issue, rules)
return rules if user.admin? || !issue.confidential?
unless issue.author == user || issue.assignee == user || issue.project.team.member?(user, Gitlab::Access::REPORTER)
2016-06-02 11:05:42 +05:30
rules.delete(:admin_issue)
rules.delete(:read_issue)
rules.delete(:update_issue)
end
rules
end
2016-08-24 12:49:21 +05:30
def project_group_member?(project, user)
project.group &&
(
project.group.members.exists?(user_id: user.id) ||
project.group.requesters.exists?(user_id: user.id)
)
end
2014-09-02 18:07:02 +05:30
end
end