diff --git a/.rubocop.yml b/.rubocop.yml index e3462a7..8837aa4 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -11,3 +11,5 @@ Style/StringLiteralsInInterpolation: Layout/LineLength: Max: 120 +Metrics/MethodLength: + Max: 12 diff --git a/Gemfile.lock b/Gemfile.lock index 9808832..460a2f6 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - jekyll-kroki (0.1.0) + jekyll-kroki (0.2.0) faraday (~> 2.7) faraday-retry (~> 2.2) jekyll (~> 4) @@ -64,7 +64,7 @@ GEM rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) mercenary (0.4.0) - minitest (5.14.2) + minitest (5.20.0) nokogiri (1.15.4-x86_64-linux) racc (~> 1.4) parallel (1.23.0) diff --git a/README.md b/README.md index aa43d11..a1ddd04 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,16 @@ jekyll-kroki: This is useful if you want to run a Kroki instance locally or your organisation maintains its own private Kroki server. `jekyll-kroki` will use the public Kroki instance https://kroki.io by default if a URL is not specified. +### Security + +Embedding diagrams as SVGs directly within HTML files can be dangerous. You should only use a Kroki instance that you trust (or run your own!). For additional security, you can configure a [Content Security Policy (CSP)](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) using custom Webrick headers in the Jekyll `_config.yml` file: + +```yaml +webrick: + headers: + Content-Security-Policy: "Add a policy here" +``` + ## Contributing Bug reports and pull requests are welcome! For major changes, please open an issue first to discuss what you would like to change. diff --git a/lib/jekyll/kroki.rb b/lib/jekyll/kroki.rb index 917671e..02d3392 100644 --- a/lib/jekyll/kroki.rb +++ b/lib/jekyll/kroki.rb @@ -59,12 +59,29 @@ def embed_page(connection, parsed_doc) # @return [String] The rendered diagram in SVG format def render_diagram(connection, diagram_desc, language) begin - encoded_diagram = encode_diagram(diagram_desc.text) - response = connection.get("#{language}/svg/#{encoded_diagram}") + response = connection.get("#{language}/svg/#{encode_diagram(diagram_desc.text)}") rescue Faraday::Error => e raise e.response[:body] end - response.body + expected_content_type = "image/svg+xml" + returned_content_type = response.headers[:content_type] + if returned_content_type != expected_content_type + raise "Kroki returned an incorrect content type: " \ + "expected '#{expected_content_type}', received '#{returned_content_type}'" + + end + sanitise_diagram(response.body) + end + + # Sanitises a rendered diagram. Only