grover 1.1.7 → 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 +4 -4
- data/lib/grover/configuration.rb +3 -1
- data/lib/grover/errors.rb +1 -0
- data/lib/grover/js/processor.cjs +7 -4
- data/lib/grover/middleware.rb +13 -2
- data/lib/grover/options_builder.rb +6 -6
- data/lib/grover/processor.rb +1 -0
- data/lib/grover/version.rb +1 -1
- data/lib/grover.rb +15 -14
- metadata +2 -176
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 82b9a3edaa4f0d20c326f3e79d61b1d2a0190454ac9ffb6867191a9607ec1ea0
|
4
|
+
data.tar.gz: 4e71234c41bf19c88a5b44c0a043a1c2ae5a74f94d0606fb0cd627c02e8511a2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 737079399ecd8ef4c6a88c535495a2aa52fcb9e2e8fa0ca171d3453b58134d795237e606487a9f3dd06afad73baac8fac834a76a33445a1099e168f929f13835
|
7
|
+
data.tar.gz: 767e6ebf33ce60336d9afd71859e004b54765910136387ed81b44a12489de7728ff88d0b5f33890dea45314a58476972d31a1f3e9e5e7834f6d68979acf0eb19
|
data/lib/grover/configuration.rb
CHANGED
@@ -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
|
10
|
+
:use_jpeg_middleware, :node_env_vars, :allow_file_uris
|
11
11
|
|
12
12
|
def initialize
|
13
13
|
@options = {}
|
@@ -18,6 +18,8 @@ class Grover
|
|
18
18
|
@use_pdf_middleware = true
|
19
19
|
@use_png_middleware = false
|
20
20
|
@use_jpeg_middleware = false
|
21
|
+
@node_env_vars = {}
|
22
|
+
@allow_file_uris = false
|
21
23
|
end
|
22
24
|
end
|
23
25
|
end
|
data/lib/grover/errors.rb
CHANGED
data/lib/grover/js/processor.cjs
CHANGED
@@ -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,
|
29
|
+
const _processPage = (async (convertAction, uriOrHtml, options) => {
|
30
30
|
let browser, page, errors = [], tmpDir, wsConnection = false;
|
31
31
|
|
32
32
|
try {
|
@@ -100,6 +100,7 @@ const _processPage = (async (convertAction, urlOrHtml, options) => {
|
|
100
100
|
}
|
101
101
|
|
102
102
|
// Setup timeout option (if provided)
|
103
|
+
if (options.timeout === null) delete options.timeout;
|
103
104
|
let requestOptions = {};
|
104
105
|
let requestTimeout = options.requestTimeout; delete options.requestTimeout;
|
105
106
|
if (requestTimeout === undefined) requestTimeout = options.timeout;
|
@@ -172,10 +173,12 @@ const _processPage = (async (convertAction, urlOrHtml, options) => {
|
|
172
173
|
}
|
173
174
|
|
174
175
|
const waitUntil = options.waitUntil; delete options.waitUntil;
|
175
|
-
|
176
|
+
const allowFileUri = options.allowFileUri; delete options.allowFileUri;
|
177
|
+
const uriRegex = allowFileUri ? /^(https?|file):\/\//i : /^https?:\/\//i;
|
178
|
+
if (uriOrHtml.match(uriRegex)) {
|
176
179
|
// Request is for a URL, so request it
|
177
180
|
requestOptions.waitUntil = waitUntil || 'networkidle2';
|
178
|
-
await page.goto(
|
181
|
+
await page.goto(uriOrHtml, requestOptions);
|
179
182
|
} else {
|
180
183
|
// Request is some HTML content. Use request interception to assign the body
|
181
184
|
requestOptions.waitUntil = waitUntil || 'networkidle0';
|
@@ -187,7 +190,7 @@ const _processPage = (async (convertAction, urlOrHtml, options) => {
|
|
187
190
|
request.continue();
|
188
191
|
else {
|
189
192
|
htmlIntercepted = true
|
190
|
-
request.respond({ body:
|
193
|
+
request.respond({ body: uriOrHtml === '' ? ' ' : uriOrHtml });
|
191
194
|
}
|
192
195
|
});
|
193
196
|
const displayUrl = options.displayUrl; delete options.displayUrl;
|
data/lib/grover/middleware.rb
CHANGED
@@ -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
|
-
|
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,
|
11
|
+
def initialize(options, uri)
|
12
12
|
super()
|
13
|
-
@
|
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
|
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(@
|
44
|
+
Nokogiri::HTML(@uri).xpath('//meta')
|
45
45
|
end
|
46
46
|
|
47
|
-
def
|
48
|
-
@
|
47
|
+
def uri_source?
|
48
|
+
@uri.match?(%r{\A(https?|file)://}i)
|
49
49
|
end
|
50
50
|
end
|
51
51
|
end
|
data/lib/grover/processor.rb
CHANGED
data/lib/grover/version.rb
CHANGED
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]
|
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(
|
37
|
-
@
|
38
|
-
@options = OptionsBuilder.new(options, @
|
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
|
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, @
|
51
|
+
processor.convert :pdf, @uri, normalized_options(path: path)
|
52
52
|
end
|
53
53
|
|
54
54
|
#
|
55
|
-
# Request
|
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, @
|
60
|
+
processor.convert :content, @uri, normalized_options(path: nil)
|
61
61
|
end
|
62
62
|
|
63
63
|
#
|
64
|
-
# Request
|
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, @
|
73
|
+
processor.convert :screenshot, @uri, options
|
74
74
|
end
|
75
75
|
|
76
76
|
#
|
77
|
-
# Request
|
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
|
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 @
|
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
|
-
|
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.
|
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-
|
11
|
+
date: 2024-07-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: combine_pdf
|
@@ -38,180 +38,6 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '1.0'
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: childprocess
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - ">="
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '0'
|
48
|
-
type: :development
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - ">="
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '0'
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: mini_magick
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - "~>"
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '4.12'
|
62
|
-
type: :development
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - "~>"
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: '4.12'
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
name: pdf-reader
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
72
|
-
requirements:
|
73
|
-
- - "~>"
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
version: '2.11'
|
76
|
-
type: :development
|
77
|
-
prerelease: false
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
79
|
-
requirements:
|
80
|
-
- - "~>"
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
version: '2.11'
|
83
|
-
- !ruby/object:Gem::Dependency
|
84
|
-
name: puma
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
86
|
-
requirements:
|
87
|
-
- - "~>"
|
88
|
-
- !ruby/object:Gem::Version
|
89
|
-
version: '6.4'
|
90
|
-
type: :development
|
91
|
-
prerelease: false
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
93
|
-
requirements:
|
94
|
-
- - "~>"
|
95
|
-
- !ruby/object:Gem::Version
|
96
|
-
version: '6.4'
|
97
|
-
- !ruby/object:Gem::Dependency
|
98
|
-
name: rack-test
|
99
|
-
requirement: !ruby/object:Gem::Requirement
|
100
|
-
requirements:
|
101
|
-
- - "~>"
|
102
|
-
- !ruby/object:Gem::Version
|
103
|
-
version: '1.1'
|
104
|
-
type: :development
|
105
|
-
prerelease: false
|
106
|
-
version_requirements: !ruby/object:Gem::Requirement
|
107
|
-
requirements:
|
108
|
-
- - "~>"
|
109
|
-
- !ruby/object:Gem::Version
|
110
|
-
version: '1.1'
|
111
|
-
- !ruby/object:Gem::Dependency
|
112
|
-
name: rake
|
113
|
-
requirement: !ruby/object:Gem::Requirement
|
114
|
-
requirements:
|
115
|
-
- - "~>"
|
116
|
-
- !ruby/object:Gem::Version
|
117
|
-
version: '13.0'
|
118
|
-
type: :development
|
119
|
-
prerelease: false
|
120
|
-
version_requirements: !ruby/object:Gem::Requirement
|
121
|
-
requirements:
|
122
|
-
- - "~>"
|
123
|
-
- !ruby/object:Gem::Version
|
124
|
-
version: '13.0'
|
125
|
-
- !ruby/object:Gem::Dependency
|
126
|
-
name: rspec
|
127
|
-
requirement: !ruby/object:Gem::Requirement
|
128
|
-
requirements:
|
129
|
-
- - "~>"
|
130
|
-
- !ruby/object:Gem::Version
|
131
|
-
version: '3.12'
|
132
|
-
type: :development
|
133
|
-
prerelease: false
|
134
|
-
version_requirements: !ruby/object:Gem::Requirement
|
135
|
-
requirements:
|
136
|
-
- - "~>"
|
137
|
-
- !ruby/object:Gem::Version
|
138
|
-
version: '3.12'
|
139
|
-
- !ruby/object:Gem::Dependency
|
140
|
-
name: rubocop
|
141
|
-
requirement: !ruby/object:Gem::Requirement
|
142
|
-
requirements:
|
143
|
-
- - "~>"
|
144
|
-
- !ruby/object:Gem::Version
|
145
|
-
version: '1.43'
|
146
|
-
type: :development
|
147
|
-
prerelease: false
|
148
|
-
version_requirements: !ruby/object:Gem::Requirement
|
149
|
-
requirements:
|
150
|
-
- - "~>"
|
151
|
-
- !ruby/object:Gem::Version
|
152
|
-
version: '1.43'
|
153
|
-
- !ruby/object:Gem::Dependency
|
154
|
-
name: rubocop-rake
|
155
|
-
requirement: !ruby/object:Gem::Requirement
|
156
|
-
requirements:
|
157
|
-
- - "~>"
|
158
|
-
- !ruby/object:Gem::Version
|
159
|
-
version: '0.6'
|
160
|
-
type: :development
|
161
|
-
prerelease: false
|
162
|
-
version_requirements: !ruby/object:Gem::Requirement
|
163
|
-
requirements:
|
164
|
-
- - "~>"
|
165
|
-
- !ruby/object:Gem::Version
|
166
|
-
version: '0.6'
|
167
|
-
- !ruby/object:Gem::Dependency
|
168
|
-
name: rubocop-rspec
|
169
|
-
requirement: !ruby/object:Gem::Requirement
|
170
|
-
requirements:
|
171
|
-
- - "~>"
|
172
|
-
- !ruby/object:Gem::Version
|
173
|
-
version: '2.18'
|
174
|
-
type: :development
|
175
|
-
prerelease: false
|
176
|
-
version_requirements: !ruby/object:Gem::Requirement
|
177
|
-
requirements:
|
178
|
-
- - "~>"
|
179
|
-
- !ruby/object:Gem::Version
|
180
|
-
version: '2.18'
|
181
|
-
- !ruby/object:Gem::Dependency
|
182
|
-
name: sinatra
|
183
|
-
requirement: !ruby/object:Gem::Requirement
|
184
|
-
requirements:
|
185
|
-
- - "~>"
|
186
|
-
- !ruby/object:Gem::Version
|
187
|
-
version: '3.2'
|
188
|
-
type: :development
|
189
|
-
prerelease: false
|
190
|
-
version_requirements: !ruby/object:Gem::Requirement
|
191
|
-
requirements:
|
192
|
-
- - "~>"
|
193
|
-
- !ruby/object:Gem::Version
|
194
|
-
version: '3.2'
|
195
|
-
- !ruby/object:Gem::Dependency
|
196
|
-
name: simplecov
|
197
|
-
requirement: !ruby/object:Gem::Requirement
|
198
|
-
requirements:
|
199
|
-
- - "~>"
|
200
|
-
- !ruby/object:Gem::Version
|
201
|
-
version: '0.17'
|
202
|
-
- - "<"
|
203
|
-
- !ruby/object:Gem::Version
|
204
|
-
version: '0.18'
|
205
|
-
type: :development
|
206
|
-
prerelease: false
|
207
|
-
version_requirements: !ruby/object:Gem::Requirement
|
208
|
-
requirements:
|
209
|
-
- - "~>"
|
210
|
-
- !ruby/object:Gem::Version
|
211
|
-
version: '0.17'
|
212
|
-
- - "<"
|
213
|
-
- !ruby/object:Gem::Version
|
214
|
-
version: '0.18'
|
215
41
|
description: Transform HTML into PDF/PNG/JPEG using Google Puppeteer/Chromium
|
216
42
|
email:
|
217
43
|
- abromwich@studiosity.com
|