generatorlabs 2.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 +546 -0
- data/lib/generatorlabs/cert.rb +220 -0
- data/lib/generatorlabs/client.rb +128 -0
- data/lib/generatorlabs/config.rb +85 -0
- data/lib/generatorlabs/contact.rb +192 -0
- data/lib/generatorlabs/rate_limit_info.rb +30 -0
- data/lib/generatorlabs/rbl.rb +297 -0
- data/lib/generatorlabs/request_handler.rb +213 -0
- data/lib/generatorlabs/response.rb +62 -0
- data/lib/generatorlabs/version.rb +15 -0
- data/lib/generatorlabs/webhook.rb +70 -0
- data/lib/generatorlabs.rb +26 -0
- metadata +90 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 8e830c5a4cd5b0df22bf19efaf939efe353e910cd65498a986f9e066f4d1faa3
|
|
4
|
+
data.tar.gz: 5038ebd57fea4966821b853c9930fb70046283051a51c5fc18821246bc8e126f
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 8229f18ff07f6e03e72ebd130f3432222a38db4afa3badc5f31ced4bf8e943044f4064a355ec275b14377d80cf2aac75c18f1be25969b6048acf353b51ab7448
|
|
7
|
+
data.tar.gz: 86e8aeda04eab53cf2898431f61093deb99e0005cf1eb8f3a8baac516f48219032d7fe9aa879d0c532dcb1b393b5c9d8f270245a548ec6cfba2751f22f557091
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Generator Labs, Inc. <support@generatorlabs.com>
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is furnished
|
|
10
|
+
to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,546 @@
|
|
|
1
|
+
# Generator Labs Ruby SDK
|
|
2
|
+
|
|
3
|
+
[](https://badge.fury.io/rb/generatorlabs)
|
|
4
|
+
[](https://github.com/generator-labs/ruby-sdk/actions)
|
|
5
|
+
[](https://opensource.org/licenses/MIT)
|
|
6
|
+
|
|
7
|
+
Official Ruby SDK for the [Generator Labs API](https://generatorlabs.com). This library provides a simple and intuitive interface for interacting with the Generator Labs v4.0 API, including RBL monitoring, contact management, and more.
|
|
8
|
+
|
|
9
|
+
## Table of Contents
|
|
10
|
+
|
|
11
|
+
- [Features](#features)
|
|
12
|
+
- [Installation](#installation)
|
|
13
|
+
- [Quick Start](#quick-start)
|
|
14
|
+
- [Webhook Verification](#webhook-verification)
|
|
15
|
+
- [API Reference](#api-reference)
|
|
16
|
+
- [Client Initialization](#client-initialization)
|
|
17
|
+
- [Configuration Options](#configuration-options)
|
|
18
|
+
- [Pagination](#pagination)
|
|
19
|
+
- [RBL Monitoring](#rbl-monitoring) - [Hosts](#hosts) | [Profiles](#profiles) | [Sources](#sources) | [Check & Listings](#check--listings)
|
|
20
|
+
- [Certificate Monitoring](#certificate-monitoring) - [Errors](#errors) | [Monitors](#monitors) | [Profiles](#profiles-1)
|
|
21
|
+
- [Contact Management](#contact-management) - [Contacts](#contacts) | [Groups](#groups)
|
|
22
|
+
- [Error Handling](#error-handling)
|
|
23
|
+
- [Retry Logic](#retry-logic)
|
|
24
|
+
- [Rate Limiting](#rate-limiting)
|
|
25
|
+
- [Examples](#examples)
|
|
26
|
+
- [Requirements](#requirements)
|
|
27
|
+
- [Testing](#testing)
|
|
28
|
+
- [Security](#security)
|
|
29
|
+
- [Release History](#release-history)
|
|
30
|
+
- [License](#license)
|
|
31
|
+
- [Support](#support)
|
|
32
|
+
- [Contributing](#contributing)
|
|
33
|
+
|
|
34
|
+
## Features
|
|
35
|
+
|
|
36
|
+
- Full support for Generator Labs API v4.0
|
|
37
|
+
- Configurable timeouts, retries, and backoff strategies
|
|
38
|
+
- Automatic retry logic with exponential backoff
|
|
39
|
+
- Automatic pagination for large result sets
|
|
40
|
+
- Connection pooling and timeout management
|
|
41
|
+
- Clean, Ruby-idiomatic API
|
|
42
|
+
- Comprehensive error handling
|
|
43
|
+
- Ruby 3.0+ support
|
|
44
|
+
|
|
45
|
+
## Installation
|
|
46
|
+
|
|
47
|
+
Add this line to your application's Gemfile:
|
|
48
|
+
|
|
49
|
+
```ruby
|
|
50
|
+
gem 'generatorlabs'
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
And then execute:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
bundle install
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Or install it yourself as:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
gem install generatorlabs
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Quick Start
|
|
66
|
+
|
|
67
|
+
```ruby
|
|
68
|
+
require 'generatorlabs'
|
|
69
|
+
|
|
70
|
+
# Initialize the client with default configuration
|
|
71
|
+
client = GeneratorLabs::Client.new(
|
|
72
|
+
'YOUR_ACCOUNT_SID',
|
|
73
|
+
'YOUR_AUTH_TOKEN'
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
# Or with custom configuration
|
|
77
|
+
config = GeneratorLabs::Config.new(
|
|
78
|
+
timeout: 45,
|
|
79
|
+
connect_timeout: 10,
|
|
80
|
+
max_retries: 5,
|
|
81
|
+
retry_backoff: 2.0,
|
|
82
|
+
base_url: 'https://api.generatorlabs.com/4.0/'
|
|
83
|
+
)
|
|
84
|
+
client = GeneratorLabs::Client.new(
|
|
85
|
+
'YOUR_ACCOUNT_SID',
|
|
86
|
+
'YOUR_AUTH_TOKEN',
|
|
87
|
+
config
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
# Get all monitored hosts
|
|
91
|
+
hosts = client.rbl.hosts.get
|
|
92
|
+
puts hosts
|
|
93
|
+
|
|
94
|
+
# Start a manual RBL check
|
|
95
|
+
result = client.rbl.check.start(host: '8.8.8.8')
|
|
96
|
+
puts result
|
|
97
|
+
|
|
98
|
+
# Get all contacts with automatic pagination
|
|
99
|
+
all_contacts = client.contact.contacts.get_all
|
|
100
|
+
puts "Total contacts: #{all_contacts.length}"
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Webhook Verification
|
|
104
|
+
|
|
105
|
+
The SDK includes a helper for verifying incoming webhook signatures. Each webhook is assigned a signing secret (available in the Portal), which is used to compute an HMAC-SHA256 signature sent with every request in the `X-Webhook-Signature` header.
|
|
106
|
+
|
|
107
|
+
```ruby
|
|
108
|
+
require 'generatorlabs'
|
|
109
|
+
|
|
110
|
+
header = request.env['HTTP_X_WEBHOOK_SIGNATURE'] || ''
|
|
111
|
+
body = request.body.read
|
|
112
|
+
secret = ENV['GENERATOR_LABS_WEBHOOK_SECRET']
|
|
113
|
+
|
|
114
|
+
begin
|
|
115
|
+
payload = GeneratorLabs::Webhook.verify(body, header, secret)
|
|
116
|
+
|
|
117
|
+
# payload is the decoded event data
|
|
118
|
+
puts payload['event']
|
|
119
|
+
|
|
120
|
+
rescue GeneratorLabs::Error => e
|
|
121
|
+
# Signature verification failed
|
|
122
|
+
halt 403, { error: 'Invalid signature' }.to_json
|
|
123
|
+
end
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
The default timestamp tolerance is 5 minutes. You can customize it (in seconds), or pass `0` to disable:
|
|
127
|
+
|
|
128
|
+
```ruby
|
|
129
|
+
payload = GeneratorLabs::Webhook.verify(body, header, secret, 600) # 10-minute tolerance
|
|
130
|
+
payload = GeneratorLabs::Webhook.verify(body, header, secret, 0) # disable timestamp check
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
See `examples/webhook_verification.rb` for a complete example.
|
|
134
|
+
|
|
135
|
+
## API Reference
|
|
136
|
+
|
|
137
|
+
### Client Initialization
|
|
138
|
+
|
|
139
|
+
```ruby
|
|
140
|
+
# With default configuration
|
|
141
|
+
client = GeneratorLabs::Client.new(account_sid, auth_token)
|
|
142
|
+
|
|
143
|
+
# With custom configuration
|
|
144
|
+
config = GeneratorLabs::Config.new(
|
|
145
|
+
timeout: 45, # Request timeout in seconds (default: 30)
|
|
146
|
+
connect_timeout: 10, # Connection timeout in seconds (default: 5)
|
|
147
|
+
max_retries: 5, # Max retry attempts (default: 3)
|
|
148
|
+
retry_backoff: 2.0, # Backoff multiplier (default: 1.0)
|
|
149
|
+
base_url: 'https://api.generatorlabs.com/4.0/'
|
|
150
|
+
)
|
|
151
|
+
client = GeneratorLabs::Client.new(account_sid, auth_token, config)
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Configuration Options
|
|
155
|
+
|
|
156
|
+
- **timeout**: Maximum duration for the entire request in seconds (default: 30)
|
|
157
|
+
- **connect_timeout**: Maximum duration for connection establishment in seconds (default: 5)
|
|
158
|
+
- **max_retries**: Maximum number of retry attempts for failed requests (default: 3)
|
|
159
|
+
- **retry_backoff**: Multiplier for exponential backoff between retries (default: 1.0)
|
|
160
|
+
- **base_url**: Custom API base URL (default: https://api.generatorlabs.com/4.0/)
|
|
161
|
+
|
|
162
|
+
### Pagination
|
|
163
|
+
|
|
164
|
+
All list operations support automatic pagination using the `get_all` method:
|
|
165
|
+
|
|
166
|
+
```ruby
|
|
167
|
+
# Get all hosts across multiple pages
|
|
168
|
+
all_hosts = client.rbl.hosts.get_all(page_size: 50)
|
|
169
|
+
|
|
170
|
+
# Get all profiles with automatic pagination
|
|
171
|
+
all_profiles = client.rbl.profiles.get_all
|
|
172
|
+
|
|
173
|
+
# Get all contacts with automatic pagination
|
|
174
|
+
all_contacts = client.contact.contacts.get_all
|
|
175
|
+
|
|
176
|
+
# Get all groups with automatic pagination
|
|
177
|
+
all_groups = client.contact.groups.get_all
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### RBL Monitoring
|
|
181
|
+
|
|
182
|
+
#### Hosts
|
|
183
|
+
|
|
184
|
+
```ruby
|
|
185
|
+
# Get all hosts
|
|
186
|
+
hosts = client.rbl.hosts.get
|
|
187
|
+
|
|
188
|
+
# Get a specific host
|
|
189
|
+
host = client.rbl.hosts.get('HT1a2b3c4d5e6f7890abcdef1234567890')
|
|
190
|
+
|
|
191
|
+
# Get multiple hosts
|
|
192
|
+
hosts = client.rbl.hosts.get('HT1a2b3c4d5e6f7890abcdef1234567890', 'HT2b3c4d5e6f7890abcdef12345678901a')
|
|
193
|
+
|
|
194
|
+
# Create a host
|
|
195
|
+
host = client.rbl.hosts.create(
|
|
196
|
+
host: '8.8.8.8',
|
|
197
|
+
name: 'Google DNS',
|
|
198
|
+
profile: 'RP9f8e7d6c5b4a3210fedcba0987654321',
|
|
199
|
+
contact_group: [
|
|
200
|
+
'CG4f3e2d1c0b9a8776655443322110fedc',
|
|
201
|
+
'CG5a6b7c8d9e0f1234567890abcdef1234'
|
|
202
|
+
],
|
|
203
|
+
tags: ['production', 'web']
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
# Update a host
|
|
207
|
+
host = client.rbl.hosts.update('HT1a2b3c4d5e6f7890abcdef1234567890',
|
|
208
|
+
name: 'Updated description',
|
|
209
|
+
tags: ['production', 'web']
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
# Delete a host
|
|
213
|
+
result = client.rbl.hosts.delete('HT1a2b3c4d5e6f7890abcdef1234567890')
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
#### Profiles
|
|
217
|
+
|
|
218
|
+
```ruby
|
|
219
|
+
# Get all profiles
|
|
220
|
+
profiles = client.rbl.profiles.get
|
|
221
|
+
|
|
222
|
+
# Get a specific profile
|
|
223
|
+
profile = client.rbl.profiles.get('RP9f8e7d6c5b4a3210fedcba0987654321')
|
|
224
|
+
|
|
225
|
+
# Create a profile
|
|
226
|
+
profile = client.rbl.profiles.create(
|
|
227
|
+
name: 'My Custom Profile',
|
|
228
|
+
entries: [
|
|
229
|
+
'RB1234567890abcdef1234567890abcdef',
|
|
230
|
+
'RB0987654321fedcba0987654321fedcba'
|
|
231
|
+
]
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
# Update a profile
|
|
235
|
+
profile = client.rbl.profiles.update('RP9f8e7d6c5b4a3210fedcba0987654321',
|
|
236
|
+
name: 'Updated Profile Name',
|
|
237
|
+
entries: [
|
|
238
|
+
'RB1234567890abcdef1234567890abcdef',
|
|
239
|
+
'RB0987654321fedcba0987654321fedcba'
|
|
240
|
+
]
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
# Delete a profile
|
|
244
|
+
result = client.rbl.profiles.delete('RP9f8e7d6c5b4a3210fedcba0987654321')
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
#### Sources
|
|
248
|
+
|
|
249
|
+
```ruby
|
|
250
|
+
# Get all RBL sources
|
|
251
|
+
sources = client.rbl.sources.get
|
|
252
|
+
|
|
253
|
+
# Get a specific source
|
|
254
|
+
source = client.rbl.sources.get('RB18c470cc518a09678bb280960dbdd524')
|
|
255
|
+
|
|
256
|
+
# Create a custom source
|
|
257
|
+
source = client.rbl.sources.create(
|
|
258
|
+
host: 'custom.rbl.example.com',
|
|
259
|
+
type: 'rbl',
|
|
260
|
+
custom_codes: ['127.0.0.2', '127.0.0.3']
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
# Update a source
|
|
264
|
+
source = client.rbl.sources.update('RB18c470cc518a09678bb280960dbdd524',
|
|
265
|
+
host: 'updated.rbl.example.com',
|
|
266
|
+
custom_codes: ['127.0.0.2', '127.0.0.3']
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
# Delete a source
|
|
270
|
+
result = client.rbl.sources.delete('RB18c470cc518a09678bb280960dbdd524')
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
#### Check & Listings
|
|
274
|
+
|
|
275
|
+
```ruby
|
|
276
|
+
# Start a manual RBL check
|
|
277
|
+
result = client.rbl.check.start(host: '8.8.8.8')
|
|
278
|
+
|
|
279
|
+
# Get check status
|
|
280
|
+
status = client.rbl.check.status('check_id')
|
|
281
|
+
|
|
282
|
+
# Get current listings
|
|
283
|
+
listings = client.rbl.listings
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
### Certificate Monitoring
|
|
287
|
+
|
|
288
|
+
Certificate monitoring allows you to monitor SSL/TLS certificates for expiration, validity, and configuration issues across HTTPS, SMTPS, IMAPS, and other TLS-enabled services.
|
|
289
|
+
|
|
290
|
+
#### Errors
|
|
291
|
+
|
|
292
|
+
```ruby
|
|
293
|
+
# Get all certificate errors
|
|
294
|
+
errors = client.cert.errors.get
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
#### Monitors
|
|
298
|
+
|
|
299
|
+
```ruby
|
|
300
|
+
# Get all certificate monitors
|
|
301
|
+
monitors = client.cert.monitors.get
|
|
302
|
+
|
|
303
|
+
# Get a specific monitor
|
|
304
|
+
monitor = client.cert.monitors.get('CM62944aeeee2b46d7a28221164f38976a')
|
|
305
|
+
|
|
306
|
+
# Create a certificate monitor
|
|
307
|
+
monitor = client.cert.monitors.create(
|
|
308
|
+
name: 'Production Web Server',
|
|
309
|
+
hostname: 'example.com',
|
|
310
|
+
protocol: 'https',
|
|
311
|
+
profile: 'CP79b597e61a984a35b5eb7dcdbc3de53c',
|
|
312
|
+
contact_group: [
|
|
313
|
+
'CG4f3e2d1c0b9a8776655443322110fedc',
|
|
314
|
+
'CG5a6b7c8d9e0f1234567890abcdef1234'
|
|
315
|
+
],
|
|
316
|
+
tags: ['production', 'web', 'ssl']
|
|
317
|
+
)
|
|
318
|
+
|
|
319
|
+
# Update a monitor
|
|
320
|
+
monitor = client.cert.monitors.update('CM62944aeeee2b46d7a28221164f38976a',
|
|
321
|
+
name: 'Updated Server Name',
|
|
322
|
+
tags: ['production', 'web', 'ssl']
|
|
323
|
+
)
|
|
324
|
+
|
|
325
|
+
# Delete a monitor
|
|
326
|
+
result = client.cert.monitors.delete('CM62944aeeee2b46d7a28221164f38976a')
|
|
327
|
+
|
|
328
|
+
# Pause monitoring
|
|
329
|
+
result = client.cert.monitors.pause('CM62944aeeee2b46d7a28221164f38976a')
|
|
330
|
+
|
|
331
|
+
# Resume monitoring
|
|
332
|
+
result = client.cert.monitors.resume('CM62944aeeee2b46d7a28221164f38976a')
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
#### Profiles
|
|
336
|
+
|
|
337
|
+
```ruby
|
|
338
|
+
# Get all certificate profiles
|
|
339
|
+
profiles = client.cert.profiles.get
|
|
340
|
+
|
|
341
|
+
# Get a specific profile
|
|
342
|
+
profile = client.cert.profiles.get('CP79b597e61a984a35b5eb7dcdbc3de53c')
|
|
343
|
+
|
|
344
|
+
# Create a profile
|
|
345
|
+
profile = client.cert.profiles.create(
|
|
346
|
+
name: 'Standard Certificate Profile',
|
|
347
|
+
expiration_thresholds: [30, 14, 7],
|
|
348
|
+
alert_on_expiration: true,
|
|
349
|
+
alert_on_name_mismatch: true,
|
|
350
|
+
alert_on_misconfigurations: true,
|
|
351
|
+
alert_on_changes: true
|
|
352
|
+
)
|
|
353
|
+
|
|
354
|
+
# Update a profile
|
|
355
|
+
profile = client.cert.profiles.update('CP79b597e61a984a35b5eb7dcdbc3de53c',
|
|
356
|
+
expiration_thresholds: [45, 14, 7],
|
|
357
|
+
alert_on_misconfigurations: true,
|
|
358
|
+
alert_on_changes: true
|
|
359
|
+
)
|
|
360
|
+
|
|
361
|
+
# Delete a profile
|
|
362
|
+
result = client.cert.profiles.delete('CP79b597e61a984a35b5eb7dcdbc3de53c')
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
### Contact Management
|
|
366
|
+
|
|
367
|
+
#### Contacts
|
|
368
|
+
|
|
369
|
+
```ruby
|
|
370
|
+
# Get all contacts
|
|
371
|
+
contacts = client.contact.contacts.get
|
|
372
|
+
|
|
373
|
+
# Get a specific contact
|
|
374
|
+
contact = client.contact.contacts.get('COabcdef1234567890abcdef1234567890')
|
|
375
|
+
|
|
376
|
+
# Get multiple contacts
|
|
377
|
+
contacts = client.contact.contacts.get('COabcdef1234567890abcdef1234567890', 'CO1234567890abcdef1234567890abcdef')
|
|
378
|
+
|
|
379
|
+
# Create a contact
|
|
380
|
+
contact = client.contact.contacts.create(
|
|
381
|
+
contact: 'user@example.com',
|
|
382
|
+
type: 'email',
|
|
383
|
+
schedule: 'every_check',
|
|
384
|
+
contact_group: [
|
|
385
|
+
'CG4f3e2d1c0b9a8776655443322110fedc',
|
|
386
|
+
'CG5a6b7c8d9e0f1234567890abcdef1234'
|
|
387
|
+
]
|
|
388
|
+
)
|
|
389
|
+
|
|
390
|
+
# Update a contact
|
|
391
|
+
contact = client.contact.contacts.update('COabcdef1234567890abcdef1234567890',
|
|
392
|
+
contact: 'updated@example.com',
|
|
393
|
+
contact_group: [
|
|
394
|
+
'CG4f3e2d1c0b9a8776655443322110fedc',
|
|
395
|
+
'CG5a6b7c8d9e0f1234567890abcdef1234'
|
|
396
|
+
]
|
|
397
|
+
)
|
|
398
|
+
|
|
399
|
+
# Delete a contact
|
|
400
|
+
result = client.contact.contacts.delete('COabcdef1234567890abcdef1234567890')
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
#### Groups
|
|
404
|
+
|
|
405
|
+
```ruby
|
|
406
|
+
# Get all groups
|
|
407
|
+
groups = client.contact.groups.get
|
|
408
|
+
|
|
409
|
+
# Get a specific group
|
|
410
|
+
group = client.contact.groups.get('CG4f3e2d1c0b9a8776655443322110fedc')
|
|
411
|
+
|
|
412
|
+
# Create a group
|
|
413
|
+
group = client.contact.groups.create(
|
|
414
|
+
name: 'Primary Contacts'
|
|
415
|
+
)
|
|
416
|
+
|
|
417
|
+
# Update a group
|
|
418
|
+
group = client.contact.groups.update('CG4f3e2d1c0b9a8776655443322110fedc',
|
|
419
|
+
name: 'Updated Group Name'
|
|
420
|
+
)
|
|
421
|
+
|
|
422
|
+
# Delete a group
|
|
423
|
+
result = client.contact.groups.delete('CG4f3e2d1c0b9a8776655443322110fedc')
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
## Error Handling
|
|
427
|
+
|
|
428
|
+
All methods raise `GeneratorLabs::Error` on failure:
|
|
429
|
+
|
|
430
|
+
```ruby
|
|
431
|
+
begin
|
|
432
|
+
result = client.rbl.check('8.8.8.8')
|
|
433
|
+
rescue GeneratorLabs::Error => e
|
|
434
|
+
puts "API error: #{e.message}"
|
|
435
|
+
end
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
## Retry Logic
|
|
439
|
+
|
|
440
|
+
The SDK automatically retries failed requests with exponential backoff:
|
|
441
|
+
- Configurable maximum retry attempts (default: 3)
|
|
442
|
+
- Retries on connection errors, 5xx server errors, and 429 rate limits
|
|
443
|
+
- Respects `Retry-After` header on 429 responses before falling back to exponential backoff
|
|
444
|
+
- Configurable exponential backoff multiplier (default: 1.0 for 1s, 2s, 4s delays)
|
|
445
|
+
- Configurable connection timeout (default: 5 seconds)
|
|
446
|
+
- Configurable request timeout (default: 30 seconds)
|
|
447
|
+
|
|
448
|
+
Customize retry behavior via the `Config` class:
|
|
449
|
+
|
|
450
|
+
```ruby
|
|
451
|
+
config = GeneratorLabs::Config.new(
|
|
452
|
+
max_retries: 5, # More retry attempts
|
|
453
|
+
retry_backoff: 2.0, # Faster exponential growth
|
|
454
|
+
timeout: 60 # Longer timeout
|
|
455
|
+
)
|
|
456
|
+
client = GeneratorLabs::Client.new(account_sid, auth_token, config)
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
## Rate Limiting
|
|
460
|
+
|
|
461
|
+
The API enforces two layers of rate limiting:
|
|
462
|
+
|
|
463
|
+
- **Hourly limit**: 1,000 requests per hour per application
|
|
464
|
+
- **Per-second limit**: varies by endpoint — 100 RPS for read operations, 50 RPS for write operations, and 20 RPS for manual check start
|
|
465
|
+
|
|
466
|
+
When a rate limit is exceeded, the API returns HTTP 429 with a `Retry-After` header indicating how many seconds to wait. The SDK automatically respects this header during retries.
|
|
467
|
+
|
|
468
|
+
All API responses include IETF draft rate limit headers, accessible via the `rate_limit_info` attribute on every response:
|
|
469
|
+
|
|
470
|
+
| Header | Description | Example |
|
|
471
|
+
|--------|-------------|---------|
|
|
472
|
+
| `RateLimit-Limit` | Active rate limit policies | `1000;w=3600, 100;w=1` |
|
|
473
|
+
| `RateLimit-Remaining` | Requests remaining in the most restrictive window | `95` |
|
|
474
|
+
| `RateLimit-Reset` | Seconds until the most restrictive window resets | `1` |
|
|
475
|
+
|
|
476
|
+
```ruby
|
|
477
|
+
response = client.rbl.hosts.get
|
|
478
|
+
|
|
479
|
+
# Access response data (bracket notation works as before)
|
|
480
|
+
hosts = response['data']
|
|
481
|
+
|
|
482
|
+
# Access rate limit info
|
|
483
|
+
if response.rate_limit_info
|
|
484
|
+
puts "Remaining: #{response.rate_limit_info.remaining}"
|
|
485
|
+
puts "Reset: #{response.rate_limit_info.reset}s"
|
|
486
|
+
end
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
## Examples
|
|
490
|
+
|
|
491
|
+
The `examples/` directory contains complete, runnable examples demonstrating:
|
|
492
|
+
|
|
493
|
+
- **check_ip.rb**: Check if an IP is listed on any RBLs
|
|
494
|
+
- **manage_hosts.rb**: Create, list, update, and delete monitored hosts
|
|
495
|
+
- **pagination.rb**: Handle large result sets with automatic pagination
|
|
496
|
+
- **error_handling.rb**: Proper error handling and custom configuration
|
|
497
|
+
|
|
498
|
+
Run examples:
|
|
499
|
+
|
|
500
|
+
```bash
|
|
501
|
+
export GENERATOR_LABS_ACCOUNT_SID="your_account_sid"
|
|
502
|
+
export GENERATOR_LABS_AUTH_TOKEN="your_auth_token"
|
|
503
|
+
ruby examples/check_ip.rb
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
## Requirements
|
|
507
|
+
|
|
508
|
+
- Ruby 3.0 or higher
|
|
509
|
+
- Valid Generator Labs API credentials (account SID and auth token)
|
|
510
|
+
|
|
511
|
+
## Testing
|
|
512
|
+
|
|
513
|
+
```bash
|
|
514
|
+
bundle exec rspec
|
|
515
|
+
```
|
|
516
|
+
|
|
517
|
+
## Security
|
|
518
|
+
|
|
519
|
+
For security best practices and vulnerability reporting, see [SECURITY.md](SECURITY.md).
|
|
520
|
+
|
|
521
|
+
## Release History
|
|
522
|
+
|
|
523
|
+
### v2.0.0 (2026-01-31)
|
|
524
|
+
* Complete rewrite for Generator Labs API v4.0
|
|
525
|
+
* RESTful endpoint design with proper HTTP verbs
|
|
526
|
+
* Updated to use Generator Labs branding (formerly RBLTracker)
|
|
527
|
+
* Automatic `Retry-After` header support on 429 rate limit responses
|
|
528
|
+
* `Response` wrapper (Hash-like) exposes per-request rate limit info (`rate_limit_info`)
|
|
529
|
+
* Added `RateLimitInfo` class with `limit`, `remaining`, and `reset` attributes
|
|
530
|
+
* Automatic retry with exponential backoff on 429 and 5xx errors
|
|
531
|
+
* Webhook signature verification with HMAC-SHA256 and constant-time comparison
|
|
532
|
+
* Automatic pagination via `get_all` for large result sets
|
|
533
|
+
|
|
534
|
+
## License
|
|
535
|
+
|
|
536
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
537
|
+
|
|
538
|
+
## Support
|
|
539
|
+
|
|
540
|
+
- Documentation: https://docs.generatorlabs.com/api/v4/
|
|
541
|
+
- Issues: https://github.com/generator-labs/ruby-sdk/issues
|
|
542
|
+
- Email: support@generatorlabs.com
|
|
543
|
+
|
|
544
|
+
## Contributing
|
|
545
|
+
|
|
546
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|