diff options
-rw-r--r-- | app/assets/stylesheets/framework/blocks.scss | 4 | ||||
-rw-r--r-- | app/views/groups/_projects.html.haml | 13 | ||||
-rw-r--r-- | app/views/groups/_shared_projects.html.haml | 19 | ||||
-rw-r--r-- | app/views/groups/show.html.haml | 33 | ||||
-rw-r--r-- | lib/banzai/filter/sanitization_filter.rb | 9 | ||||
-rw-r--r-- | spec/lib/banzai/filter/sanitization_filter_spec.rb | 20 |
6 files changed, 54 insertions, 44 deletions
diff --git a/app/assets/stylesheets/framework/blocks.scss b/app/assets/stylesheets/framework/blocks.scss index 6edabe20136..d20b77ffae9 100644 --- a/app/assets/stylesheets/framework/blocks.scss +++ b/app/assets/stylesheets/framework/blocks.scss @@ -120,6 +120,10 @@ .cover-desc { padding: 0 $gl-padding 3px; color: $gl-text-color; + + &.username:last-child { + padding-bottom: $gl-padding; + } } .cover-controls { diff --git a/app/views/groups/_projects.html.haml b/app/views/groups/_projects.html.haml index 7cd8e9bea46..cca7dc27b1c 100644 --- a/app/views/groups/_projects.html.haml +++ b/app/views/groups/_projects.html.haml @@ -1,12 +1 @@ -.top-area - .nav-controls - = form_tag request.original_url, method: :get, class: 'project-filter-form', id: 'project-filter-form' do |f| - - if @projects.present? - = search_field_tag :filter_projects, nil, placeholder: 'Filter by name', class: 'projects-list-filter form-control', spellcheck: false - = render 'shared/projects/dropdown' - - if can? current_user, :create_projects, @group - = link_to new_project_path(namespace_id: @group.id), class: 'btn btn-new pull-right' do - = icon('plus') - New Project - -= render 'shared/projects/list', projects: @projects, stars: false, skip_namespace: true += render 'shared/projects/list', projects: projects, stars: false, skip_namespace: true diff --git a/app/views/groups/_shared_projects.html.haml b/app/views/groups/_shared_projects.html.haml index d707ad4272d..b1694c919d0 100644 --- a/app/views/groups/_shared_projects.html.haml +++ b/app/views/groups/_shared_projects.html.haml @@ -1,18 +1 @@ -- if projects.present? - .panel.panel-default - .panel-heading - Projects shared with - %strong #{@group.name} - (#{projects.count}) - %ul.well-list - - projects.each do |project| - %li.project-row - = link_to namespace_project_path(project.namespace, project), class: dom_class(project) do - %span.namespace-name - - if project.namespace - = project.namespace.human_name - \/ - %span.project-name - = truncate(project.name, length: 25) - %span.arrow - %i.icon-angle-right += render 'shared/projects/list', projects: projects, stars: false, skip_namespace: false diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml index de314a4190c..23a34ac36dd 100644 --- a/app/views/groups/show.html.haml +++ b/app/views/groups/show.html.haml @@ -27,24 +27,33 @@ .cover-desc.description = markdown(@group.description, pipeline: :description) - - %ul.nav-links - %li.active - = link_to "#projects", 'data-toggle' => 'tab' do - Projects - - if @shared_projects.present? - %li - = link_to "#shared", 'data-toggle' => 'tab' do - Shared Projects - - if can?(current_user, :read_group, @group) %div{ class: container_class } + .top-area + %ul.nav-links + %li.active + = link_to "#projects", 'data-toggle' => 'tab' do + All Projects + - if @shared_projects.present? + %li + = link_to "#shared", 'data-toggle' => 'tab' do + Shared Projects + .nav-controls + = form_tag request.original_url, method: :get, class: 'project-filter-form', id: 'project-filter-form' do |f| + = search_field_tag :filter_projects, nil, placeholder: 'Filter by name', class: 'projects-list-filter form-control', spellcheck: false + = render 'shared/projects/dropdown' + - if can? current_user, :create_projects, @group + = link_to new_project_path(namespace_id: @group.id), class: 'btn btn-new pull-right' do + = icon('plus') + New Project + .tab-content .tab-pane.active#projects = render "projects", projects: @projects - .tab-pane#shared - = render "shared_projects", projects: @shared_projects + - if @shared_projects.present? + .tab-pane#shared + = render "shared_projects", projects: @shared_projects - else %p.nav-links.no-top diff --git a/lib/banzai/filter/sanitization_filter.rb b/lib/banzai/filter/sanitization_filter.rb index abd79b329ae..e8011519608 100644 --- a/lib/banzai/filter/sanitization_filter.rb +++ b/lib/banzai/filter/sanitization_filter.rb @@ -7,7 +7,7 @@ module Banzai # # Extends HTML::Pipeline::SanitizationFilter with a custom whitelist. class SanitizationFilter < HTML::Pipeline::SanitizationFilter - UNSAFE_PROTOCOLS = %w(javascript :javascript data vbscript).freeze + UNSAFE_PROTOCOLS = %w(data javascript vbscript).freeze def whitelist whitelist = super @@ -64,7 +64,12 @@ module Banzai return unless node.name == 'a' return unless node.has_attribute?('href') - if node['href'].start_with?(*UNSAFE_PROTOCOLS) + begin + uri = Addressable::URI.parse(node['href']) + uri.scheme.strip! if uri.scheme + + node.remove_attribute('href') if UNSAFE_PROTOCOLS.include?(uri.scheme) + rescue Addressable::URI::InvalidURIError node.remove_attribute('href') end end diff --git a/spec/lib/banzai/filter/sanitization_filter_spec.rb b/spec/lib/banzai/filter/sanitization_filter_spec.rb index 4a7b00c7660..27ce312b11c 100644 --- a/spec/lib/banzai/filter/sanitization_filter_spec.rb +++ b/spec/lib/banzai/filter/sanitization_filter_spec.rb @@ -149,10 +149,20 @@ describe Banzai::Filter::SanitizationFilter, lib: true do output: '<a href="java"></a>' }, + 'protocol-based JS injection: invalid URL char' => { + input: '<img src=java\script:alert("XSS")>', + output: '<img>' + }, + 'protocol-based JS injection: spaces and entities' => { input: '<a href="  javascript:alert(\'XSS\');">foo</a>', output: '<a href="">foo</a>' }, + + 'protocol whitespace' => { + input: '<a href=" http://example.com/"></a>', + output: '<a href="http://example.com/"></a>' + } } protocols.each do |name, data| @@ -177,6 +187,16 @@ describe Banzai::Filter::SanitizationFilter, lib: true do expect(output.to_html).to eq '<a>XSS</a>' end + it 'disallows invalid URIs' do + expect(Addressable::URI).to receive(:parse).with('foo://example.com'). + and_raise(Addressable::URI::InvalidURIError) + + input = '<a href="foo://example.com">Foo</a>' + output = filter(input) + + expect(output.to_html).to eq '<a>Foo</a>' + end + it 'allows non-standard anchor schemes' do exp = %q{<a href="irc://irc.freenode.net/git">IRC</a>} act = filter(exp) |