From dca76506c512ab92caee4b75e5f1c36987c94459 Mon Sep 17 00:00:00 2001 From: Beth Skurrie Date: Mon, 1 Apr 2019 15:32:17 +1100 Subject: [PATCH] fix: sanitize fields when rendering pact html --- .../markdown/consumer_contract_renderer.rb | 14 ++++++---- lib/pact/doc/markdown/interaction.erb | 6 ++--- lib/pact/doc/markdown/interaction_renderer.rb | 8 ++++-- .../consumer_contract_renderer_spec.rb | 16 +++++++++++ spec/support/markdown_pact_with_html.json | 27 +++++++++++++++++++ 5 files changed, 61 insertions(+), 10 deletions(-) create mode 100644 spec/support/markdown_pact_with_html.json diff --git a/lib/pact/doc/markdown/consumer_contract_renderer.rb b/lib/pact/doc/markdown/consumer_contract_renderer.rb index ca35f272b..34adc85b9 100644 --- a/lib/pact/doc/markdown/consumer_contract_renderer.rb +++ b/lib/pact/doc/markdown/consumer_contract_renderer.rb @@ -1,5 +1,6 @@ require 'pact/doc/markdown/interaction_renderer' require 'pact/doc/sort_interactions' +require 'rack/utils' module Pact module Doc @@ -15,7 +16,7 @@ def self.call consumer_contract end def call - title + summaries_title + summaries.join + interactions_title + full_interactions.join + title + summaries_title + summaries + interactions_title + full_interactions end private @@ -39,11 +40,11 @@ def interactions_title end def summaries - interaction_renderers.collect(&:render_summary) + interaction_renderers.collect(&:render_summary).join end def full_interactions - interaction_renderers.collect(&:render_full_interaction) + interaction_renderers.collect(&:render_full_interaction).join end def sorted_interactions @@ -51,17 +52,20 @@ def sorted_interactions end def consumer_name - markdown_escape consumer_contract.consumer.name + h(markdown_escape consumer_contract.consumer.name) end def provider_name - markdown_escape consumer_contract.provider.name + h(markdown_escape consumer_contract.provider.name) end def markdown_escape string string.gsub('*','\*').gsub('_','\_') end + def h(text) + Rack::Utils.escape_html(text) + end end end end diff --git a/lib/pact/doc/markdown/interaction.erb b/lib/pact/doc/markdown/interaction.erb index 41dcd9ee4..ae2877a93 100644 --- a/lib/pact/doc/markdown/interaction.erb +++ b/lib/pact/doc/markdown/interaction.erb @@ -1,14 +1,14 @@ <%= if interaction.has_provider_state? - "Given **#{interaction.provider_state}**, upon receiving" + "Given **#{h(interaction.provider_state)}**, upon receiving" else "Upon receiving" end -%> **<%= interaction.description %>** from <%= interaction.consumer_name %>, with +%> **<%= h(interaction.description) %>** from <%= h(interaction.consumer_name) %>, with ```json <%= interaction.request %> ``` -<%= interaction.provider_name %> will respond with: +<%= h(interaction.provider_name) %> will respond with: ```json <%= interaction.response %> ``` diff --git a/lib/pact/doc/markdown/interaction_renderer.rb b/lib/pact/doc/markdown/interaction_renderer.rb index bf95983fa..e721ba70a 100644 --- a/lib/pact/doc/markdown/interaction_renderer.rb +++ b/lib/pact/doc/markdown/interaction_renderer.rb @@ -1,5 +1,6 @@ require 'erb' require 'pact/doc/interaction_view_model' +require 'rack/utils' module Pact module Doc @@ -12,8 +13,8 @@ def initialize interaction, pact end def render_summary - suffix = interaction.has_provider_state? ? " given #{interaction.provider_state}" : "" - "* [#{interaction.description(true)}](##{interaction.id})#{suffix}\n\n" + suffix = interaction.has_provider_state? ? " given #{h(interaction.provider_state)}" : "" + "* [#{h(interaction.description(true))}](##{interaction.id})#{suffix}\n\n" end def render_full_interaction @@ -36,6 +37,9 @@ def template_contents(template_file) File.dirname(__FILE__) + template_file end + def h(text) + Rack::Utils.escape_html(text) + end end end end diff --git a/spec/lib/pact/doc/markdown/consumer_contract_renderer_spec.rb b/spec/lib/pact/doc/markdown/consumer_contract_renderer_spec.rb index 9ff6a309c..e72ab8939 100644 --- a/spec/lib/pact/doc/markdown/consumer_contract_renderer_spec.rb +++ b/spec/lib/pact/doc/markdown/consumer_contract_renderer_spec.rb @@ -39,6 +39,22 @@ module Markdown it "renders the interactions" do expect(subject.call).to eq(expected_output) end + + context "when the pact fields have html embedded in them" do + let(:consumer_contract) { Pact::ConsumerContract.from_uri './spec/support/markdown_pact_with_html.json' } + + its(:title) { is_expected.to include "<h1>Consumer</h1>" } + its(:title) { is_expected.to include "<h1>Provider</h1>" } + + its(:summaries_title) { is_expected.to include "<h1>Consumer</h1>" } + its(:summaries_title) { is_expected.to include "<h1>Provider</h1>" } + + its(:summaries) { is_expected.to include "<h1>alligators</h1>" } + its(:summaries) { is_expected.to_not include "

alligators

" } + + its(:full_interactions) { is_expected.to include "<h1>alligators</h1>" } + its(:full_interactions) { is_expected.to_not include "

alligators

" } + end end end diff --git a/spec/support/markdown_pact_with_html.json b/spec/support/markdown_pact_with_html.json new file mode 100644 index 000000000..8dbafbf84 --- /dev/null +++ b/spec/support/markdown_pact_with_html.json @@ -0,0 +1,27 @@ +{ + "provider": { + "name": "Some

Provider

" + }, + "consumer": { + "name": "Some

Consumer

" + }, + "interactions": [ + { + "description": "a request for

alligators

in France", + "provider_state": "

alligators

exist", + "request": { + "method": "get", + "path": "/alligators" + }, + "response": { + "headers" : {"Content-Type": "application/json"}, + "status" : 200, + "body" : { + "alligators": [{ + "name": "Bob" + }] + } + } + } + ] +}