diff --git a/app/models/enterprise.rb b/app/models/enterprise.rb index dd5a63a5fc..fdad5f4814 100644 --- a/app/models/enterprise.rb +++ b/app/models/enterprise.rb @@ -247,6 +247,11 @@ class Enterprise < ApplicationRecord count(distinct: true) end + # Remove any unsupported HTML. + def long_description=(html) + super(HtmlSanitizer.sanitize(html)) + end + def contact contact = users.where(enterprise_roles: { receives_notifications: true }).first contact || owner diff --git a/app/services/html_sanitizer.rb b/app/services/html_sanitizer.rb new file mode 100644 index 0000000000..4f2e44e0ab --- /dev/null +++ b/app/services/html_sanitizer.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +# Keeps only allowed HTML. +# +# We store some rich text as HTML in attributes of models like Enterprise. +# We offer an editor which supports certain tags but you can't insert just any +# HTML, which would be dangerous. +class HtmlSanitizer + def self.sanitize(html) + @sanitizer ||= Rails::HTML5::SafeListSanitizer.new + @sanitizer.sanitize( + html, tags: %w[h1 h2 h3 h4 p b i u a], attributes: %w[href target], + ) + end +end diff --git a/spec/models/enterprise_spec.rb b/spec/models/enterprise_spec.rb index 300dd84ccb..b853031c23 100644 --- a/spec/models/enterprise_spec.rb +++ b/spec/models/enterprise_spec.rb @@ -398,6 +398,13 @@ RSpec.describe Enterprise do end end + describe "serialisation" do + it "sanitises HTML in long_description" do + subject.long_description = "Hello dearest monster." + expect(subject.long_description).to eq "Hello alert dearest monster." + end + end + describe "callbacks" do it "restores permalink to original value when it is changed and invalid" do e1 = create(:enterprise, permalink: "taken") diff --git a/spec/services/html_sanitizer_spec.rb b/spec/services/html_sanitizer_spec.rb new file mode 100644 index 0000000000..7f238ab733 --- /dev/null +++ b/spec/services/html_sanitizer_spec.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe HtmlSanitizer do + subject { described_class } + + it "removes dangerous tags" do + html = "Hello !" + expect(subject.sanitize(html)) + .to eq "Hello alert!" + end + + it "keeps supported tags" do + html = "Hello alert!" + expect(subject.sanitize(html)) + .to eq "Hello alert!" + end + + it "keeps supported attributes" do + html = 'Hello alert!' + expect(subject.sanitize(html)) + .to eq 'Hello alert!' + end + + it "removes unsupported attributes" do + html = 'Hello alert!' + expect(subject.sanitize(html)) + .to eq 'Hello alert!' + end + + it "removes dangerous attribute values" do + html = 'Hello you!' + expect(subject.sanitize(html)) + .to eq 'Hello you!' + end +end