grover 1.1.8 → 1.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7bfcdc3d84dade94866bbb29eca6c1e91b9459a5f020ebd175341f740dfdd585
4
- data.tar.gz: 539a10195c08de66249983fccdf3f5314f1adec83b400d6058f87d127e731f86
3
+ metadata.gz: 82b9a3edaa4f0d20c326f3e79d61b1d2a0190454ac9ffb6867191a9607ec1ea0
4
+ data.tar.gz: 4e71234c41bf19c88a5b44c0a043a1c2ae5a74f94d0606fb0cd627c02e8511a2
5
5
  SHA512:
6
- metadata.gz: 6322c7cd633f776d58bb2fcad105d067a3df4782dcbc2fb15aff4fe60dcc2e8e1a58075e4972bb9f65362075eebe973e51f8aa385bd651d89ad41078e00fd4ca
7
- data.tar.gz: e9431f9a613f4b40f5d836616ad2e8afd6470a606a8daf80ad5553e248a461035228c62e290f0778e742aa2f2a9b663fe23f0590600cdda592cd8a26339ba391
6
+ metadata.gz: 737079399ecd8ef4c6a88c535495a2aa52fcb9e2e8fa0ca171d3453b58134d795237e606487a9f3dd06afad73baac8fac834a76a33445a1099e168f929f13835
7
+ data.tar.gz: 767e6ebf33ce60336d9afd71859e004b54765910136387ed81b44a12489de7728ff88d0b5f33890dea45314a58476972d31a1f3e9e5e7834f6d68979acf0eb19
@@ -7,7 +7,7 @@ class Grover
7
7
  class Configuration
8
8
  attr_accessor :options, :meta_tag_prefix, :ignore_path, :ignore_request,
9
9
  :root_url, :use_pdf_middleware, :use_png_middleware,
10
- :use_jpeg_middleware, :node_env_vars
10
+ :use_jpeg_middleware, :node_env_vars, :allow_file_uris
11
11
 
12
12
  def initialize
13
13
  @options = {}
@@ -19,6 +19,7 @@ class Grover
19
19
  @use_png_middleware = false
20
20
  @use_jpeg_middleware = false
21
21
  @node_env_vars = {}
22
+ @allow_file_uris = false
22
23
  end
23
24
  end
24
25
  end
data/lib/grover/errors.rb CHANGED
@@ -15,4 +15,5 @@ class Grover
15
15
  const_set name, Class.new(Error)
16
16
  end
17
17
  end
18
+ UnsafeConfigurationError = Class.new(Error)
18
19
  end
@@ -26,7 +26,7 @@ const fs = require('fs');
26
26
  const os = require('os');
27
27
  const path = require('path');
28
28
 
29
- const _processPage = (async (convertAction, urlOrHtml, options) => {
29
+ const _processPage = (async (convertAction, uriOrHtml, options) => {
30
30
  let browser, page, errors = [], tmpDir, wsConnection = false;
31
31
 
32
32
  try {
@@ -173,10 +173,12 @@ const _processPage = (async (convertAction, urlOrHtml, options) => {
173
173
  }
174
174
 
175
175
  const waitUntil = options.waitUntil; delete options.waitUntil;
176
- if (urlOrHtml.match(/^http/i)) {
176
+ const allowFileUri = options.allowFileUri; delete options.allowFileUri;
177
+ const uriRegex = allowFileUri ? /^(https?|file):\/\//i : /^https?:\/\//i;
178
+ if (uriOrHtml.match(uriRegex)) {
177
179
  // Request is for a URL, so request it
178
180
  requestOptions.waitUntil = waitUntil || 'networkidle2';
179
- await page.goto(urlOrHtml, requestOptions);
181
+ await page.goto(uriOrHtml, requestOptions);
180
182
  } else {
181
183
  // Request is some HTML content. Use request interception to assign the body
182
184
  requestOptions.waitUntil = waitUntil || 'networkidle0';
@@ -188,7 +190,7 @@ const _processPage = (async (convertAction, urlOrHtml, options) => {
188
190
  request.continue();
189
191
  else {
190
192
  htmlIntercepted = true
191
- request.respond({ body: urlOrHtml === '' ? ' ' : urlOrHtml });
193
+ request.respond({ body: uriOrHtml === '' ? ' ' : uriOrHtml });
192
194
  }
193
195
  });
194
196
  const displayUrl = options.displayUrl; delete options.displayUrl;
@@ -24,11 +24,14 @@ class Grover
24
24
  dup._call(env)
25
25
  end
26
26
 
27
- def _call(env)
27
+ def _call(env) # rubocop:disable Metrics/MethodLength
28
28
  @request = Rack::Request.new(env)
29
29
  identify_request_type
30
30
 
31
- configure_env_for_grover_request(env) if grover_request?
31
+ if grover_request?
32
+ check_file_uri_configuration
33
+ configure_env_for_grover_request(env)
34
+ end
32
35
  status, headers, response = @app.call(env)
33
36
  response = update_response response, headers if grover_request? && html_content?(headers)
34
37
 
@@ -45,6 +48,14 @@ class Grover
45
48
 
46
49
  attr_reader :pdf_request, :png_request, :jpeg_request
47
50
 
51
+ def check_file_uri_configuration
52
+ return unless Grover.configuration.allow_file_uris
53
+
54
+ # The combination of middleware and allowing file URLs is exceptionally
55
+ # unsafe as it can lead to data exfiltration from the host system.
56
+ raise UnsafeConfigurationError, 'using `allow_file_uris` configuration with middleware is exceptionally unsafe'
57
+ end
58
+
48
59
  def identify_request_type
49
60
  @pdf_request = Grover.configuration.use_pdf_middleware && path_matches?(PDF_REGEX)
50
61
  @png_request = Grover.configuration.use_png_middleware && path_matches?(PNG_REGEX)
@@ -8,12 +8,12 @@ class Grover
8
8
  # Build options from Grover.configuration, meta_options, and passed-in options
9
9
  #
10
10
  class OptionsBuilder < Hash
11
- def initialize(options, url)
11
+ def initialize(options, uri)
12
12
  super()
13
- @url = url
13
+ @uri = uri
14
14
  combined = grover_configuration
15
15
  Utils.deep_merge! combined, Utils.deep_stringify_keys(options)
16
- Utils.deep_merge! combined, meta_options unless url_source?
16
+ Utils.deep_merge! combined, meta_options unless uri_source?
17
17
 
18
18
  update OptionsFixer.new(combined).run
19
19
  end
@@ -41,11 +41,11 @@ class Grover
41
41
  end
42
42
 
43
43
  def meta_tags
44
- Nokogiri::HTML(@url).xpath('//meta')
44
+ Nokogiri::HTML(@uri).xpath('//meta')
45
45
  end
46
46
 
47
- def url_source?
48
- @url.match(/\Ahttp/i)
47
+ def uri_source?
48
+ @uri.match?(%r{\A(https?|file)://}i)
49
49
  end
50
50
  end
51
51
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Grover
4
- VERSION = '1.1.8'
4
+ VERSION = '1.1.9'
5
5
  end
data/lib/grover.rb CHANGED
@@ -28,40 +28,40 @@ class Grover
28
28
  attr_reader :front_cover_path, :back_cover_path
29
29
 
30
30
  #
31
- # @param [String] url URL of the page to convert
31
+ # @param [String] uri URI of the page to convert
32
32
  # @param [Hash] options Optional parameters to pass to PDF processor
33
33
  # see https://github.com/puppeteer/puppeteer/blob/main/docs/api/puppeteer.pdfoptions.md
34
34
  # and https://github.com/puppeteer/puppeteer/blob/main/docs/api/puppeteer.screenshotoptions.md
35
35
  #
36
- def initialize(url, **options)
37
- @url = url.to_s
38
- @options = OptionsBuilder.new(options, @url)
36
+ def initialize(uri, **options)
37
+ @uri = uri.to_s
38
+ @options = OptionsBuilder.new(options, @uri)
39
39
  @root_path = @options.delete 'root_path'
40
40
  @front_cover_path = @options.delete 'front_cover_path'
41
41
  @back_cover_path = @options.delete 'back_cover_path'
42
42
  end
43
43
 
44
44
  #
45
- # Request URL with provided options and create PDF
45
+ # Request URI with provided options and create PDF
46
46
  #
47
47
  # @param [String] path Optional path to write the PDF to
48
48
  # @return [String] The resulting PDF data
49
49
  #
50
50
  def to_pdf(path = nil)
51
- processor.convert :pdf, @url, normalized_options(path: path)
51
+ processor.convert :pdf, @uri, normalized_options(path: path)
52
52
  end
53
53
 
54
54
  #
55
- # Request URL with provided options and render HTML
55
+ # Request URI with provided options and render HTML
56
56
  #
57
57
  # @return [String] The resulting HTML string
58
58
  #
59
59
  def to_html
60
- processor.convert :content, @url, normalized_options(path: nil)
60
+ processor.convert :content, @uri, normalized_options(path: nil)
61
61
  end
62
62
 
63
63
  #
64
- # Request URL with provided options and create screenshot
64
+ # Request URI with provided options and create screenshot
65
65
  #
66
66
  # @param [String] path Optional path to write the screenshot to
67
67
  # @param [String] format Optional format of the screenshot
@@ -70,11 +70,11 @@ class Grover
70
70
  def screenshot(path: nil, format: nil)
71
71
  options = normalized_options(path: path)
72
72
  options['type'] = format if %w[png jpeg].include? format
73
- processor.convert :screenshot, @url, options
73
+ processor.convert :screenshot, @uri, options
74
74
  end
75
75
 
76
76
  #
77
- # Request URL with provided options and create PNG
77
+ # Request URI with provided options and create PNG
78
78
  #
79
79
  # @param [String] path Optional path to write the screenshot to
80
80
  # @return [String] The resulting PNG data
@@ -84,7 +84,7 @@ class Grover
84
84
  end
85
85
 
86
86
  #
87
- # Request URL with provided options and create JPEG
87
+ # Request URI with provided options and create JPEG
88
88
  #
89
89
  # @param [String] path Optional path to write the screenshot to
90
90
  # @return [String] The resulting JPEG data
@@ -116,10 +116,10 @@ class Grover
116
116
  #
117
117
  def inspect
118
118
  format(
119
- '#<%<class_name>s:0x%<object_id>p @url="%<url>s">',
119
+ '#<%<class_name>s:0x%<object_id>p @uri="%<uri>s">',
120
120
  class_name: self.class.name,
121
121
  object_id: object_id,
122
- url: @url
122
+ uri: @uri
123
123
  )
124
124
  end
125
125
 
@@ -147,6 +147,7 @@ class Grover
147
147
  def normalized_options(path:)
148
148
  normalized_options = Utils.normalize_object @options, excluding: ['extraHTTPHeaders']
149
149
  normalized_options['path'] = path if path.is_a? ::String
150
+ normalized_options['allowFileUri'] = Grover.configuration.allow_file_uris == true
150
151
  normalized_options
151
152
  end
152
153
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: grover
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.8
4
+ version: 1.1.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Bromwich
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-06-23 00:00:00.000000000 Z
11
+ date: 2024-07-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: combine_pdf