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.
@@ -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,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module WebsiteScreenshotWorld
4
+ # The library's version, sent in the User-Agent header.
5
+ VERSION = "0.1.3"
6
+ 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: []