gophish-ruby 0.1.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.
data/docs/EXAMPLES.md ADDED
@@ -0,0 +1,665 @@
1
+ # Examples
2
+
3
+ This document contains practical examples for common use cases with the Gophish Ruby SDK.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Basic Operations](#basic-operations)
8
+ - [CSV Operations](#csv-operations)
9
+ - [Error Handling](#error-handling)
10
+ - [Advanced Scenarios](#advanced-scenarios)
11
+ - [Production Examples](#production-examples)
12
+
13
+ ## Basic Operations
14
+
15
+ ### Configuration Setup
16
+
17
+ ```ruby
18
+ require 'gophish-ruby'
19
+
20
+ # Standard configuration
21
+ Gophish.configure do |config|
22
+ config.url = "https://gophish.company.com"
23
+ config.api_key = "your-api-key"
24
+ config.verify_ssl = true
25
+ config.debug_output = false
26
+ end
27
+
28
+ # Development configuration with debugging
29
+ Gophish.configure do |config|
30
+ config.url = "https://localhost:3333"
31
+ config.api_key = "dev-api-key"
32
+ config.verify_ssl = false
33
+ config.debug_output = true
34
+ end
35
+ ```
36
+
37
+ ### Creating Groups
38
+
39
+ ```ruby
40
+ # Simple group creation
41
+ group = Gophish::Group.new(
42
+ name: "Engineering Team",
43
+ targets: [
44
+ {
45
+ first_name: "Alice",
46
+ last_name: "Developer",
47
+ email: "alice@company.com",
48
+ position: "Senior Developer"
49
+ },
50
+ {
51
+ first_name: "Bob",
52
+ last_name: "Engineer",
53
+ email: "bob@company.com",
54
+ position: "Software Engineer"
55
+ }
56
+ ]
57
+ )
58
+
59
+ puts group.save ? "✓ Group created" : "✗ Failed: #{group.errors.full_messages}"
60
+ ```
61
+
62
+ ### Retrieving Groups
63
+
64
+ ```ruby
65
+ # Get all groups
66
+ all_groups = Gophish::Group.all
67
+ puts "Total groups: #{all_groups.length}"
68
+
69
+ all_groups.each do |group|
70
+ puts "#{group.id}: #{group.name} (#{group.targets.length} targets)"
71
+ end
72
+
73
+ # Find specific group
74
+ begin
75
+ group = Gophish::Group.find(1)
76
+ puts "Found: #{group.name}"
77
+ rescue StandardError => e
78
+ puts "Group not found: #{e.message}"
79
+ end
80
+ ```
81
+
82
+ ### Updating Groups
83
+
84
+ ```ruby
85
+ # Load and update existing group
86
+ group = Gophish::Group.find(1)
87
+ original_name = group.name
88
+
89
+ group.name = "Updated Engineering Team"
90
+ group.targets << {
91
+ first_name: "Charlie",
92
+ last_name: "New",
93
+ email: "charlie@company.com",
94
+ position: "Junior Developer"
95
+ }
96
+
97
+ if group.save
98
+ puts "✓ Updated group from '#{original_name}' to '#{group.name}'"
99
+ puts " Now has #{group.targets.length} targets"
100
+ else
101
+ puts "✗ Update failed: #{group.errors.full_messages}"
102
+ end
103
+ ```
104
+
105
+ ### Deleting Groups
106
+
107
+ ```ruby
108
+ # Safe deletion with confirmation
109
+ group = Gophish::Group.find(1)
110
+ puts "About to delete group: #{group.name} (#{group.targets.length} targets)"
111
+
112
+ if group.destroy
113
+ puts "✓ Group deleted successfully"
114
+ else
115
+ puts "✗ Failed to delete group"
116
+ end
117
+ ```
118
+
119
+ ## CSV Operations
120
+
121
+ ### Basic CSV Import
122
+
123
+ ```ruby
124
+ # CSV data with proper headers
125
+ csv_data = <<~CSV
126
+ First Name,Last Name,Email,Position
127
+ John,Smith,john.smith@company.com,Manager
128
+ Sarah,Johnson,sarah.johnson@company.com,Developer
129
+ Mike,Brown,mike.brown@company.com,Analyst
130
+ Lisa,Wilson,lisa.wilson@company.com,Designer
131
+ CSV
132
+
133
+ group = Gophish::Group.new(name: "Marketing Department")
134
+ group.import_csv(csv_data)
135
+
136
+ puts "Imported #{group.targets.length} targets"
137
+ puts "First target: #{group.targets.first[:first_name]} #{group.targets.first[:last_name]}"
138
+
139
+ group.save
140
+ ```
141
+
142
+ ### Reading CSV from File
143
+
144
+ ```ruby
145
+ # Read from external CSV file
146
+ def import_from_file(file_path, group_name)
147
+ unless File.exist?(file_path)
148
+ puts "Error: File not found - #{file_path}"
149
+ return nil
150
+ end
151
+
152
+ csv_content = File.read(file_path)
153
+
154
+ group = Gophish::Group.new(name: group_name)
155
+ group.import_csv(csv_content)
156
+
157
+ if group.valid?
158
+ if group.save
159
+ puts "✓ Imported #{group.targets.length} targets from #{file_path}"
160
+ return group
161
+ else
162
+ puts "✗ Save failed: #{group.errors.full_messages}"
163
+ end
164
+ else
165
+ puts "✗ Validation failed: #{group.errors.full_messages}"
166
+ end
167
+
168
+ nil
169
+ end
170
+
171
+ # Usage
172
+ group = import_from_file("employees.csv", "All Employees")
173
+ ```
174
+
175
+ ### CSV with Different Encodings
176
+
177
+ ```ruby
178
+ # Handle different file encodings
179
+ def import_csv_with_encoding(file_path, group_name, encoding = 'UTF-8')
180
+ begin
181
+ csv_content = File.read(file_path, encoding: encoding)
182
+
183
+ # Convert to UTF-8 if needed
184
+ csv_content = csv_content.encode('UTF-8') unless encoding == 'UTF-8'
185
+
186
+ group = Gophish::Group.new(name: group_name)
187
+ group.import_csv(csv_content)
188
+ group.save
189
+
190
+ puts "✓ Imported #{group.targets.length} targets with #{encoding} encoding"
191
+ rescue Encoding::UndefinedConversionError => e
192
+ puts "✗ Encoding error: #{e.message}"
193
+ puts "Try a different encoding (e.g., 'ISO-8859-1', 'Windows-1252')"
194
+ end
195
+ end
196
+
197
+ # Usage for different encodings
198
+ import_csv_with_encoding("employees_utf8.csv", "UTF-8 Group", 'UTF-8')
199
+ import_csv_with_encoding("employees_latin1.csv", "Latin-1 Group", 'ISO-8859-1')
200
+ ```
201
+
202
+ ### Large CSV Processing
203
+
204
+ ```ruby
205
+ require 'csv'
206
+
207
+ # Process large CSV files in chunks
208
+ def import_large_csv(file_path, group_name, chunk_size = 1000)
209
+ puts "Processing large CSV file: #{file_path}"
210
+
211
+ all_targets = []
212
+ row_count = 0
213
+
214
+ CSV.foreach(file_path, headers: true) do |row|
215
+ target = {
216
+ first_name: row['First Name'],
217
+ last_name: row['Last Name'],
218
+ email: row['Email'],
219
+ position: row['Position']
220
+ }
221
+
222
+ all_targets << target
223
+ row_count += 1
224
+
225
+ # Process in chunks
226
+ if all_targets.length >= chunk_size
227
+ puts " Processed #{row_count} rows..."
228
+ # Could save intermediate groups here if needed
229
+ end
230
+ end
231
+
232
+ puts "✓ Read #{row_count} rows total"
233
+
234
+ # Create single group with all targets
235
+ group = Gophish::Group.new(name: group_name, targets: all_targets)
236
+
237
+ if group.valid?
238
+ if group.save
239
+ puts "✓ Successfully imported #{group.targets.length} targets"
240
+ return group
241
+ else
242
+ puts "✗ Save failed: #{group.errors.full_messages}"
243
+ end
244
+ else
245
+ puts "✗ Validation failed: #{group.errors.full_messages}"
246
+ end
247
+
248
+ nil
249
+ end
250
+
251
+ # Usage
252
+ group = import_large_csv("large_employee_list.csv", "All Company Employees")
253
+ ```
254
+
255
+ ## Error Handling
256
+
257
+ ### Comprehensive Error Handling
258
+
259
+ ```ruby
260
+ def robust_group_creation(name, csv_file_path)
261
+ puts "Creating group '#{name}' from #{csv_file_path}"
262
+
263
+ # Step 1: Verify file exists
264
+ unless File.exist?(csv_file_path)
265
+ puts "✗ Error: CSV file not found"
266
+ return false
267
+ end
268
+
269
+ # Step 2: Read file safely
270
+ begin
271
+ csv_content = File.read(csv_file_path)
272
+ rescue Errno::EACCES
273
+ puts "✗ Error: Permission denied reading file"
274
+ return false
275
+ rescue StandardError => e
276
+ puts "✗ Error reading file: #{e.message}"
277
+ return false
278
+ end
279
+
280
+ # Step 3: Create group and import
281
+ group = Gophish::Group.new(name: name)
282
+
283
+ begin
284
+ group.import_csv(csv_content)
285
+ rescue CSV::MalformedCSVError => e
286
+ puts "✗ CSV format error: #{e.message}"
287
+ return false
288
+ rescue StandardError => e
289
+ puts "✗ Import error: #{e.message}"
290
+ return false
291
+ end
292
+
293
+ # Step 4: Validate
294
+ unless group.valid?
295
+ puts "✗ Validation errors:"
296
+ group.errors.full_messages.each { |error| puts " - #{error}" }
297
+ return false
298
+ end
299
+
300
+ # Step 5: Save with API error handling
301
+ begin
302
+ unless group.save
303
+ puts "✗ Save failed (API errors):"
304
+ group.errors.full_messages.each { |error| puts " - #{error}" }
305
+ return false
306
+ end
307
+ rescue StandardError => e
308
+ puts "✗ Network/API error: #{e.message}"
309
+ return false
310
+ end
311
+
312
+ puts "✓ Successfully created group '#{name}' with #{group.targets.length} targets"
313
+ puts " Group ID: #{group.id}"
314
+ true
315
+ end
316
+
317
+ # Usage
318
+ success = robust_group_creation("Sales Team", "sales_team.csv")
319
+ puts success ? "Operation completed" : "Operation failed"
320
+ ```
321
+
322
+ ### Validation Error Details
323
+
324
+ ```ruby
325
+ def diagnose_validation_errors(group)
326
+ return true if group.valid?
327
+
328
+ puts "Validation failed. Details:"
329
+
330
+ # Check each error type
331
+ group.errors.each do |attribute, messages|
332
+ puts " #{attribute.to_s.humanize}:"
333
+ Array(messages).each { |msg| puts " - #{msg}" }
334
+ end
335
+
336
+ # Special handling for targets errors
337
+ if group.errors[:targets].any?
338
+ puts "\nTarget validation details:"
339
+ group.targets.each_with_index do |target, index|
340
+ # Check each required field
341
+ %i[first_name last_name email position].each do |field|
342
+ value = target[field] || target[field.to_s]
343
+ if value.nil? || value.to_s.strip.empty?
344
+ puts " Target #{index}: missing #{field}"
345
+ end
346
+ end
347
+
348
+ # Check email format
349
+ email = target[:email] || target['email']
350
+ if email && !email.match?(/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/)
351
+ puts " Target #{index}: invalid email format '#{email}'"
352
+ end
353
+ end
354
+ end
355
+
356
+ false
357
+ end
358
+
359
+ # Usage
360
+ group = Gophish::Group.new(name: "", targets: [
361
+ { first_name: "John", last_name: "", email: "invalid-email", position: "Manager" }
362
+ ])
363
+
364
+ diagnose_validation_errors(group)
365
+ ```
366
+
367
+ ## Advanced Scenarios
368
+
369
+ ### Batch Operations
370
+
371
+ ```ruby
372
+ # Create multiple groups from directory of CSV files
373
+ def create_groups_from_directory(csv_directory)
374
+ Dir.glob("#{csv_directory}/*.csv").each do |csv_file|
375
+ file_name = File.basename(csv_file, '.csv')
376
+ group_name = file_name.gsub('_', ' ').split.map(&:capitalize).join(' ')
377
+
378
+ puts "Processing #{csv_file} -> '#{group_name}'"
379
+
380
+ csv_content = File.read(csv_file)
381
+ group = Gophish::Group.new(name: group_name)
382
+ group.import_csv(csv_content)
383
+
384
+ if group.valid? && group.save
385
+ puts " ✓ Created group with #{group.targets.length} targets"
386
+ else
387
+ puts " ✗ Failed: #{group.errors.full_messages.join(', ')}"
388
+ end
389
+ end
390
+ end
391
+
392
+ # Usage
393
+ create_groups_from_directory("./csv_files")
394
+ ```
395
+
396
+ ### Group Synchronization
397
+
398
+ ```ruby
399
+ # Sync local CSV with existing Gophish group
400
+ def sync_group_with_csv(group_id, csv_file_path)
401
+ # Load existing group
402
+ begin
403
+ group = Gophish::Group.find(group_id)
404
+ rescue StandardError
405
+ puts "Group #{group_id} not found"
406
+ return false
407
+ end
408
+
409
+ puts "Syncing group '#{group.name}' with #{csv_file_path}"
410
+ puts " Current targets: #{group.targets.length}"
411
+
412
+ # Import new targets from CSV
413
+ csv_content = File.read(csv_file_path)
414
+ temp_group = Gophish::Group.new(name: "temp")
415
+ temp_group.import_csv(csv_content)
416
+
417
+ # Compare and update
418
+ old_emails = group.targets.map { |t| t[:email] || t['email'] }
419
+ new_emails = temp_group.targets.map { |t| t[:email] || t['email'] }
420
+
421
+ added = new_emails - old_emails
422
+ removed = old_emails - new_emails
423
+
424
+ puts " Changes detected:"
425
+ puts " Adding: #{added.length} targets"
426
+ puts " Removing: #{removed.length} targets"
427
+
428
+ # Update the group
429
+ group.targets = temp_group.targets
430
+
431
+ if group.save
432
+ puts " ✓ Sync completed"
433
+ puts " New target count: #{group.targets.length}"
434
+ else
435
+ puts " ✗ Sync failed: #{group.errors.full_messages}"
436
+ end
437
+ end
438
+
439
+ # Usage
440
+ sync_group_with_csv(1, "updated_employees.csv")
441
+ ```
442
+
443
+ ### Change Tracking Example
444
+
445
+ ```ruby
446
+ # Monitor and log changes to groups
447
+ class GroupChangeTracker
448
+ def self.track_changes(group)
449
+ return unless group.persisted?
450
+
451
+ changes = {}
452
+
453
+ if group.attribute_changed?(:name)
454
+ changes[:name] = {
455
+ from: group.attribute_was(:name),
456
+ to: group.name
457
+ }
458
+ end
459
+
460
+ if group.attribute_changed?(:targets)
461
+ old_targets = group.attribute_was(:targets) || []
462
+ new_targets = group.targets || []
463
+
464
+ changes[:targets] = {
465
+ count_change: new_targets.length - old_targets.length,
466
+ old_count: old_targets.length,
467
+ new_count: new_targets.length
468
+ }
469
+ end
470
+
471
+ changes
472
+ end
473
+
474
+ def self.log_and_save(group)
475
+ changes = track_changes(group)
476
+
477
+ if changes.any?
478
+ puts "Saving changes to group '#{group.name}':"
479
+ changes.each do |field, change|
480
+ case field
481
+ when :name
482
+ puts " Name: '#{change[:from]}' → '#{change[:to]}'"
483
+ when :targets
484
+ puts " Targets: #{change[:old_count]} → #{change[:new_count]} (#{change[:count_change]:+d})"
485
+ end
486
+ end
487
+ end
488
+
489
+ result = group.save
490
+ puts result ? " ✓ Changes saved" : " ✗ Save failed"
491
+ result
492
+ end
493
+ end
494
+
495
+ # Usage
496
+ group = Gophish::Group.find(1)
497
+ group.name = "Updated Team Name"
498
+ group.targets << { first_name: "New", last_name: "Person", email: "new@company.com", position: "Intern" }
499
+
500
+ GroupChangeTracker.log_and_save(group)
501
+ ```
502
+
503
+ ## Production Examples
504
+
505
+ ### Configuration with Environment Variables
506
+
507
+ ```ruby
508
+ # config/gophish.rb
509
+ class GophishConfig
510
+ def self.setup
511
+ Gophish.configure do |config|
512
+ config.url = ENV.fetch('GOPHISH_URL') { raise "GOPHISH_URL environment variable required" }
513
+ config.api_key = ENV.fetch('GOPHISH_API_KEY') { raise "GOPHISH_API_KEY environment variable required" }
514
+ config.verify_ssl = ENV.fetch('GOPHISH_VERIFY_SSL', 'true') == 'true'
515
+ config.debug_output = ENV.fetch('GOPHISH_DEBUG', 'false') == 'true'
516
+ end
517
+
518
+ # Test connection
519
+ begin
520
+ Gophish::Group.all
521
+ puts "✓ Gophish connection configured successfully"
522
+ rescue StandardError => e
523
+ puts "✗ Gophish connection failed: #{e.message}"
524
+ raise
525
+ end
526
+ end
527
+ end
528
+
529
+ # Initialize in your application
530
+ GophishConfig.setup
531
+ ```
532
+
533
+ ### Logging and Monitoring
534
+
535
+ ```ruby
536
+ require 'logger'
537
+
538
+ class GophishManager
539
+ def initialize(logger = Logger.new(STDOUT))
540
+ @logger = logger
541
+ end
542
+
543
+ def create_group_with_logging(name, csv_data)
544
+ @logger.info "Starting group creation: '#{name}'"
545
+
546
+ group = Gophish::Group.new(name: name)
547
+
548
+ # Parse CSV with logging
549
+ begin
550
+ group.import_csv(csv_data)
551
+ @logger.info "CSV parsed successfully: #{group.targets.length} targets"
552
+ rescue CSV::MalformedCSVError => e
553
+ @logger.error "CSV parsing failed: #{e.message}"
554
+ return false
555
+ end
556
+
557
+ # Validate with detailed logging
558
+ unless group.valid?
559
+ @logger.error "Validation failed for group '#{name}'"
560
+ group.errors.full_messages.each { |error| @logger.error " - #{error}" }
561
+ return false
562
+ end
563
+
564
+ # Save with timing
565
+ start_time = Time.now
566
+ success = group.save
567
+ duration = Time.now - start_time
568
+
569
+ if success
570
+ @logger.info "Group '#{name}' created successfully in #{duration.round(2)}s (ID: #{group.id})"
571
+ else
572
+ @logger.error "Failed to save group '#{name}' after #{duration.round(2)}s"
573
+ group.errors.full_messages.each { |error| @logger.error " - #{error}" }
574
+ end
575
+
576
+ success
577
+ end
578
+
579
+ def bulk_import(csv_directory)
580
+ @logger.info "Starting bulk import from #{csv_directory}"
581
+
582
+ csv_files = Dir.glob("#{csv_directory}/*.csv")
583
+ @logger.info "Found #{csv_files.length} CSV files to process"
584
+
585
+ results = { success: 0, failed: 0 }
586
+
587
+ csv_files.each_with_index do |csv_file, index|
588
+ file_name = File.basename(csv_file, '.csv')
589
+ group_name = file_name.gsub(/[_-]/, ' ').split.map(&:capitalize).join(' ')
590
+
591
+ @logger.info "[#{index + 1}/#{csv_files.length}] Processing '#{group_name}'"
592
+
593
+ csv_content = File.read(csv_file)
594
+ if create_group_with_logging(group_name, csv_content)
595
+ results[:success] += 1
596
+ else
597
+ results[:failed] += 1
598
+ end
599
+ end
600
+
601
+ @logger.info "Bulk import completed: #{results[:success]} succeeded, #{results[:failed]} failed"
602
+ results
603
+ end
604
+ end
605
+
606
+ # Usage
607
+ logger = Logger.new('gophish_import.log')
608
+ manager = GophishManager.new(logger)
609
+ results = manager.bulk_import('./employee_csvs')
610
+ ```
611
+
612
+ ### Retry Logic for API Calls
613
+
614
+ ```ruby
615
+ class RetryableGophishOperation
616
+ MAX_RETRIES = 3
617
+ RETRY_DELAY = 2
618
+
619
+ def self.with_retry(operation_name)
620
+ retries = 0
621
+
622
+ begin
623
+ yield
624
+ rescue StandardError => e
625
+ retries += 1
626
+
627
+ if retries <= MAX_RETRIES
628
+ puts "#{operation_name} failed (attempt #{retries}): #{e.message}"
629
+ puts "Retrying in #{RETRY_DELAY} seconds..."
630
+ sleep(RETRY_DELAY)
631
+ retry
632
+ else
633
+ puts "#{operation_name} failed after #{MAX_RETRIES} attempts"
634
+ raise
635
+ end
636
+ end
637
+ end
638
+
639
+ def self.create_group_with_retry(name, targets)
640
+ with_retry("Group creation for '#{name}'") do
641
+ group = Gophish::Group.new(name: name, targets: targets)
642
+
643
+ unless group.valid?
644
+ raise StandardError, "Validation failed: #{group.errors.full_messages.join(', ')}"
645
+ end
646
+
647
+ unless group.save
648
+ raise StandardError, "Save failed: #{group.errors.full_messages.join(', ')}"
649
+ end
650
+
651
+ puts "✓ Group '#{name}' created successfully"
652
+ group
653
+ end
654
+ end
655
+ end
656
+
657
+ # Usage
658
+ targets = [
659
+ { first_name: "John", last_name: "Doe", email: "john@example.com", position: "Manager" }
660
+ ]
661
+
662
+ group = RetryableGophishOperation.create_group_with_retry("Test Group", targets)
663
+ ```
664
+
665
+ These examples demonstrate real-world usage patterns and robust error handling for production environments.