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 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
+ [![Gem Version](https://badge.fury.io/rb/generatorlabs.svg)](https://badge.fury.io/rb/generatorlabs)
4
+ [![Tests](https://github.com/generator-labs/ruby-sdk/workflows/Tests/badge.svg)](https://github.com/generator-labs/ruby-sdk/actions)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](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.