websitescreenshotworld 0.1.3
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 +7 -0
- data/CHANGELOG.md +59 -0
- data/LICENSE +21 -0
- data/README.md +371 -0
- data/lib/websitescreenshotworld/auto_schedule.rb +22 -0
- data/lib/websitescreenshotworld/capture.rb +124 -0
- data/lib/websitescreenshotworld/capture_file.rb +167 -0
- data/lib/websitescreenshotworld/catalog.rb +19 -0
- data/lib/websitescreenshotworld/client.rb +48 -0
- data/lib/websitescreenshotworld/defaults.rb +87 -0
- data/lib/websitescreenshotworld/error_response.rb +76 -0
- data/lib/websitescreenshotworld/errors.rb +63 -0
- data/lib/websitescreenshotworld/event_data.rb +164 -0
- data/lib/websitescreenshotworld/events.rb +74 -0
- data/lib/websitescreenshotworld/instant_snap.rb +260 -0
- data/lib/websitescreenshotworld/model.rb +46 -0
- data/lib/websitescreenshotworld/service.rb +65 -0
- data/lib/websitescreenshotworld/tokens.rb +110 -0
- data/lib/websitescreenshotworld/transport.rb +124 -0
- data/lib/websitescreenshotworld/trigger_result.rb +24 -0
- data/lib/websitescreenshotworld/version.rb +6 -0
- data/lib/websitescreenshotworld/webhook.rb +68 -0
- data/lib/websitescreenshotworld.rb +33 -0
- metadata +69 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module WebsiteScreenshotWorld
|
|
4
|
+
# The answer to {AutoSchedule#trigger_now}. The capture itself arrives later by webhook.
|
|
5
|
+
#
|
|
6
|
+
# @!attribute [r] status
|
|
7
|
+
# @return [String] one of {TriggerStatus}
|
|
8
|
+
# @!attribute [r] web_page_id
|
|
9
|
+
# @return [String]
|
|
10
|
+
# @!attribute [r] triggered_by
|
|
11
|
+
# @return [String] one of {TriggeredBy}
|
|
12
|
+
# @!attribute [r] triggered_at
|
|
13
|
+
# @return [Time] when the capture was queued; for +already_pending+, the original trigger
|
|
14
|
+
# @!attribute [r] message
|
|
15
|
+
# @return [String] one sentence for a person
|
|
16
|
+
TriggerResult = Data.define(:status, :web_page_id, :triggered_by, :triggered_at, :message) do
|
|
17
|
+
include Model::Raw
|
|
18
|
+
|
|
19
|
+
# @api private
|
|
20
|
+
def self.from_api(hash)
|
|
21
|
+
Model.build(self, hash, triggered_at: Model.time(hash["triggered_at"]))
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module WebsiteScreenshotWorld
|
|
4
|
+
# Verifies webhook deliveries from both products.
|
|
5
|
+
#
|
|
6
|
+
# @example
|
|
7
|
+
# event = WebsiteScreenshotWorld::Webhook.verify(
|
|
8
|
+
# request.raw_post, request.headers["X-WSW-Signature"], ENV.fetch("WSW_WEBHOOK_SECRET")
|
|
9
|
+
# )
|
|
10
|
+
module Webhook
|
|
11
|
+
# The header that carries the signature.
|
|
12
|
+
SIGNATURE_HEADER = "X-WSW-Signature"
|
|
13
|
+
|
|
14
|
+
# Seconds a delivery's timestamp may differ from the current time.
|
|
15
|
+
DEFAULT_TOLERANCE = 300
|
|
16
|
+
|
|
17
|
+
class << self
|
|
18
|
+
# Checks a delivery's signature and returns its event.
|
|
19
|
+
#
|
|
20
|
+
# @param payload [String] the request body exactly as received, not parsed and re-serialised
|
|
21
|
+
# @param signature_header [String, nil] the value of the +X-WSW-Signature+ header
|
|
22
|
+
# @param secret [String] the endpoint's signing secret
|
|
23
|
+
# @param tolerance [Integer] seconds the signed timestamp may be before or after +now+
|
|
24
|
+
# @param now [Time] the current time
|
|
25
|
+
# @return [Event] a subclass matching the event's type, or {UnknownEvent}
|
|
26
|
+
# @raise [SignatureVerificationError] when the header is missing or malformed, the timestamp is outside
|
|
27
|
+
# the tolerance, or no signature matches
|
|
28
|
+
# @raise [ArgumentError] when +payload+ is not a String or +secret+ is empty
|
|
29
|
+
def verify(payload, signature_header, secret, tolerance: DEFAULT_TOLERANCE, now: Time.now)
|
|
30
|
+
raise ArgumentError, "payload must be the raw request body as a String" unless payload.is_a?(String)
|
|
31
|
+
raise ArgumentError, "secret must not be empty" if secret.to_s.empty?
|
|
32
|
+
|
|
33
|
+
timestamp, signatures = parse_header(signature_header.to_s)
|
|
34
|
+
if (now.to_i - timestamp).abs > tolerance
|
|
35
|
+
raise SignatureVerificationError, "The signature's timestamp is outside the #{tolerance}-second tolerance."
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
expected = OpenSSL::HMAC.hexdigest("SHA256", secret.to_s.b, "#{timestamp}.".b + payload.b)
|
|
39
|
+
unless signatures.any? { |signature| OpenSSL.secure_compare(expected, signature.downcase) }
|
|
40
|
+
raise SignatureVerificationError, "No signature in the #{SIGNATURE_HEADER} header matches the payload."
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
Event.from_api(Model.parse_json(payload))
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
private
|
|
47
|
+
|
|
48
|
+
def parse_header(header)
|
|
49
|
+
pairs = header.split(",").map { |part| part.split("=", 2).map(&:strip) }
|
|
50
|
+
[timestamp_from(pairs), signatures_from(pairs)]
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def timestamp_from(pairs)
|
|
54
|
+
value = pairs.find { |name, _| name == "t" }&.last
|
|
55
|
+
return Integer(value, 10) if value&.match?(/\A\d+\z/)
|
|
56
|
+
|
|
57
|
+
raise SignatureVerificationError, "The #{SIGNATURE_HEADER} header has no valid timestamp."
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def signatures_from(pairs)
|
|
61
|
+
signatures = pairs.filter_map { |name, value| value if name == "v1" }
|
|
62
|
+
return signatures unless signatures.empty?
|
|
63
|
+
|
|
64
|
+
raise SignatureVerificationError, "The #{SIGNATURE_HEADER} header has no v1 signature."
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
require "net/http"
|
|
5
|
+
require "openssl"
|
|
6
|
+
require "securerandom"
|
|
7
|
+
require "tempfile"
|
|
8
|
+
require "time"
|
|
9
|
+
require "uri"
|
|
10
|
+
|
|
11
|
+
require_relative "websitescreenshotworld/version"
|
|
12
|
+
require_relative "websitescreenshotworld/tokens"
|
|
13
|
+
require_relative "websitescreenshotworld/errors"
|
|
14
|
+
require_relative "websitescreenshotworld/error_response"
|
|
15
|
+
require_relative "websitescreenshotworld/model"
|
|
16
|
+
require_relative "websitescreenshotworld/capture"
|
|
17
|
+
require_relative "websitescreenshotworld/capture_file"
|
|
18
|
+
require_relative "websitescreenshotworld/defaults"
|
|
19
|
+
require_relative "websitescreenshotworld/catalog"
|
|
20
|
+
require_relative "websitescreenshotworld/trigger_result"
|
|
21
|
+
require_relative "websitescreenshotworld/event_data"
|
|
22
|
+
require_relative "websitescreenshotworld/events"
|
|
23
|
+
require_relative "websitescreenshotworld/webhook"
|
|
24
|
+
require_relative "websitescreenshotworld/transport"
|
|
25
|
+
require_relative "websitescreenshotworld/service"
|
|
26
|
+
require_relative "websitescreenshotworld/instant_snap"
|
|
27
|
+
require_relative "websitescreenshotworld/auto_schedule"
|
|
28
|
+
require_relative "websitescreenshotworld/client"
|
|
29
|
+
|
|
30
|
+
# Client for the Website Screenshot World APIs: Instant Snap captures, Auto Schedule triggers and webhook
|
|
31
|
+
# verification. Start with {Client}.
|
|
32
|
+
module WebsiteScreenshotWorld
|
|
33
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: websitescreenshotworld
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.3
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Silhouettec Solutions Private Limited
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies: []
|
|
12
|
+
description: Capture web pages as images, videos or PDFs with Instant Snap, trigger
|
|
13
|
+
scheduled captures with Auto Schedule, and verify Website Screenshot World webhooks.
|
|
14
|
+
email:
|
|
15
|
+
- support@websitescreenshotworld.com
|
|
16
|
+
executables: []
|
|
17
|
+
extensions: []
|
|
18
|
+
extra_rdoc_files: []
|
|
19
|
+
files:
|
|
20
|
+
- CHANGELOG.md
|
|
21
|
+
- LICENSE
|
|
22
|
+
- README.md
|
|
23
|
+
- lib/websitescreenshotworld.rb
|
|
24
|
+
- lib/websitescreenshotworld/auto_schedule.rb
|
|
25
|
+
- lib/websitescreenshotworld/capture.rb
|
|
26
|
+
- lib/websitescreenshotworld/capture_file.rb
|
|
27
|
+
- lib/websitescreenshotworld/catalog.rb
|
|
28
|
+
- lib/websitescreenshotworld/client.rb
|
|
29
|
+
- lib/websitescreenshotworld/defaults.rb
|
|
30
|
+
- lib/websitescreenshotworld/error_response.rb
|
|
31
|
+
- lib/websitescreenshotworld/errors.rb
|
|
32
|
+
- lib/websitescreenshotworld/event_data.rb
|
|
33
|
+
- lib/websitescreenshotworld/events.rb
|
|
34
|
+
- lib/websitescreenshotworld/instant_snap.rb
|
|
35
|
+
- lib/websitescreenshotworld/model.rb
|
|
36
|
+
- lib/websitescreenshotworld/service.rb
|
|
37
|
+
- lib/websitescreenshotworld/tokens.rb
|
|
38
|
+
- lib/websitescreenshotworld/transport.rb
|
|
39
|
+
- lib/websitescreenshotworld/trigger_result.rb
|
|
40
|
+
- lib/websitescreenshotworld/version.rb
|
|
41
|
+
- lib/websitescreenshotworld/webhook.rb
|
|
42
|
+
homepage: https://websitescreenshotworld.com
|
|
43
|
+
licenses:
|
|
44
|
+
- MIT
|
|
45
|
+
metadata:
|
|
46
|
+
homepage_uri: https://websitescreenshotworld.com
|
|
47
|
+
source_code_uri: https://github.com/websitescreenshotworld/websitescreenshotworld-ruby
|
|
48
|
+
changelog_uri: https://github.com/websitescreenshotworld/websitescreenshotworld-ruby/blob/main/CHANGELOG.md
|
|
49
|
+
bug_tracker_uri: https://github.com/websitescreenshotworld/websitescreenshotworld-ruby/issues
|
|
50
|
+
rubygems_mfa_required: 'true'
|
|
51
|
+
rdoc_options: []
|
|
52
|
+
require_paths:
|
|
53
|
+
- lib
|
|
54
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
55
|
+
requirements:
|
|
56
|
+
- - ">="
|
|
57
|
+
- !ruby/object:Gem::Version
|
|
58
|
+
version: '3.2'
|
|
59
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
60
|
+
requirements:
|
|
61
|
+
- - ">="
|
|
62
|
+
- !ruby/object:Gem::Version
|
|
63
|
+
version: '0'
|
|
64
|
+
requirements: []
|
|
65
|
+
rubygems_version: 3.6.9
|
|
66
|
+
specification_version: 4
|
|
67
|
+
summary: Ruby client for the Website Screenshot World Instant Snap and Auto Schedule
|
|
68
|
+
APIs.
|
|
69
|
+
test_files: []
|