Skip to content

Commit dca7650

Browse files
committed
fix: sanitize fields when rendering pact html
1 parent 2a0fbc7 commit dca7650

File tree

5 files changed

+61
-10
lines changed

5 files changed

+61
-10
lines changed

lib/pact/doc/markdown/consumer_contract_renderer.rb

+9-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
require 'pact/doc/markdown/interaction_renderer'
22
require 'pact/doc/sort_interactions'
3+
require 'rack/utils'
34

45
module Pact
56
module Doc
@@ -15,7 +16,7 @@ def self.call consumer_contract
1516
end
1617

1718
def call
18-
title + summaries_title + summaries.join + interactions_title + full_interactions.join
19+
title + summaries_title + summaries + interactions_title + full_interactions
1920
end
2021

2122
private
@@ -39,29 +40,32 @@ def interactions_title
3940
end
4041

4142
def summaries
42-
interaction_renderers.collect(&:render_summary)
43+
interaction_renderers.collect(&:render_summary).join
4344
end
4445

4546
def full_interactions
46-
interaction_renderers.collect(&:render_full_interaction)
47+
interaction_renderers.collect(&:render_full_interaction).join
4748
end
4849

4950
def sorted_interactions
5051
SortInteractions.call(consumer_contract.interactions)
5152
end
5253

5354
def consumer_name
54-
markdown_escape consumer_contract.consumer.name
55+
h(markdown_escape consumer_contract.consumer.name)
5556
end
5657

5758
def provider_name
58-
markdown_escape consumer_contract.provider.name
59+
h(markdown_escape consumer_contract.provider.name)
5960
end
6061

6162
def markdown_escape string
6263
string.gsub('*','\*').gsub('_','\_')
6364
end
6465

66+
def h(text)
67+
Rack::Utils.escape_html(text)
68+
end
6569
end
6670
end
6771
end

lib/pact/doc/markdown/interaction.erb

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
<a name="<%= interaction.id %>"></a>
22
<%= if interaction.has_provider_state?
3-
"Given **#{interaction.provider_state}**, upon receiving"
3+
"Given **#{h(interaction.provider_state)}**, upon receiving"
44
else
55
"Upon receiving"
66
end
7-
%> **<%= interaction.description %>** from <%= interaction.consumer_name %>, with
7+
%> **<%= h(interaction.description) %>** from <%= h(interaction.consumer_name) %>, with
88
```json
99
<%= interaction.request %>
1010
```
11-
<%= interaction.provider_name %> will respond with:
11+
<%= h(interaction.provider_name) %> will respond with:
1212
```json
1313
<%= interaction.response %>
1414
```

lib/pact/doc/markdown/interaction_renderer.rb

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
require 'erb'
22
require 'pact/doc/interaction_view_model'
3+
require 'rack/utils'
34

45
module Pact
56
module Doc
@@ -12,8 +13,8 @@ def initialize interaction, pact
1213
end
1314

1415
def render_summary
15-
suffix = interaction.has_provider_state? ? " given #{interaction.provider_state}" : ""
16-
"* [#{interaction.description(true)}](##{interaction.id})#{suffix}\n\n"
16+
suffix = interaction.has_provider_state? ? " given #{h(interaction.provider_state)}" : ""
17+
"* [#{h(interaction.description(true))}](##{interaction.id})#{suffix}\n\n"
1718
end
1819

1920
def render_full_interaction
@@ -36,6 +37,9 @@ def template_contents(template_file)
3637
File.dirname(__FILE__) + template_file
3738
end
3839

40+
def h(text)
41+
Rack::Utils.escape_html(text)
42+
end
3943
end
4044
end
4145
end

spec/lib/pact/doc/markdown/consumer_contract_renderer_spec.rb

+16
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,22 @@ module Markdown
3939
it "renders the interactions" do
4040
expect(subject.call).to eq(expected_output)
4141
end
42+
43+
context "when the pact fields have html embedded in them" do
44+
let(:consumer_contract) { Pact::ConsumerContract.from_uri './spec/support/markdown_pact_with_html.json' }
45+
46+
its(:title) { is_expected.to include "&lt;h1&gt;Consumer&lt;&#x2F;h1&gt;" }
47+
its(:title) { is_expected.to include "&lt;h1&gt;Provider&lt;&#x2F;h1&gt;" }
48+
49+
its(:summaries_title) { is_expected.to include "&lt;h1&gt;Consumer&lt;&#x2F;h1&gt;" }
50+
its(:summaries_title) { is_expected.to include "&lt;h1&gt;Provider&lt;&#x2F;h1&gt;" }
51+
52+
its(:summaries) { is_expected.to include "&lt;h1&gt;alligators&lt;/h1&gt;" }
53+
its(:summaries) { is_expected.to_not include "<h1>alligators</h1>" }
54+
55+
its(:full_interactions) { is_expected.to include "&lt;h1&gt;alligators&lt;/h1&gt;" }
56+
its(:full_interactions) { is_expected.to_not include "<h1>alligators</h1>" }
57+
end
4258
end
4359

4460
end
+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"provider": {
3+
"name": "Some <h1>Provider</h1>"
4+
},
5+
"consumer": {
6+
"name": "Some <h1>Consumer</h1>"
7+
},
8+
"interactions": [
9+
{
10+
"description": "a request for <h1>alligators</h1> in France",
11+
"provider_state": "<h1>alligators</h1> exist",
12+
"request": {
13+
"method": "get",
14+
"path": "/alligators"
15+
},
16+
"response": {
17+
"headers" : {"Content-Type": "application/json"},
18+
"status" : 200,
19+
"body" : {
20+
"alligators": [{
21+
"name": "Bob"
22+
}]
23+
}
24+
}
25+
}
26+
]
27+
}

0 commit comments

Comments
 (0)