Update upstream source from tag 'upstream/10.7.6+dfsg'

Update to upstream version '10.7.6+dfsg'
with Debian dir d621e562d0
This commit is contained in:
Pirate Praveen 2018-06-27 16:04:44 +05:30
commit 6dd2eb13f7
39 changed files with 167 additions and 272 deletions

View file

@ -2,6 +2,22 @@
documentation](doc/development/changelog.md) for instructions on adding your own documentation](doc/development/changelog.md) for instructions on adding your own
entry. entry.
## 10.7.6 (2018-06-21)
### Security (6 changes)
- Fix XSS vulnerability for table of content generation.
- Update sanitize gem to 4.6.5 to fix HTML injection vulnerability.
- HTML escape branch name in project graphs page.
- HTML escape the name of the user in ProjectsHelper#link_to_member.
- Don't show events from internal projects for anonymous users in public feed.
- XSS fix to use safe_params instead of params in url_for helpers.
### Other (1 change)
- Replacing gollum libraries for gitlab custom libs. !18343
## 10.7.5 (2018-05-28) ## 10.7.5 (2018-05-28)
### Security (3 changes) ### Security (3 changes)

15
Gemfile
View file

@ -81,16 +81,9 @@ gem 'net-ldap'
# Git Wiki # Git Wiki
# Required manually in config/initializers/gollum.rb to control load order # Required manually in config/initializers/gollum.rb to control load order
# Before updating this gem, check if gem 'gitlab-gollum-lib', '~> 4.2'
# https://github.com/gollum/gollum-lib/pull/292 has been merged.
# If it has, then remove the monkey patch for update_page, rename_page and raw_data_in_committer
# in config/initializers/gollum.rb
gem 'gollum-lib', '~> 4.2', require: false
# Before updating this gem, check if gem 'gitlab-gollum-rugged_adapter', '~> 0.4.4', require: false
# https://github.com/gollum/rugged_adapter/pull/28 has been merged.
# If it has, then remove the monkey patch for tree_entry in config/initializers/gollum.rb
gem 'gollum-rugged_adapter', '~> 0.4.4', require: false
# Language detection # Language detection
gem 'github-linguist', '~> 5.3.3', require: 'linguist' gem 'github-linguist', '~> 5.3.3', require: 'linguist'
@ -146,7 +139,7 @@ gem 'creole', '~> 0.5.0'
gem 'wikicloth', '0.8.1' gem 'wikicloth', '0.8.1'
gem 'asciidoctor', '~> 1.5.6' gem 'asciidoctor', '~> 1.5.6'
gem 'asciidoctor-plantuml', '0.0.8' gem 'asciidoctor-plantuml', '0.0.8'
gem 'rouge', '~> 2.0' gem 'rouge', '~> 3.1'
gem 'truncato', '~> 0.7.9' gem 'truncato', '~> 0.7.9'
gem 'bootstrap_form', '~> 2.7.0' gem 'bootstrap_form', '~> 2.7.0'
gem 'nokogiri', '~> 1.8.2' gem 'nokogiri', '~> 1.8.2'
@ -226,7 +219,7 @@ gem 'kubeclient', '~> 3.0'
gem 'd3_rails', '~> 3.5.0' gem 'd3_rails', '~> 3.5.0'
# Sanitize user input # Sanitize user input
gem 'sanitize', '~> 2.0' gem 'sanitize', '~> 4.6.5'
gem 'babosa', '~> 1.0.2' gem 'babosa', '~> 1.0.2'
# Sanitizes SVG input # Sanitizes SVG input

View file

@ -298,11 +298,22 @@ GEM
escape_utils (~> 1.1.0) escape_utils (~> 1.1.0)
mime-types (>= 1.19) mime-types (>= 1.19)
rugged (>= 0.25.1) rugged (>= 0.25.1)
github-markup (1.6.1) github-markup (1.7.0)
gitlab-flowdock-git-hook (1.0.1) gitlab-flowdock-git-hook (1.0.1)
flowdock (~> 0.7) flowdock (~> 0.7)
gitlab-grit (>= 2.4.1) gitlab-grit (>= 2.4.1)
multi_json multi_json
gitlab-gollum-lib (4.2.7.5)
gemojione (~> 3.2)
github-markup (~> 1.6)
gollum-grit_adapter (~> 1.0)
nokogiri (>= 1.6.1, < 2.0)
rouge (~> 3.1)
sanitize (~> 4.6.4)
stringex (~> 2.6)
gitlab-gollum-rugged_adapter (0.4.4)
mime-types (>= 1.15)
rugged (~> 0.25)
gitlab-grit (2.8.2) gitlab-grit (2.8.2)
charlock_holmes (~> 0.6) charlock_holmes (~> 0.6)
diff-lcs (~> 1.1) diff-lcs (~> 1.1)
@ -322,17 +333,6 @@ GEM
activesupport (>= 4.2.0) activesupport (>= 4.2.0)
gollum-grit_adapter (1.0.1) gollum-grit_adapter (1.0.1)
gitlab-grit (~> 2.7, >= 2.7.1) gitlab-grit (~> 2.7, >= 2.7.1)
gollum-lib (4.2.7)
gemojione (~> 3.2)
github-markup (~> 1.6)
gollum-grit_adapter (~> 1.0)
nokogiri (>= 1.6.1, < 2.0)
rouge (~> 2.1)
sanitize (~> 2.1)
stringex (~> 2.6)
gollum-rugged_adapter (0.4.4)
mime-types (>= 1.15)
rugged (~> 0.25)
gon (6.1.0) gon (6.1.0)
actionpack (>= 3.0) actionpack (>= 3.0)
json json
@ -517,6 +517,8 @@ GEM
netrc (0.11.0) netrc (0.11.0)
nokogiri (1.8.2) nokogiri (1.8.2)
mini_portile2 (~> 2.3.0) mini_portile2 (~> 2.3.0)
nokogumbo (1.5.0)
nokogiri
numerizer (0.1.1) numerizer (0.1.1)
oauth (0.5.4) oauth (0.5.4)
oauth2 (1.4.0) oauth2 (1.4.0)
@ -744,7 +746,7 @@ GEM
retriable (3.1.1) retriable (3.1.1)
rinku (2.0.0) rinku (2.0.0)
rotp (2.1.2) rotp (2.1.2)
rouge (2.2.1) rouge (3.1.1)
rqrcode (0.7.0) rqrcode (0.7.0)
chunky_png chunky_png
rqrcode-rails3 (0.1.7) rqrcode-rails3 (0.1.7)
@ -812,8 +814,10 @@ GEM
et-orbi (~> 1.0) et-orbi (~> 1.0)
rugged (0.27.0) rugged (0.27.0)
safe_yaml (1.0.4) safe_yaml (1.0.4)
sanitize (2.1.0) sanitize (4.6.5)
crass (~> 1.0.2)
nokogiri (>= 1.4.4) nokogiri (>= 1.4.4)
nokogumbo (~> 1.4)
sass (3.5.5) sass (3.5.5)
sass-listen (~> 4.0.0) sass-listen (~> 4.0.0)
sass-listen (4.0.0) sass-listen (4.0.0)
@ -904,7 +908,7 @@ GEM
state_machines-activerecord (0.5.1) state_machines-activerecord (0.5.1)
activerecord (>= 4.1, < 6.0) activerecord (>= 4.1, < 6.0)
state_machines-activemodel (>= 0.5.0) state_machines-activemodel (>= 0.5.0)
stringex (2.7.1) stringex (2.8.4)
sys-filesystem (1.1.6) sys-filesystem (1.1.6)
ffi ffi
sysexits (1.2.0) sysexits (1.2.0)
@ -1061,11 +1065,11 @@ DEPENDENCIES
gitaly-proto (~> 0.96.0) gitaly-proto (~> 0.96.0)
github-linguist (~> 5.3.3) github-linguist (~> 5.3.3)
gitlab-flowdock-git-hook (~> 1.0.1) gitlab-flowdock-git-hook (~> 1.0.1)
gitlab-gollum-lib (~> 4.2)
gitlab-gollum-rugged_adapter (~> 0.4.4)
gitlab-markup (~> 1.6.2) gitlab-markup (~> 1.6.2)
gitlab-styles (~> 2.3) gitlab-styles (~> 2.3)
gitlab_omniauth-ldap (~> 2.0.4) gitlab_omniauth-ldap (~> 2.0.4)
gollum-lib (~> 4.2)
gollum-rugged_adapter (~> 0.4.4)
gon (~> 6.1.0) gon (~> 6.1.0)
google-api-client (~> 0.19.8) google-api-client (~> 0.19.8)
google-protobuf (= 3.5.1) google-protobuf (= 3.5.1)
@ -1156,7 +1160,7 @@ DEPENDENCIES
redis-rails (~> 5.0.2) redis-rails (~> 5.0.2)
request_store (~> 1.3) request_store (~> 1.3)
responders (~> 2.0) responders (~> 2.0)
rouge (~> 2.0) rouge (~> 3.1)
rqrcode-rails3 (~> 0.1.7) rqrcode-rails3 (~> 0.1.7)
rspec-parameterized rspec-parameterized
rspec-rails (~> 3.6.0) rspec-rails (~> 3.6.0)
@ -1170,7 +1174,7 @@ DEPENDENCIES
ruby_parser (~> 3.8) ruby_parser (~> 3.8)
rufus-scheduler (~> 3.4) rufus-scheduler (~> 3.4)
rugged (~> 0.27) rugged (~> 0.27)
sanitize (~> 2.0) sanitize (~> 4.6.5)
sass-rails (~> 5.0.6) sass-rails (~> 5.0.6)
scss_lint (~> 0.56.0) scss_lint (~> 0.56.0)
seed-fu (~> 2.3.7) seed-fu (~> 2.3.7)

View file

@ -1 +1 @@
10.7.5 10.7.6

View file

@ -5,6 +5,7 @@ class ApplicationController < ActionController::Base
include Gitlab::GonHelper include Gitlab::GonHelper
include GitlabRoutingHelper include GitlabRoutingHelper
include PageLayoutHelper include PageLayoutHelper
include SafeParamsHelper
include SentryHelper include SentryHelper
include WorkhorseHelper include WorkhorseHelper
include EnforcesTwoFactorAuthentication include EnforcesTwoFactorAuthentication

View file

@ -57,7 +57,7 @@ module IssuableCollections
out_of_range = @issuables.current_page > total_pages # rubocop:disable Gitlab/ModuleWithInstanceVariables out_of_range = @issuables.current_page > total_pages # rubocop:disable Gitlab/ModuleWithInstanceVariables
if out_of_range if out_of_range
redirect_to(url_for(params.merge(page: total_pages, only_path: true))) redirect_to(url_for(safe_params.merge(page: total_pages, only_path: true)))
end end
out_of_range out_of_range

View file

@ -86,7 +86,7 @@ class Dashboard::TodosController < Dashboard::ApplicationController
out_of_range = todos.current_page > total_pages out_of_range = todos.current_page > total_pages
if out_of_range if out_of_range
redirect_to url_for(params.merge(page: total_pages, only_path: true)) redirect_to url_for(safe_params.merge(page: total_pages, only_path: true))
end end
out_of_range out_of_range

View file

@ -33,6 +33,6 @@ class Groups::ApplicationController < ApplicationController
def build_canonical_path(group) def build_canonical_path(group)
params[:group_id] = group.to_param params[:group_id] = group.to_param
url_for(params) url_for(safe_params)
end end
end end

View file

@ -189,6 +189,6 @@ class GroupsController < Groups::ApplicationController
params[:id] = group.to_param params[:id] = group.to_param
url_for(params) url_for(safe_params)
end end
end end

View file

@ -25,7 +25,7 @@ class Projects::ApplicationController < ApplicationController
params[:namespace_id] = project.namespace.to_param params[:namespace_id] = project.namespace.to_param
params[:project_id] = project.to_param params[:project_id] = project.to_param
url_for(params) url_for(safe_params)
end end
def repository def repository

View file

@ -404,7 +404,7 @@ class ProjectsController < Projects::ApplicationController
params[:namespace_id] = project.namespace.to_param params[:namespace_id] = project.namespace.to_param
params[:id] = project.to_param params[:id] = project.to_param
url_for(params) url_for(safe_params)
end end
def project_export_enabled def project_export_enabled

View file

@ -146,6 +146,6 @@ class UsersController < ApplicationController
end end
def build_canonical_path(user) def build_canonical_path(user)
url_for(params.merge(username: user.to_param)) url_for(safe_params.merge(username: user.to_param))
end end
end end

View file

@ -56,7 +56,7 @@ class UserRecentEventsFinder
visible = target_user visible = target_user
.project_interactions .project_interactions
.where(visibility_level: [Gitlab::VisibilityLevel::INTERNAL, Gitlab::VisibilityLevel::PUBLIC]) .where(visibility_level: Gitlab::VisibilityLevel.levels_for_user(current_user))
.select(:id) .select(:id)
Gitlab::SQL::Union.new([authorized, visible]).to_sql Gitlab::SQL::Union.new([authorized, visible]).to_sql

View file

@ -259,7 +259,7 @@ module BlobHelper
options = [] options = []
if error == :collapsed if error == :collapsed
options << link_to('load it anyway', url_for(params.merge(viewer: viewer.type, expanded: true, format: nil))) options << link_to('load it anyway', url_for(safe_params.merge(viewer: viewer.type, expanded: true, format: nil)))
end end
# If the error is `:server_side_but_stored_externally`, the simple viewer will show the same error, # If the error is `:server_side_but_stored_externally`, the simple viewer will show the same error,

View file

@ -180,7 +180,7 @@ module DiffHelper
private private
def diff_btn(title, name, selected) def diff_btn(title, name, selected)
params_copy = params.dup params_copy = safe_params.dup
params_copy[:view] = name params_copy[:view] = name
# Always use HTML to handle case where JSON diff rendered this button # Always use HTML to handle case where JSON diff rendered this button

View file

@ -40,7 +40,8 @@ module ProjectsHelper
name_tag_options[:class] << 'has-tooltip' name_tag_options[:class] << 'has-tooltip'
end end
content_tag(:span, sanitize(username), name_tag_options) # NOTE: ActionView::Helpers::TagHelper#content_tag HTML escapes username
content_tag(:span, username, name_tag_options)
end end
def link_to_member(project, author, opts = {}, &block) def link_to_member(project, author, opts = {}, &block)

View file

@ -0,0 +1,11 @@
module SafeParamsHelper
# Rails 5.0 requires to permit parameters if used in url helpers.
# Use this helper when generating links with `params.merge(...)`
def safe_params
if params.respond_to?(:permit!)
params.except(:host, :port, :protocol).permit!
else
params
end
end
end

View file

@ -1,5 +1,5 @@
xml.title "#{current_user.name} issues" xml.title "#{current_user.name} issues"
xml.link href: url_for(params), rel: "self", type: "application/atom+xml" xml.link href: url_for(safe_params), rel: "self", type: "application/atom+xml"
xml.link href: issues_dashboard_url, rel: "alternate", type: "text/html" xml.link href: issues_dashboard_url, rel: "alternate", type: "text/html"
xml.id issues_dashboard_url xml.id issues_dashboard_url
xml.updated @issues.first.updated_at.xmlschema if @issues.reorder(nil).any? xml.updated @issues.first.updated_at.xmlschema if @issues.reorder(nil).any?

View file

@ -2,12 +2,12 @@
- page_title _("Issues") - page_title _("Issues")
- @breadcrumb_link = issues_dashboard_path(assignee_id: current_user.id) - @breadcrumb_link = issues_dashboard_path(assignee_id: current_user.id)
= content_for :meta_tags do = content_for :meta_tags do
= auto_discovery_link_tag(:atom, params.merge(rss_url_options), title: "#{current_user.name} issues") = auto_discovery_link_tag(:atom, safe_params.merge(rss_url_options).to_h, title: "#{current_user.name} issues")
.top-area .top-area
= render 'shared/issuable/nav', type: :issues, display_count: !@no_filters_set = render 'shared/issuable/nav', type: :issues, display_count: !@no_filters_set
.nav-controls .nav-controls
= link_to params.merge(rss_url_options), class: 'btn has-tooltip', data: { container: 'body' }, title: 'Subscribe' do = link_to safe_params.merge(rss_url_options), class: 'btn has-tooltip', data: { container: 'body' }, title: 'Subscribe' do
= icon('rss') = icon('rss')
= render 'shared/new_project_item_select', path: 'issues/new', label: "New issue", with_feature_enabled: 'issues', type: :issues = render 'shared/new_project_item_select', path: 'issues/new', label: "New issue", with_feature_enabled: 'issues', type: :issues

View file

@ -1,5 +1,5 @@
xml.title "#{@group.name} issues" xml.title "#{@group.name} issues"
xml.link href: url_for(params), rel: "self", type: "application/atom+xml" xml.link href: url_for(safe_params), rel: "self", type: "application/atom+xml"
xml.link href: issues_group_url, rel: "alternate", type: "text/html" xml.link href: issues_group_url, rel: "alternate", type: "text/html"
xml.id issues_group_url xml.id issues_group_url
xml.updated @issues.first.updated_at.xmlschema if @issues.reorder(nil).any? xml.updated @issues.first.updated_at.xmlschema if @issues.reorder(nil).any?

View file

@ -1,6 +1,6 @@
- page_title "Issues" - page_title "Issues"
= content_for :meta_tags do = content_for :meta_tags do
= auto_discovery_link_tag(:atom, params.merge(rss_url_options), title: "#{@group.name} issues") = auto_discovery_link_tag(:atom, safe_params.merge(rss_url_options).to_h, title: "#{@group.name} issues")
- if group_issues_count(state: 'all').zero? - if group_issues_count(state: 'all').zero?
= render 'shared/empty_states/issues', project_select_button: true = render 'shared/empty_states/issues', project_select_button: true

View file

@ -3,7 +3,7 @@
#js-peek{ data: { env: Peek.env, #js-peek{ data: { env: Peek.env,
request_id: Peek.request_id, request_id: Peek.request_id,
peek_url: peek_routes.results_url, peek_url: peek_routes.results_url,
profile_url: url_for(params.merge(lineprofiler: 'true')) }, profile_url: url_for(safe_params.merge(lineprofiler: 'true')) },
class: Peek.env } class: Peek.env }
#peek-view-performance-bar.hidden #peek-view-performance-bar.hidden

View file

@ -3,7 +3,7 @@
- rich_type = viewer.type == :rich ? viewer.partial_name : nil - rich_type = viewer.type == :rich ? viewer.partial_name : nil
- load_async = local_assigns.fetch(:load_async, viewer.load_async? && render_error.nil?) - load_async = local_assigns.fetch(:load_async, viewer.load_async? && render_error.nil?)
- viewer_url = local_assigns.fetch(:viewer_url) { url_for(params.merge(viewer: viewer.type, format: :json)) } if load_async - viewer_url = local_assigns.fetch(:viewer_url) { url_for(safe_params.merge(viewer: viewer.type, format: :json)) } if load_async
.blob-viewer{ data: { type: viewer.type, rich_type: rich_type, url: viewer_url }, class: ('hidden' if hidden) } .blob-viewer{ data: { type: viewer.type, rich_type: rich_type, url: viewer_url }, class: ('hidden' if hidden) }
- if render_error - if render_error
= render 'projects/blob/render_error', viewer: viewer = render 'projects/blob/render_error', viewer: viewer

View file

@ -1,5 +1,5 @@
- diff_file = viewer.diff_file - diff_file = viewer.diff_file
- url = url_for(params.merge(action: :diff_for_path, old_path: diff_file.old_path, new_path: diff_file.new_path, file_identifier: diff_file.file_identifier)) - url = url_for(safe_params.merge(action: :diff_for_path, old_path: diff_file.old_path, new_path: diff_file.new_path, file_identifier: diff_file.file_identifier))
.nothing-here-block.diff-collapsed{ data: { diff_for_path: url } } .nothing-here-block.diff-collapsed{ data: { diff_for_path: url } }
This diff is collapsed. This diff is collapsed.
%a.click-to-expand Click to expand it. %a.click-to-expand Click to expand it.

View file

@ -8,7 +8,7 @@
.files-changed-inner .files-changed-inner
.inline-parallel-buttons.hidden-xs.hidden-sm .inline-parallel-buttons.hidden-xs.hidden-sm
- if !diffs_expanded? && diff_files.any? { |diff_file| diff_file.collapsed? } - if !diffs_expanded? && diff_files.any? { |diff_file| diff_file.collapsed? }
= link_to 'Expand all', url_for(params.merge(expanded: 1, format: nil)), class: 'btn btn-default' = link_to 'Expand all', url_for(safe_params.merge(expanded: 1, format: nil)), class: 'btn btn-default'
- if show_whitespace_toggle - if show_whitespace_toggle
- if current_controller?(:commit) - if current_controller?(:commit)
= commit_diff_whitespace_link(diffs.project, @commit, class: 'hidden-xs') = commit_diff_whitespace_link(diffs.project, @commit, class: 'hidden-xs')

View file

@ -30,7 +30,7 @@
#{@commits_graph.start_date.strftime('%b %d')} #{@commits_graph.start_date.strftime('%b %d')}
- end_time = capture do - end_time = capture do
#{@commits_graph.end_date.strftime('%b %d')} #{@commits_graph.end_date.strftime('%b %d')}
= (_("Commit statistics for %{ref} %{start_time} - %{end_time}") % { ref: "<strong>#{@ref}</strong>", start_time: start_time, end_time: end_time }).html_safe = (_("Commit statistics for %{ref} %{start_time} - %{end_time}") % { ref: "<strong>#{h @ref}</strong>", start_time: start_time, end_time: end_time }).html_safe
.col-md-6 .col-md-6
.tree-ref-container .tree-ref-container

View file

@ -1,4 +1,4 @@
= link_to params.merge(rss_url_options), class: 'btn btn-default append-right-10 has-tooltip', title: 'Subscribe' do = link_to safe_params.merge(rss_url_options), class: 'btn btn-default append-right-10 has-tooltip', title: 'Subscribe' do
= icon('rss') = icon('rss')
- if @can_bulk_update - if @can_bulk_update
= button_tag "Edit issues", class: "btn btn-default append-right-10 js-bulk-update-toggle" = button_tag "Edit issues", class: "btn btn-default append-right-10 js-bulk-update-toggle"

View file

@ -1,5 +1,5 @@
xml.title "#{@project.name} issues" xml.title "#{@project.name} issues"
xml.link href: url_for(params), rel: "self", type: "application/atom+xml" xml.link href: url_for(safe_params), rel: "self", type: "application/atom+xml"
xml.link href: project_issues_url(@project), rel: "alternate", type: "text/html" xml.link href: project_issues_url(@project), rel: "alternate", type: "text/html"
xml.id project_issues_url(@project) xml.id project_issues_url(@project)
xml.updated @issues.first.updated_at.xmlschema if @issues.reorder(nil).any? xml.updated @issues.first.updated_at.xmlschema if @issues.reorder(nil).any?

View file

@ -5,7 +5,7 @@
- new_issue_email = @project.new_issuable_address(current_user, 'issue') - new_issue_email = @project.new_issuable_address(current_user, 'issue')
= content_for :meta_tags do = content_for :meta_tags do
= auto_discovery_link_tag(:atom, params.merge(rss_url_options), title: "#{@project.name} issues") = auto_discovery_link_tag(:atom, safe_params.merge(rss_url_options).to_h, title: "#{@project.name} issues")
- if project_issues(@project).exists? - if project_issues(@project).exists?
%div{ class: (container_class) } %div{ class: (container_class) }

View file

@ -26,16 +26,16 @@
- else - else
%ul.merge-request-tabs.nav-links.no-top.no-bottom %ul.merge-request-tabs.nav-links.no-top.no-bottom
%li.commits-tab.active %li.commits-tab.active
= link_to url_for(params), data: {target: 'div#commits', action: 'new', toggle: 'tab'} do = link_to url_for(safe_params), data: {target: 'div#commits', action: 'new', toggle: 'tab'} do
Commits Commits
%span.badge= @commits.size %span.badge= @commits.size
- if @pipelines.any? - if @pipelines.any?
%li.builds-tab %li.builds-tab
= link_to url_for(params.merge(action: 'pipelines')), data: {target: 'div#pipelines', action: 'pipelines', toggle: 'tab'} do = link_to url_for(safe_params.merge(action: 'pipelines')), data: {target: 'div#pipelines', action: 'pipelines', toggle: 'tab'} do
Pipelines Pipelines
%span.badge= @pipelines.size %span.badge= @pipelines.size
%li.diffs-tab %li.diffs-tab
= link_to url_for(params.merge(action: 'diffs')), data: {target: 'div#diffs', action: 'diffs', toggle: 'tab'} do = link_to url_for(safe_params.merge(action: 'diffs')), data: {target: 'div#diffs', action: 'diffs', toggle: 'tab'} do
Changes Changes
%span.badge= @merge_request.diff_size %span.badge= @merge_request.diff_size
@ -46,7 +46,7 @@
-# This tab is always loaded via AJAX -# This tab is always loaded via AJAX
- if @pipelines.any? - if @pipelines.any?
#pipelines.pipelines.tab-pane #pipelines.pipelines.tab-pane
= render 'projects/merge_requests/pipelines', endpoint: url_for(params.merge(action: 'pipelines', format: :json)), disable_initialization: true = render 'projects/merge_requests/pipelines', endpoint: url_for(safe_params.merge(action: 'pipelines', format: :json)), disable_initialization: true
.mr-loading-status .mr-loading-status
= spinner = spinner

View file

@ -7,139 +7,6 @@ module Gollum
end end
require "gollum-lib" require "gollum-lib"
module Gollum
class Committer
# Patch for UTF-8 path
def method_missing(name, *args)
index.send(name, *args)
end
end
class Wiki
def pages(treeish = nil, limit: nil)
tree_list((treeish || @ref), limit: limit)
end
def tree_list(ref, limit: nil)
if (sha = @access.ref_to_sha(ref))
commit = @access.commit(sha)
tree_map_for(sha).inject([]) do |list, entry|
next list unless @page_class.valid_page_name?(entry.name)
list << entry.page(self, commit)
break list if limit && list.size >= limit
list
end
else
[]
end
end
# Remove if https://github.com/gollum/gollum-lib/pull/292 has been merged
def update_page(page, name, format, data, commit = {})
name = name ? ::File.basename(name) : page.name
format ||= page.format
dir = ::File.dirname(page.path)
dir = '' if dir == '.'
filename = (rename = page.name != name) ? Gollum::Page.cname(name) : page.filename_stripped
multi_commit = !!commit[:committer]
committer = multi_commit ? commit[:committer] : Committer.new(self, commit)
if !rename && page.format == format
committer.add(page.path, normalize(data))
else
committer.delete(page.path)
committer.add_to_index(dir, filename, format, data)
end
committer.after_commit do |index, _sha|
@access.refresh
index.update_working_dir(dir, page.filename_stripped, page.format)
index.update_working_dir(dir, filename, format)
end
multi_commit ? committer : committer.commit
end
# Remove if https://github.com/gollum/gollum-lib/pull/292 has been merged
def rename_page(page, rename, commit = {})
return false if page.nil?
return false if rename.nil? || rename.empty?
(target_dir, target_name) = ::File.split(rename)
(source_dir, source_name) = ::File.split(page.path)
source_name = page.filename_stripped
# File.split gives us relative paths with ".", commiter.add_to_index doesn't like that.
target_dir = '' if target_dir == '.'
source_dir = '' if source_dir == '.'
target_dir = target_dir.gsub(/^\//, '') # rubocop:disable Style/RegexpLiteral
# if the rename is a NOOP, abort
if source_dir == target_dir && source_name == target_name
return false
end
multi_commit = !!commit[:committer]
committer = multi_commit ? commit[:committer] : Committer.new(self, commit)
# This piece only works for multi_commit
# If we are in a commit batch and one of the previous operations
# has updated the page, any information we ask to the page can be outdated.
# Therefore, we should ask first to the current committer tree to see if
# there is any updated change.
raw_data = raw_data_in_committer(committer, source_dir, page.filename) ||
raw_data_in_committer(committer, source_dir, "#{target_name}.#{Page.format_to_ext(page.format)}") ||
page.raw_data
committer.delete(page.path)
committer.add_to_index(target_dir, target_name, page.format, raw_data)
committer.after_commit do |index, _sha|
@access.refresh
index.update_working_dir(source_dir, source_name, page.format)
index.update_working_dir(target_dir, target_name, page.format)
end
multi_commit ? committer : committer.commit
end
# Remove if https://github.com/gollum/gollum-lib/pull/292 has been merged
def raw_data_in_committer(committer, dir, filename)
data = nil
[*dir.split(::File::SEPARATOR), filename].each do |key|
data = data ? data[key] : committer.tree[key]
break unless data
end
data
end
end
module Git
class Git
def tree_entry(commit, path)
pathname = Pathname.new(path)
tmp_entry = nil
pathname.each_filename do |dir|
tmp_entry = if tmp_entry.nil?
commit.tree[dir]
else
@repo.lookup(tmp_entry[:oid])[dir]
end
return nil unless tmp_entry
end
tmp_entry
end
end
end
end
Rails.application.configure do Rails.application.configure do
config.after_initialize do config.after_initialize do
Gollum::Page.per_page = Kaminari.config.default_per_page Gollum::Page.per_page = Kaminari.config.default_per_page

View file

@ -25,10 +25,11 @@ module Banzai
# Only push these customizations once # Only push these customizations once
return if customized?(whitelist[:transformers]) return if customized?(whitelist[:transformers])
# Allow table alignment; we whitelist specific style properties in a # Allow table alignment; we whitelist specific text-align values in a
# transformer below # transformer below
whitelist[:attributes]['th'] = %w(style) whitelist[:attributes]['th'] = %w(style)
whitelist[:attributes]['td'] = %w(style) whitelist[:attributes]['td'] = %w(style)
whitelist[:css] = { properties: ['text-align'] }
# Allow span elements # Allow span elements
whitelist[:elements].push('span') whitelist[:elements].push('span')

View file

@ -92,7 +92,7 @@ module Banzai
def text def text
return '' unless node return '' unless node
@text ||= node.text @text ||= EscapeUtils.escape_html(node.text)
end end
private private

View file

@ -3,6 +3,7 @@ require 'spec_helper'
describe 'Project Graph', :js do describe 'Project Graph', :js do
let(:user) { create :user } let(:user) { create :user }
let(:project) { create(:project, :repository, namespace: user.namespace) } let(:project) { create(:project, :repository, namespace: user.namespace) }
let(:branch_name) { 'master' }
before do before do
project.add_master(user) project.add_master(user)
@ -12,7 +13,7 @@ describe 'Project Graph', :js do
shared_examples 'page should have commits graphs' do shared_examples 'page should have commits graphs' do
it 'renders commits' do it 'renders commits' do
expect(page).to have_content('Commit statistics for master') expect(page).to have_content("Commit statistics for #{branch_name}")
expect(page).to have_content('Commits per day of month') expect(page).to have_content('Commits per day of month')
end end
end end
@ -57,6 +58,23 @@ describe 'Project Graph', :js do
it_behaves_like 'page should have languages graphs' it_behaves_like 'page should have languages graphs'
end end
context 'chart graph with HTML escaped branch name' do
let(:branch_name) { '<h1>evil</h1>' }
before do
project.repository.create_branch(branch_name, 'master')
visit charts_project_graph_path(project, branch_name)
end
it_behaves_like 'page should have commits graphs'
it 'HTML escapes branch name' do
expect(page.body).to include("Commit statistics for <strong>#{ERB::Util.html_escape(branch_name)}</strong>")
expect(page.body).not_to include(branch_name)
end
end
context 'when CI enabled' do context 'when CI enabled' do
before do before do
project.enable_ci project.enable_ci

View file

@ -1,31 +1,50 @@
require 'spec_helper' require 'spec_helper'
describe UserRecentEventsFinder do describe UserRecentEventsFinder do
let(:user) { create(:user) } let(:current_user) { create(:user) }
let(:project) { create(:project) } let(:project_owner) { create(:user) }
let(:project_owner) { project.creator } let(:private_project) { create(:project, :private, creator: project_owner) }
let!(:event) { create(:event, project: project, author: project_owner) } let(:internal_project) { create(:project, :internal, creator: project_owner) }
let(:public_project) { create(:project, :public, creator: project_owner) }
let!(:private_event) { create(:event, project: private_project, author: project_owner) }
let!(:internal_event) { create(:event, project: internal_project, author: project_owner) }
let!(:public_event) { create(:event, project: public_project, author: project_owner) }
subject(:finder) { described_class.new(user, project_owner) } subject(:finder) { described_class.new(current_user, project_owner) }
describe '#execute' do describe '#execute' do
it 'does not include the event when a user does not have access to the project' do context 'current user does not have access to projects' do
expect(finder.execute).to be_empty it 'returns public and internal events' do
records = finder.execute
expect(records).to include(public_event, internal_event)
expect(records).not_to include(private_event)
end
end end
context 'when the user has access to a project' do context 'when current user has access to the projects' do
before do before do
project.add_developer(user) private_project.add_developer(current_user)
internal_project.add_developer(current_user)
public_project.add_developer(current_user)
end end
it 'includes the event' do it 'returns all the events' do
expect(finder.execute).to include(event) expect(finder.execute).to include(private_event, internal_event, public_event)
end end
it 'does not include the event if the user cannot read cross project' do it 'does not include the events if the user cannot read cross project' do
expect(Ability).to receive(:allowed?).with(user, :read_cross_project) { false } expect(Ability).to receive(:allowed?).with(current_user, :read_cross_project) { false }
expect(finder.execute).to be_empty expect(finder.execute).to be_empty
end end
end end
context 'when current user is anonymous' do
let(:current_user) { nil }
it 'returns public events only' do
expect(finder.execute).to eq([public_event])
end
end
end end
end end

View file

@ -244,7 +244,7 @@ describe ProjectsHelper do
describe '#link_to_member' do describe '#link_to_member' do
let(:group) { build_stubbed(:group) } let(:group) { build_stubbed(:group) }
let(:project) { build_stubbed(:project, group: group) } let(:project) { build_stubbed(:project, group: group) }
let(:user) { build_stubbed(:user) } let(:user) { build_stubbed(:user, name: '<h1>Administrator</h1>') }
describe 'using the default options' do describe 'using the default options' do
it 'returns an HTML link to the user' do it 'returns an HTML link to the user' do
@ -252,6 +252,13 @@ describe ProjectsHelper do
expect(link).to match(%r{/#{user.username}}) expect(link).to match(%r{/#{user.username}})
end end
it 'HTML escapes the name of the user' do
link = helper.link_to_member(project, user)
expect(link).to include(ERB::Util.html_escape(user.name))
expect(link).not_to include(user.name)
end
end end
end end

View file

@ -1,62 +0,0 @@
require 'spec_helper'
describe 'gollum' do
let(:project) { create(:project) }
let(:user) { project.owner }
let(:wiki) { ProjectWiki.new(project, user) }
let(:gollum_wiki) { Gollum::Wiki.new(wiki.repository.path) }
before do
create_page(page_name, 'content1')
end
after do
destroy_page(page_name)
end
context 'with simple paths' do
let(:page_name) { 'page1' }
it 'returns the entry hash if it matches the file name' do
expect(tree_entry(page_name)).not_to be_nil
end
it 'returns nil if the path does not fit completely' do
expect(tree_entry("foo/#{page_name}")).to be_nil
end
end
context 'with complex paths' do
let(:page_name) { '/foo/bar/page2' }
it 'returns the entry hash if it matches the file name' do
expect(tree_entry(page_name)).not_to be_nil
end
it 'returns nil if the path does not fit completely' do
expect(tree_entry("foo1/bar/page2")).to be_nil
expect(tree_entry("foo/bar1/page2")).to be_nil
end
end
def tree_entry(name)
gollum_wiki.repo.git.tree_entry(wiki_commits[0].commit, name + '.md')
end
def wiki_commits
gollum_wiki.repo.commits
end
def commit_details
Gitlab::Git::Wiki::CommitDetails.new(user.name, user.email, "test commit")
end
def create_page(name, content)
wiki.wiki.write_page(name, :markdown, content, commit_details)
end
def destroy_page(name)
page = wiki.find_page(name).page
wiki.delete_page(page, "test commit")
end
end

View file

@ -93,6 +93,16 @@ describe Banzai::Filter::SanitizationFilter do
expect(doc.at_css('td')['style']).to eq 'text-align: center' expect(doc.at_css('td')['style']).to eq 'text-align: center'
end end
it 'disallows `text-align` property in `style` attribute on other elements' do
html = <<~HTML
<div style="text-align: center">Text</div>
HTML
doc = filter(html)
expect(doc.at_css('div')['style']).to be_nil
end
it 'allows `span` elements' do it 'allows `span` elements' do
exp = act = %q{<span>Hello</span>} exp = act = %q{<span>Hello</span>}
expect(filter(act).to_html).to eq exp expect(filter(act).to_html).to eq exp
@ -224,7 +234,7 @@ describe Banzai::Filter::SanitizationFilter do
'protocol-based JS injection: spaces and entities' => { 'protocol-based JS injection: spaces and entities' => {
input: '<a href=" &#14; javascript:alert(\'XSS\');">foo</a>', input: '<a href=" &#14; javascript:alert(\'XSS\');">foo</a>',
output: '<a href="">foo</a>' output: '<a href>foo</a>'
}, },
'protocol whitespace' => { 'protocol whitespace' => {

View file

@ -139,5 +139,14 @@ describe Banzai::Filter::TableOfContentsFilter do
expect(items[5].ancestors).to include(items[4]) expect(items[5].ancestors).to include(items[4])
end end
end end
context 'header text contains escaped content' do
let(:content) { '&lt;img src="x" onerror="alert(42)"&gt;' }
let(:results) { result(header(1, content)) }
it 'outputs escaped content' do
expect(doc.inner_html).to include(content)
end
end
end end
end end