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

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorDouwe Maan <douwe@gitlab.com>2018-01-18 19:07:06 +0300
committerRobert Speicher <rspeicher@gmail.com>2018-02-09 21:04:05 +0300
commit5e9e56924a56dcb84c3ae4ae6fc308f635f39f66 (patch)
treeb7160c4277521c309d1f3cc97580c62474cfa759 /app
parent721fab661de4a01c2d73e88bdd000dfe2e094ced (diff)
Merge branch 'security-10-4-25223-snippets-finder-doesnt-obey-feature-visibility' into 'security-10-4'
[Port for security-10-4]: Makes SnippetFinder ensure feature visibility
Diffstat (limited to 'app')
-rw-r--r--app/finders/snippets_finder.rb67
-rw-r--r--app/models/snippet.rb21
-rw-r--r--app/policies/project_policy.rb1
3 files changed, 67 insertions, 22 deletions
diff --git a/app/finders/snippets_finder.rb b/app/finders/snippets_finder.rb
index 4450766485f..33359fa1efb 100644
--- a/app/finders/snippets_finder.rb
+++ b/app/finders/snippets_finder.rb
@@ -1,14 +1,28 @@
+# Snippets Finder
+#
+# Used to filter Snippets collections by a set of params
+#
+# Arguments.
+#
+# current_user - The current user, nil also can be used.
+# params:
+# visibility (integer) - Individual snippet visibility: Public(20), internal(10) or private(0).
+# project (Project) - Project related.
+# author (User) - Author related.
+#
+# params are optional
class SnippetsFinder < UnionFinder
- attr_accessor :current_user, :params
+ include Gitlab::Allowable
+ attr_accessor :current_user, :params, :project
def initialize(current_user, params = {})
@current_user = current_user
@params = params
+ @project = params[:project]
end
def execute
items = init_collection
- items = by_project(items)
items = by_author(items)
items = by_visibility(items)
@@ -18,25 +32,42 @@ class SnippetsFinder < UnionFinder
private
def init_collection
- items = Snippet.all
+ if project.present?
+ authorized_snippets_from_project
+ else
+ authorized_snippets
+ end
+ end
- accessible(items)
+ def authorized_snippets_from_project
+ if can?(current_user, :read_project_snippet, project)
+ if project.team.member?(current_user)
+ project.snippets
+ else
+ project.snippets.public_to_user(current_user)
+ end
+ else
+ Snippet.none
+ end
end
- def accessible(items)
- segments = []
- segments << items.public_to_user(current_user)
- segments << authorized_to_user(items) if current_user
+ def authorized_snippets
+ Snippet.where(feature_available_projects.or(not_project_related)).public_or_visible_to_user(current_user)
+ end
- find_union(segments, Snippet.includes(:author))
+ def feature_available_projects
+ projects = Project.public_or_visible_to_user(current_user)
+ .with_feature_available_for_user(:snippets, current_user).select(:id)
+ arel_query = Arel::Nodes::SqlLiteral.new(projects.to_sql)
+ table[:project_id].in(arel_query)
end
- def authorized_to_user(items)
- items.where(
- 'author_id = :author_id
- OR project_id IN (:project_ids)',
- author_id: current_user.id,
- project_ids: current_user.authorized_projects.select(:id))
+ def not_project_related
+ table[:project_id].eq(nil)
+ end
+
+ def table
+ Snippet.arel_table
end
def by_visibility(items)
@@ -53,12 +84,6 @@ class SnippetsFinder < UnionFinder
items.where(author_id: params[:author].id)
end
- def by_project(items)
- return items unless params[:project]
-
- items.where(project_id: params[:project].id)
- end
-
def visibility_from_scope
case params[:scope].to_s
when 'are_private'
diff --git a/app/models/snippet.rb b/app/models/snippet.rb
index 7c8716f8c18..a58c208279e 100644
--- a/app/models/snippet.rb
+++ b/app/models/snippet.rb
@@ -74,6 +74,27 @@ class Snippet < ActiveRecord::Base
@link_reference_pattern ||= super("snippets", /(?<snippet>\d+)/)
end
+ # Returns a collection of snippets that are either public or visible to the
+ # logged in user.
+ #
+ # This method does not verify the user actually has the access to the project
+ # the snippet is in, so it should be only used on a relation that's already scoped
+ # for project access
+ def self.public_or_visible_to_user(user = nil)
+ if user
+ authorized = user
+ .project_authorizations
+ .select(1)
+ .where('project_authorizations.project_id = snippets.project_id')
+
+ levels = Gitlab::VisibilityLevel.levels_for_user(user)
+
+ where('EXISTS (?) OR snippets.visibility_level IN (?) or snippets.author_id = (?)', authorized, levels, user.id)
+ else
+ public_to_user
+ end
+ end
+
def to_reference(from = nil, full: false)
reference = "#{self.class.reference_prefix}#{id}"
diff --git a/app/policies/project_policy.rb b/app/policies/project_policy.rb
index 1dd8f0a25a9..61a7bf02675 100644
--- a/app/policies/project_policy.rb
+++ b/app/policies/project_policy.rb
@@ -119,7 +119,6 @@ class ProjectPolicy < BasePolicy
enable :create_note
enable :upload_file
enable :read_cycle_analytics
- enable :read_project_snippet
end
rule { can?(:reporter_access) }.policy do