screenshotfreeapi 1.0.0
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/LICENSE +21 -0
- data/README.md +442 -0
- data/lib/screenshotfreeapi/client.rb +67 -0
- data/lib/screenshotfreeapi/errors.rb +89 -0
- data/lib/screenshotfreeapi/http_client.rb +180 -0
- data/lib/screenshotfreeapi/resources/auth.rb +58 -0
- data/lib/screenshotfreeapi/resources/billing.rb +77 -0
- data/lib/screenshotfreeapi/resources/integrations.rb +52 -0
- data/lib/screenshotfreeapi/resources/jobs.rb +59 -0
- data/lib/screenshotfreeapi/resources/monitors.rb +88 -0
- data/lib/screenshotfreeapi/resources/screenshots.rb +166 -0
- data/lib/screenshotfreeapi/resources/workspaces.rb +96 -0
- data/lib/screenshotfreeapi/version.rb +5 -0
- data/lib/screenshotfreeapi/webhooks.rb +78 -0
- data/lib/screenshotfreeapi.rb +47 -0
- metadata +64 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ScreenshotFreeAPI
|
|
4
|
+
module Resources
|
|
5
|
+
# Team workspace management.
|
|
6
|
+
#
|
|
7
|
+
# Workspaces allow multiple users to share API keys and collaborate.
|
|
8
|
+
# All methods require a management JWT (from Auth#token) passed as `jwt:`.
|
|
9
|
+
#
|
|
10
|
+
# Member roles: "owner" | "admin" | "member" | "viewer"
|
|
11
|
+
class Workspaces
|
|
12
|
+
def initialize(http)
|
|
13
|
+
@http = http
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Create a new workspace.
|
|
17
|
+
#
|
|
18
|
+
# @param jwt [String] Management JWT
|
|
19
|
+
# @param name [String] Workspace display name
|
|
20
|
+
#
|
|
21
|
+
# @return [Hash] Workspace object
|
|
22
|
+
def create(jwt:, name:, **options)
|
|
23
|
+
body = { name: name }.merge(options)
|
|
24
|
+
@http.request(:post, "/workspaces", body: body, auth_header: "Bearer #{jwt}")
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# List workspaces the authenticated user belongs to.
|
|
28
|
+
#
|
|
29
|
+
# @param jwt [String] Management JWT
|
|
30
|
+
#
|
|
31
|
+
# @return [Array<Hash>] Array of workspace objects
|
|
32
|
+
def list(jwt:)
|
|
33
|
+
@http.request(:get, "/workspaces", auth_header: "Bearer #{jwt}")
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Get a single workspace with its members list.
|
|
37
|
+
#
|
|
38
|
+
# @param jwt [String] Management JWT
|
|
39
|
+
# @param workspace_id [String] Workspace ID
|
|
40
|
+
#
|
|
41
|
+
# @return [Hash] Workspace object including "members" array
|
|
42
|
+
def get(jwt:, workspace_id:)
|
|
43
|
+
@http.request(:get, "/workspaces/#{workspace_id}", auth_header: "Bearer #{jwt}")
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Invite a user to the workspace by email address.
|
|
47
|
+
#
|
|
48
|
+
# @param jwt [String]
|
|
49
|
+
# @param workspace_id [String]
|
|
50
|
+
# @param email [String] Email of the person to invite
|
|
51
|
+
# @param role [String] "admin" | "member" | "viewer"
|
|
52
|
+
#
|
|
53
|
+
# @return [Hash] Invitation object
|
|
54
|
+
def invite(jwt:, workspace_id:, email:, role: "member")
|
|
55
|
+
@http.request(
|
|
56
|
+
:post,
|
|
57
|
+
"/workspaces/#{workspace_id}/invite",
|
|
58
|
+
body: { email: email, role: role },
|
|
59
|
+
auth_header: "Bearer #{jwt}"
|
|
60
|
+
)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Remove a member from the workspace.
|
|
64
|
+
#
|
|
65
|
+
# @param jwt [String]
|
|
66
|
+
# @param workspace_id [String]
|
|
67
|
+
# @param user_id [String] ID of the member to remove
|
|
68
|
+
#
|
|
69
|
+
# @return [Hash] Confirmation object
|
|
70
|
+
def remove_member(jwt:, workspace_id:, user_id:)
|
|
71
|
+
@http.request(
|
|
72
|
+
:delete,
|
|
73
|
+
"/workspaces/#{workspace_id}/members/#{user_id}",
|
|
74
|
+
auth_header: "Bearer #{jwt}"
|
|
75
|
+
)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Change a member's role within the workspace.
|
|
79
|
+
#
|
|
80
|
+
# @param jwt [String]
|
|
81
|
+
# @param workspace_id [String]
|
|
82
|
+
# @param user_id [String]
|
|
83
|
+
# @param role [String] New role: "admin" | "member" | "viewer"
|
|
84
|
+
#
|
|
85
|
+
# @return [Hash] Updated member object
|
|
86
|
+
def update_member(jwt:, workspace_id:, user_id:, role:)
|
|
87
|
+
@http.request(
|
|
88
|
+
:patch,
|
|
89
|
+
"/workspaces/#{workspace_id}/members/#{user_id}",
|
|
90
|
+
body: { role: role },
|
|
91
|
+
auth_header: "Bearer #{jwt}"
|
|
92
|
+
)
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "openssl"
|
|
4
|
+
|
|
5
|
+
module ScreenshotFreeAPI
|
|
6
|
+
# Utilities for verifying incoming ScreenshotFreeAPI webhook signatures.
|
|
7
|
+
#
|
|
8
|
+
# The API signs webhook payloads with HMAC-SHA256 using your webhook secret.
|
|
9
|
+
# The signature is delivered in the `X-ScreenshotFree-Signature` header as a hex digest.
|
|
10
|
+
#
|
|
11
|
+
# Example (Rack / Rails):
|
|
12
|
+
#
|
|
13
|
+
# raw_body = request.body.read
|
|
14
|
+
# signature = request.headers["X-ScreenshotFree-Signature"]
|
|
15
|
+
#
|
|
16
|
+
# unless ScreenshotFreeAPI::Webhooks.verify_signature(raw_body, signature, ENV["WEBHOOK_SECRET"])
|
|
17
|
+
# render plain: "Bad signature", status: :forbidden and return
|
|
18
|
+
# end
|
|
19
|
+
#
|
|
20
|
+
module Webhooks
|
|
21
|
+
# Verify that a webhook payload was signed by the ScreenshotFreeAPI.
|
|
22
|
+
#
|
|
23
|
+
# Uses a constant-time comparison to prevent timing attacks.
|
|
24
|
+
#
|
|
25
|
+
# @param raw_body [String] Raw request body bytes (before any parsing)
|
|
26
|
+
# @param signature [String] Value of the `X-ScreenshotFree-Signature` header
|
|
27
|
+
# @param secret [String] Your webhook signing secret
|
|
28
|
+
#
|
|
29
|
+
# @return [Boolean] `true` if the signature is valid, `false` otherwise
|
|
30
|
+
def self.verify_signature(raw_body, signature, secret)
|
|
31
|
+
return false if raw_body.nil? || signature.nil? || secret.nil?
|
|
32
|
+
return false if signature.empty? || secret.empty?
|
|
33
|
+
|
|
34
|
+
expected = OpenSSL::HMAC.hexdigest("SHA256", secret.to_s, raw_body.to_s)
|
|
35
|
+
secure_compare(expected, signature.to_s)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Parse a verified webhook payload into a plain hash.
|
|
39
|
+
#
|
|
40
|
+
# Raises ArgumentError if the signature is invalid.
|
|
41
|
+
#
|
|
42
|
+
# @param raw_body [String] Raw request body
|
|
43
|
+
# @param signature [String] X-ScreenshotFree-Signature header value
|
|
44
|
+
# @param secret [String] Webhook signing secret
|
|
45
|
+
#
|
|
46
|
+
# @return [Hash] Parsed event payload
|
|
47
|
+
def self.construct_event(raw_body, signature, secret)
|
|
48
|
+
unless verify_signature(raw_body, signature, secret)
|
|
49
|
+
raise ArgumentError, "Invalid webhook signature"
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
require "json"
|
|
53
|
+
JSON.parse(raw_body)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Constant-time string comparison to mitigate timing side-channel attacks.
|
|
57
|
+
#
|
|
58
|
+
# XORs each byte of both strings and accumulates any differences.
|
|
59
|
+
# Returns true only when the accumulated diff is zero (all bytes equal)
|
|
60
|
+
# and both strings have the same length.
|
|
61
|
+
#
|
|
62
|
+
# @param a [String] First string (expected)
|
|
63
|
+
# @param b [String] Second string (provided)
|
|
64
|
+
# @return [Boolean]
|
|
65
|
+
def self.secure_compare(a, b)
|
|
66
|
+
return false unless a.bytesize == b.bytesize
|
|
67
|
+
|
|
68
|
+
l = a.unpack("C#{a.bytesize}")
|
|
69
|
+
r = b.unpack("C#{b.bytesize}")
|
|
70
|
+
|
|
71
|
+
diff = 0
|
|
72
|
+
l.zip(r) { |x, y| diff |= (x ^ y) }
|
|
73
|
+
diff.zero?
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
private_class_method :secure_compare
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# screenshotfreeapi — Official Ruby SDK for ScreenshotFreeAPI
|
|
4
|
+
#
|
|
5
|
+
# ScreenshotFreeAPI is a screenshot-as-a-service platform. This SDK wraps the
|
|
6
|
+
# REST API and provides a clean Ruby interface for capturing web pages,
|
|
7
|
+
# mobile app store listings, and HTML strings.
|
|
8
|
+
#
|
|
9
|
+
# Quick start:
|
|
10
|
+
#
|
|
11
|
+
# require "screenshotfreeapi"
|
|
12
|
+
#
|
|
13
|
+
# client = ScreenshotFreeAPI.new(api_key: ENV["SCREENSHOTFREEAPI_KEY"])
|
|
14
|
+
# result = client.capture("https://example.com")
|
|
15
|
+
# puts result["screenshots"].first["url"]
|
|
16
|
+
#
|
|
17
|
+
|
|
18
|
+
require_relative "screenshotfreeapi/version"
|
|
19
|
+
require_relative "screenshotfreeapi/errors"
|
|
20
|
+
require_relative "screenshotfreeapi/http_client"
|
|
21
|
+
require_relative "screenshotfreeapi/webhooks"
|
|
22
|
+
require_relative "screenshotfreeapi/resources/auth"
|
|
23
|
+
require_relative "screenshotfreeapi/resources/jobs"
|
|
24
|
+
require_relative "screenshotfreeapi/resources/screenshots"
|
|
25
|
+
require_relative "screenshotfreeapi/resources/billing"
|
|
26
|
+
require_relative "screenshotfreeapi/resources/workspaces"
|
|
27
|
+
require_relative "screenshotfreeapi/resources/monitors"
|
|
28
|
+
require_relative "screenshotfreeapi/resources/integrations"
|
|
29
|
+
require_relative "screenshotfreeapi/client"
|
|
30
|
+
|
|
31
|
+
module ScreenshotFreeAPI
|
|
32
|
+
# Convenience constructor — creates a Client without needing to reference
|
|
33
|
+
# the full class path.
|
|
34
|
+
#
|
|
35
|
+
# @param api_key [String]
|
|
36
|
+
# @param base_url [String] (optional)
|
|
37
|
+
# @param timeout [Integer] (optional)
|
|
38
|
+
# @param max_retries [Integer] (optional)
|
|
39
|
+
#
|
|
40
|
+
# @return [ScreenshotFreeAPI::Client]
|
|
41
|
+
#
|
|
42
|
+
# @example
|
|
43
|
+
# client = ScreenshotFreeAPI.new(api_key: "sfa_...")
|
|
44
|
+
def self.new(api_key:, **opts)
|
|
45
|
+
Client.new(api_key: api_key, **opts)
|
|
46
|
+
end
|
|
47
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: screenshotfreeapi
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- ScreenshotFreeAPI
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2026-06-20 00:00:00.000000000 Z
|
|
12
|
+
dependencies: []
|
|
13
|
+
description: Ruby client for ScreenshotFreeAPI — screenshot-as-a-service. Capture
|
|
14
|
+
web pages, mobile app store listings, and HTML strings via a simple HTTP API. Supports
|
|
15
|
+
async job polling, webhook signature verification, and all billing/workspace endpoints.
|
|
16
|
+
email:
|
|
17
|
+
- support@screenshotfreeapi.com
|
|
18
|
+
executables: []
|
|
19
|
+
extensions: []
|
|
20
|
+
extra_rdoc_files: []
|
|
21
|
+
files:
|
|
22
|
+
- LICENSE
|
|
23
|
+
- README.md
|
|
24
|
+
- lib/screenshotfreeapi.rb
|
|
25
|
+
- lib/screenshotfreeapi/client.rb
|
|
26
|
+
- lib/screenshotfreeapi/errors.rb
|
|
27
|
+
- lib/screenshotfreeapi/http_client.rb
|
|
28
|
+
- lib/screenshotfreeapi/resources/auth.rb
|
|
29
|
+
- lib/screenshotfreeapi/resources/billing.rb
|
|
30
|
+
- lib/screenshotfreeapi/resources/integrations.rb
|
|
31
|
+
- lib/screenshotfreeapi/resources/jobs.rb
|
|
32
|
+
- lib/screenshotfreeapi/resources/monitors.rb
|
|
33
|
+
- lib/screenshotfreeapi/resources/screenshots.rb
|
|
34
|
+
- lib/screenshotfreeapi/resources/workspaces.rb
|
|
35
|
+
- lib/screenshotfreeapi/version.rb
|
|
36
|
+
- lib/screenshotfreeapi/webhooks.rb
|
|
37
|
+
homepage: https://api.screenshotfreeapi.com
|
|
38
|
+
licenses:
|
|
39
|
+
- MIT
|
|
40
|
+
metadata:
|
|
41
|
+
homepage_uri: https://api.screenshotfreeapi.com
|
|
42
|
+
source_code_uri: https://github.com/chinkauchenna2021/screenshotfreeapi-ruby
|
|
43
|
+
changelog_uri: https://github.com/chinkauchenna2021/screenshotfreeapi-ruby/blob/main/CHANGELOG.md
|
|
44
|
+
bug_tracker_uri: https://github.com/chinkauchenna2021/screenshotfreeapi-ruby/issues
|
|
45
|
+
post_install_message:
|
|
46
|
+
rdoc_options: []
|
|
47
|
+
require_paths:
|
|
48
|
+
- lib
|
|
49
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - ">="
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '2.7'
|
|
54
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
55
|
+
requirements:
|
|
56
|
+
- - ">="
|
|
57
|
+
- !ruby/object:Gem::Version
|
|
58
|
+
version: '0'
|
|
59
|
+
requirements: []
|
|
60
|
+
rubygems_version: 3.4.19
|
|
61
|
+
signing_key:
|
|
62
|
+
specification_version: 4
|
|
63
|
+
summary: Official Ruby SDK for ScreenshotFreeAPI
|
|
64
|
+
test_files: []
|