debian-mirror-gitlab/lib/banzai/filter/inline_metrics_redactor_filter.rb

148 lines
4.2 KiB
Ruby
Raw Normal View History

2019-09-30 21:07:59 +05:30
# frozen_string_literal: true
module Banzai
module Filter
# HTML filter that removes embeded elements that the current user does
# not have permission to view.
class InlineMetricsRedactorFilter < HTML::Pipeline::Filter
include Gitlab::Utils::StrongMemoize
METRICS_CSS_CLASS = '.js-render-metrics'
2020-01-01 13:55:28 +05:30
EMBED_LIMIT = 100
2019-12-26 22:10:19 +05:30
2020-04-08 14:13:33 +05:30
Route = Struct.new(:regex, :permission)
2019-12-26 22:10:19 +05:30
Embed = Struct.new(:project_path, :permission)
2019-09-30 21:07:59 +05:30
# Finds all embeds based on the css class the FE
# uses to identify the embedded content, removing
# only unnecessary nodes.
def call
nodes.each do |node|
2019-12-26 22:10:19 +05:30
embed = embeds_by_node[node]
user_has_access = user_access_by_embed[embed]
2019-09-30 21:07:59 +05:30
node.remove unless user_has_access
end
doc
end
private
def user
context[:current_user]
end
# Returns all nodes which the FE will identify as
2019-12-26 22:10:19 +05:30
# a metrics embed placeholder element
2019-09-30 21:07:59 +05:30
#
2020-01-01 13:55:28 +05:30
# Removes any nodes beyond the first 100
#
2019-09-30 21:07:59 +05:30
# @return [Nokogiri::XML::NodeSet]
def nodes
2020-01-01 13:55:28 +05:30
strong_memoize(:nodes) do
nodes = doc.css(METRICS_CSS_CLASS)
nodes.drop(EMBED_LIMIT).each(&:remove)
nodes
end
2019-09-30 21:07:59 +05:30
end
2019-12-26 22:10:19 +05:30
# Maps a node to key properties of an embed.
2019-09-30 21:07:59 +05:30
# Memoized so we only need to run the regex to get
# the project full path from the url once per node.
#
2019-12-26 22:10:19 +05:30
# @return [Hash<Nokogiri::XML::Node, Embed>]
def embeds_by_node
strong_memoize(:embeds_by_node) do
nodes.each_with_object({}) do |node, embeds|
embed = Embed.new
url = node.attribute('data-dashboard-url').to_s
2020-04-08 14:13:33 +05:30
permissions_by_route.each do |route|
set_path_and_permission(embed, url, route.regex, route.permission) unless embed.permission
end
2019-12-26 22:10:19 +05:30
embeds[node] = embed if embed.permission
2019-09-30 21:07:59 +05:30
end
end
end
2020-04-08 14:13:33 +05:30
def permissions_by_route
[
Route.new(
::Gitlab::Metrics::Dashboard::Url.metrics_regex,
:read_environment
),
Route.new(
::Gitlab::Metrics::Dashboard::Url.grafana_regex,
:read_project
)
]
end
2019-12-26 22:10:19 +05:30
# Attempts to determine the path and permission attributes
# of a url based on expected dashboard url formats and
# sets the attributes on an Embed object
2019-09-30 21:07:59 +05:30
#
2019-12-26 22:10:19 +05:30
# @param embed [Embed]
# @param url [String]
# @param regex [RegExp]
# @param permission [Symbol]
def set_path_and_permission(embed, url, regex, permission)
return unless path = regex.match(url) do |m|
2019-09-30 21:07:59 +05:30
"#{$~[:namespace]}/#{$~[:project]}"
end
2019-12-26 22:10:19 +05:30
embed.project_path = path
embed.permission = permission
end
# Returns a mapping representing whether the current user
# has permission to view the embed for the project.
# Determined in a batch
#
# @return [Hash<Embed, Boolean>]
def user_access_by_embed
strong_memoize(:user_access_by_embed) do
unique_embeds.each_with_object({}) do |embed, access|
project = projects_by_path[embed.project_path]
access[embed] = Ability.allowed?(user, embed.permission, project)
end
end
end
# Returns a unique list of embeds
#
# @return [Array<Embed>]
def unique_embeds
embeds_by_node.values.uniq
2019-09-30 21:07:59 +05:30
end
# Maps a project's full path to a Project object.
# Contains all of the Projects referenced in the
# metrics placeholder elements of the current document
#
# @return [Hash<String, Project>]
def projects_by_path
strong_memoize(:projects_by_path) do
Project.eager_load(:route, namespace: [:route])
2019-12-26 22:10:19 +05:30
.where_full_path_in(unique_project_paths)
2019-09-30 21:07:59 +05:30
.index_by(&:full_path)
end
end
2019-12-26 22:10:19 +05:30
# Returns a list of the full_paths of every project which
# has an embed in the doc
2019-09-30 21:07:59 +05:30
#
2019-12-26 22:10:19 +05:30
# @return [Array<String>]
def unique_project_paths
embeds_by_node.values.map(&:project_path).uniq
2019-09-30 21:07:59 +05:30
end
end
end
end
2020-04-08 14:13:33 +05:30
Banzai::Filter::InlineMetricsRedactorFilter.prepend_if_ee('EE::Banzai::Filter::InlineMetricsRedactorFilter')