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.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +295 -0
- data/CHANGELOG.md +83 -0
- data/CODE_OF_CONDUCT.md +132 -0
- data/LICENSE.txt +21 -0
- data/README.md +340 -0
- data/Rakefile +12 -0
- data/docs/API_REFERENCE.md +512 -0
- data/docs/EXAMPLES.md +665 -0
- data/docs/GETTING_STARTED.md +340 -0
- data/lib/gophish/base.rb +206 -0
- data/lib/gophish/configuration.rb +5 -0
- data/lib/gophish/group.rb +72 -0
- data/lib/gophish/version.rb +5 -0
- data/lib/gophish-ruby.rb +18 -0
- data/sig/gophish/ruby.rbs +6 -0
- metadata +137 -0
@@ -0,0 +1,340 @@
|
|
1
|
+
# Getting Started Guide
|
2
|
+
|
3
|
+
This guide will help you get up and running with the Gophish Ruby SDK quickly.
|
4
|
+
|
5
|
+
## Prerequisites
|
6
|
+
|
7
|
+
- Ruby >= 3.1.0
|
8
|
+
- A running Gophish server
|
9
|
+
- API access credentials for your Gophish instance
|
10
|
+
|
11
|
+
## Installation
|
12
|
+
|
13
|
+
Add the gem to your project:
|
14
|
+
|
15
|
+
```bash
|
16
|
+
# Add to Gemfile
|
17
|
+
echo 'gem "gophish-ruby"' >> Gemfile
|
18
|
+
bundle install
|
19
|
+
|
20
|
+
# Or install directly
|
21
|
+
gem install gophish-ruby
|
22
|
+
```
|
23
|
+
|
24
|
+
## Quick Start
|
25
|
+
|
26
|
+
### 1. Configure the SDK
|
27
|
+
|
28
|
+
First, configure the SDK with your Gophish server details:
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
require 'gophish-ruby'
|
32
|
+
|
33
|
+
Gophish.configure do |config|
|
34
|
+
config.url = "https://your-gophish-server.com"
|
35
|
+
config.api_key = "your-api-key-here"
|
36
|
+
config.verify_ssl = true
|
37
|
+
config.debug_output = false
|
38
|
+
end
|
39
|
+
```
|
40
|
+
|
41
|
+
**Getting Your API Key:**
|
42
|
+
|
43
|
+
1. Log into your Gophish admin panel
|
44
|
+
2. Navigate to Settings → Users
|
45
|
+
3. Click on your user account
|
46
|
+
4. Copy the API Key from the user details
|
47
|
+
|
48
|
+
### 2. Test the Connection
|
49
|
+
|
50
|
+
Verify your configuration works:
|
51
|
+
|
52
|
+
```ruby
|
53
|
+
# Try to fetch existing groups (should return empty array if none exist)
|
54
|
+
begin
|
55
|
+
groups = Gophish::Group.all
|
56
|
+
puts "✓ Connected successfully! Found #{groups.length} groups."
|
57
|
+
rescue StandardError => e
|
58
|
+
puts "✗ Connection failed: #{e.message}"
|
59
|
+
puts "Please check your configuration."
|
60
|
+
end
|
61
|
+
```
|
62
|
+
|
63
|
+
### 3. Create Your First Group
|
64
|
+
|
65
|
+
```ruby
|
66
|
+
# Create a simple group with one target
|
67
|
+
group = Gophish::Group.new(
|
68
|
+
name: "My First Group",
|
69
|
+
targets: [
|
70
|
+
{
|
71
|
+
first_name: "Test",
|
72
|
+
last_name: "User",
|
73
|
+
email: "test@example.com",
|
74
|
+
position: "Tester"
|
75
|
+
}
|
76
|
+
]
|
77
|
+
)
|
78
|
+
|
79
|
+
if group.save
|
80
|
+
puts "✓ Group created successfully with ID: #{group.id}"
|
81
|
+
else
|
82
|
+
puts "✗ Failed to create group:"
|
83
|
+
group.errors.full_messages.each { |error| puts " - #{error}" }
|
84
|
+
end
|
85
|
+
```
|
86
|
+
|
87
|
+
## Common Workflows
|
88
|
+
|
89
|
+
### Importing Targets from CSV
|
90
|
+
|
91
|
+
The most common use case is importing a list of targets from a CSV file:
|
92
|
+
|
93
|
+
```ruby
|
94
|
+
# Prepare your CSV file with headers: First Name,Last Name,Email,Position
|
95
|
+
csv_content = <<~CSV
|
96
|
+
First Name,Last Name,Email,Position
|
97
|
+
John,Doe,john@company.com,Manager
|
98
|
+
Jane,Smith,jane@company.com,Developer
|
99
|
+
Bob,Wilson,bob@company.com,Analyst
|
100
|
+
CSV
|
101
|
+
|
102
|
+
# Create and import
|
103
|
+
group = Gophish::Group.new(name: "Company Employees")
|
104
|
+
group.import_csv(csv_content)
|
105
|
+
|
106
|
+
puts "Imported #{group.targets.length} targets"
|
107
|
+
group.save
|
108
|
+
```
|
109
|
+
|
110
|
+
### Reading from a File
|
111
|
+
|
112
|
+
```ruby
|
113
|
+
# Read CSV from file
|
114
|
+
csv_content = File.read("employees.csv")
|
115
|
+
|
116
|
+
group = Gophish::Group.new(name: "Employees")
|
117
|
+
group.import_csv(csv_content)
|
118
|
+
|
119
|
+
if group.valid?
|
120
|
+
group.save
|
121
|
+
puts "Imported #{group.targets.length} employees"
|
122
|
+
else
|
123
|
+
puts "Validation errors:"
|
124
|
+
group.errors.full_messages.each { |error| puts " - #{error}" }
|
125
|
+
end
|
126
|
+
```
|
127
|
+
|
128
|
+
### Managing Existing Groups
|
129
|
+
|
130
|
+
```ruby
|
131
|
+
# List all groups
|
132
|
+
puts "Existing groups:"
|
133
|
+
Gophish::Group.all.each do |group|
|
134
|
+
puts " #{group.id}: #{group.name} (#{group.targets.length} targets)"
|
135
|
+
end
|
136
|
+
|
137
|
+
# Find and update a specific group
|
138
|
+
group = Gophish::Group.find(1)
|
139
|
+
group.name = "Updated Group Name"
|
140
|
+
|
141
|
+
# Add new targets
|
142
|
+
group.targets << {
|
143
|
+
first_name: "New",
|
144
|
+
last_name: "Employee",
|
145
|
+
email: "new.employee@company.com",
|
146
|
+
position: "Intern"
|
147
|
+
}
|
148
|
+
|
149
|
+
group.save
|
150
|
+
```
|
151
|
+
|
152
|
+
### Deleting Groups
|
153
|
+
|
154
|
+
```ruby
|
155
|
+
# Find and delete a group
|
156
|
+
group = Gophish::Group.find(1)
|
157
|
+
if group.destroy
|
158
|
+
puts "Group deleted successfully"
|
159
|
+
else
|
160
|
+
puts "Failed to delete group"
|
161
|
+
end
|
162
|
+
```
|
163
|
+
|
164
|
+
## Error Handling
|
165
|
+
|
166
|
+
Always handle errors gracefully in production code:
|
167
|
+
|
168
|
+
```ruby
|
169
|
+
def create_group_safely(name, csv_file_path)
|
170
|
+
# Read CSV file
|
171
|
+
begin
|
172
|
+
csv_content = File.read(csv_file_path)
|
173
|
+
rescue Errno::ENOENT
|
174
|
+
puts "Error: CSV file not found at #{csv_file_path}"
|
175
|
+
return false
|
176
|
+
end
|
177
|
+
|
178
|
+
# Create group
|
179
|
+
group = Gophish::Group.new(name: name)
|
180
|
+
|
181
|
+
# Import CSV
|
182
|
+
begin
|
183
|
+
group.import_csv(csv_content)
|
184
|
+
rescue CSV::MalformedCSVError => e
|
185
|
+
puts "Error: Invalid CSV format - #{e.message}"
|
186
|
+
return false
|
187
|
+
end
|
188
|
+
|
189
|
+
# Validate
|
190
|
+
unless group.valid?
|
191
|
+
puts "Validation errors:"
|
192
|
+
group.errors.full_messages.each { |error| puts " - #{error}" }
|
193
|
+
return false
|
194
|
+
end
|
195
|
+
|
196
|
+
# Save
|
197
|
+
unless group.save
|
198
|
+
puts "Save failed:"
|
199
|
+
group.errors.full_messages.each { |error| puts " - #{error}" }
|
200
|
+
return false
|
201
|
+
end
|
202
|
+
|
203
|
+
puts "✓ Group '#{name}' created successfully with #{group.targets.length} targets"
|
204
|
+
true
|
205
|
+
end
|
206
|
+
|
207
|
+
# Usage
|
208
|
+
create_group_safely("Sales Team", "sales_team.csv")
|
209
|
+
```
|
210
|
+
|
211
|
+
## Development Setup
|
212
|
+
|
213
|
+
For development and testing, you might want to use different settings:
|
214
|
+
|
215
|
+
```ruby
|
216
|
+
# Development configuration
|
217
|
+
if ENV['RAILS_ENV'] == 'development' || ENV['RUBY_ENV'] == 'development'
|
218
|
+
Gophish.configure do |config|
|
219
|
+
config.url = "https://localhost:3333"
|
220
|
+
config.api_key = "dev-api-key"
|
221
|
+
config.verify_ssl = false # For self-signed certificates
|
222
|
+
config.debug_output = true # See HTTP requests
|
223
|
+
end
|
224
|
+
else
|
225
|
+
# Production configuration
|
226
|
+
Gophish.configure do |config|
|
227
|
+
config.url = ENV['GOPHISH_URL']
|
228
|
+
config.api_key = ENV['GOPHISH_API_KEY']
|
229
|
+
config.verify_ssl = true
|
230
|
+
config.debug_output = false
|
231
|
+
end
|
232
|
+
end
|
233
|
+
```
|
234
|
+
|
235
|
+
## Validation and Data Quality
|
236
|
+
|
237
|
+
The SDK provides comprehensive validation:
|
238
|
+
|
239
|
+
### Required Fields
|
240
|
+
|
241
|
+
All these fields are required for each target:
|
242
|
+
|
243
|
+
- `first_name`
|
244
|
+
- `last_name`
|
245
|
+
- `email` (must be valid format)
|
246
|
+
- `position`
|
247
|
+
|
248
|
+
### Email Validation
|
249
|
+
|
250
|
+
The SDK validates email format using a regex pattern:
|
251
|
+
|
252
|
+
```ruby
|
253
|
+
# Valid emails
|
254
|
+
"user@example.com"
|
255
|
+
"first.last@company.co.uk"
|
256
|
+
"user+tag@domain.org"
|
257
|
+
|
258
|
+
# Invalid emails (will cause validation errors)
|
259
|
+
"invalid-email"
|
260
|
+
"@domain.com"
|
261
|
+
"user@"
|
262
|
+
""
|
263
|
+
```
|
264
|
+
|
265
|
+
### Custom Validation
|
266
|
+
|
267
|
+
You can check validation before saving:
|
268
|
+
|
269
|
+
```ruby
|
270
|
+
group = Gophish::Group.new(name: "Test", targets: [...])
|
271
|
+
|
272
|
+
if group.valid?
|
273
|
+
puts "✓ All validations passed"
|
274
|
+
group.save
|
275
|
+
else
|
276
|
+
puts "✗ Validation failed:"
|
277
|
+
|
278
|
+
# Show all errors
|
279
|
+
group.errors.full_messages.each { |error| puts " - #{error}" }
|
280
|
+
|
281
|
+
# Check specific field errors
|
282
|
+
if group.errors[:name].any?
|
283
|
+
puts "Name issues: #{group.errors[:name].join(', ')}"
|
284
|
+
end
|
285
|
+
|
286
|
+
if group.errors[:targets].any?
|
287
|
+
puts "Target issues: #{group.errors[:targets].join(', ')}"
|
288
|
+
end
|
289
|
+
end
|
290
|
+
```
|
291
|
+
|
292
|
+
## Next Steps
|
293
|
+
|
294
|
+
Now that you have the basics:
|
295
|
+
|
296
|
+
1. **Read the [API Reference](API_REFERENCE.md)** for detailed method documentation
|
297
|
+
2. **Check out [Examples](EXAMPLES.md)** for more complex scenarios
|
298
|
+
3. **Set up proper error handling** for production use
|
299
|
+
4. **Consider security** - never log API keys or sensitive data
|
300
|
+
|
301
|
+
## Troubleshooting
|
302
|
+
|
303
|
+
### Common Issues
|
304
|
+
|
305
|
+
**"Connection refused" errors:**
|
306
|
+
|
307
|
+
- Check that your Gophish server is running
|
308
|
+
- Verify the URL is correct (include protocol: https://)
|
309
|
+
- Ensure the port is correct
|
310
|
+
|
311
|
+
**"SSL certificate verify failed" errors:**
|
312
|
+
|
313
|
+
- Set `config.verify_ssl = false` for self-signed certificates
|
314
|
+
- Or properly configure SSL certificates on your Gophish server
|
315
|
+
|
316
|
+
**"Invalid API key" errors:**
|
317
|
+
|
318
|
+
- Double-check your API key in the Gophish admin panel
|
319
|
+
- Ensure there are no extra spaces or characters
|
320
|
+
|
321
|
+
**CSV import fails:**
|
322
|
+
|
323
|
+
- Verify CSV headers exactly match: "First Name", "Last Name", "Email", "Position"
|
324
|
+
- Check for malformed CSV data (unescaped quotes, etc.)
|
325
|
+
- Ensure all required fields are present for each row
|
326
|
+
|
327
|
+
**Validation errors:**
|
328
|
+
|
329
|
+
- Check that all required fields are present
|
330
|
+
- Verify email addresses have valid format
|
331
|
+
- Ensure group name is not empty
|
332
|
+
|
333
|
+
### Getting Help
|
334
|
+
|
335
|
+
If you encounter issues:
|
336
|
+
|
337
|
+
1. Check the [API Reference](API_REFERENCE.md) for detailed documentation
|
338
|
+
2. Look at [Examples](EXAMPLES.md) for working code samples
|
339
|
+
3. Open an issue on [GitHub](https://github.com/EliSebastian/gophish-ruby/issues)
|
340
|
+
4. Consult the [Gophish documentation](https://docs.getgophish.com/) for server-side issues
|
data/lib/gophish/base.rb
ADDED
@@ -0,0 +1,206 @@
|
|
1
|
+
require 'httparty'
|
2
|
+
require 'active_support'
|
3
|
+
require 'active_model'
|
4
|
+
require 'active_record'
|
5
|
+
require 'json'
|
6
|
+
require 'uri'
|
7
|
+
require_relative 'configuration'
|
8
|
+
|
9
|
+
module Gophish
|
10
|
+
class Base
|
11
|
+
include HTTParty
|
12
|
+
include ActiveSupport::Inflector
|
13
|
+
include ActiveModel::Model
|
14
|
+
include ActiveModel::Attributes
|
15
|
+
include ActiveModel::Validations
|
16
|
+
include ActiveRecord::Callbacks
|
17
|
+
|
18
|
+
def initialize(attributes = {})
|
19
|
+
@persisted = false
|
20
|
+
@changed_attributes = {}
|
21
|
+
super(attributes)
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.configuration
|
25
|
+
@configuration ||= {
|
26
|
+
base_uri: "#{Gophish.configuration.url}/api",
|
27
|
+
headers: { 'Authorization' => Gophish.configuration.api_key },
|
28
|
+
verify: Gophish.configuration.verify_ssl,
|
29
|
+
debug_output: Gophish.configuration.debug_output ? STDOUT : nil
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.get(path, options = {})
|
34
|
+
options = configuration.merge options
|
35
|
+
options[:headers] = (options[:headers] || {}).merge(configuration[:headers])
|
36
|
+
super(path, options)
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.post(path, options = {})
|
40
|
+
options = configuration.merge options
|
41
|
+
options[:headers] = (options[:headers] || {}).merge(configuration[:headers])
|
42
|
+
super(path, options)
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.put(path, options = {})
|
46
|
+
options = configuration.merge options
|
47
|
+
options[:headers] = (options[:headers] || {}).merge(configuration[:headers])
|
48
|
+
super(path, options)
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.delete(path, options = {})
|
52
|
+
options = configuration.merge options
|
53
|
+
options[:headers] = (options[:headers] || {}).merge(configuration[:headers])
|
54
|
+
super(path, options)
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.resource_name
|
58
|
+
name.split('::').last.underscore.dasherize
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.resource_path
|
62
|
+
"/#{resource_name.pluralize}"
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.all
|
66
|
+
response = get "#{resource_path}/"
|
67
|
+
if response.response.code == '200'
|
68
|
+
response.parsed_response.map do |data|
|
69
|
+
instance = new filter_attributes(data)
|
70
|
+
instance.instance_variable_set :@persisted, true
|
71
|
+
instance
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def self.find(id)
|
77
|
+
response = get "#{resource_path}/#{id}"
|
78
|
+
raise StandardError, "Resource not found with id: #{id}" if response.response.code != '200'
|
79
|
+
|
80
|
+
data = JSON.parse response.body
|
81
|
+
instance = new filter_attributes(data)
|
82
|
+
instance.instance_variable_set :@persisted, true
|
83
|
+
instance
|
84
|
+
end
|
85
|
+
|
86
|
+
def save
|
87
|
+
return false unless valid?
|
88
|
+
|
89
|
+
return update_record if persisted?
|
90
|
+
|
91
|
+
create_record
|
92
|
+
end
|
93
|
+
|
94
|
+
def update_attributes(attributes)
|
95
|
+
attributes.each { |key, value| send "#{key}=", value if respond_to? "#{key}=" }
|
96
|
+
save
|
97
|
+
end
|
98
|
+
|
99
|
+
def destroy
|
100
|
+
return false unless persisted?
|
101
|
+
return false if id.nil?
|
102
|
+
|
103
|
+
response = self.class.delete "#{self.class.resource_path}/#{id}"
|
104
|
+
return handle_error_response response unless response.success?
|
105
|
+
|
106
|
+
@persisted = false
|
107
|
+
freeze
|
108
|
+
true
|
109
|
+
end
|
110
|
+
|
111
|
+
def persisted?
|
112
|
+
@persisted && !id.nil?
|
113
|
+
end
|
114
|
+
|
115
|
+
def new_record?
|
116
|
+
!persisted?
|
117
|
+
end
|
118
|
+
|
119
|
+
private
|
120
|
+
|
121
|
+
def update_attributes_from_response(parsed_response)
|
122
|
+
return unless parsed_response.is_a? Hash
|
123
|
+
|
124
|
+
parsed_response.each do |key, value|
|
125
|
+
send "#{key}=", value if respond_to? "#{key}="
|
126
|
+
end
|
127
|
+
@persisted = true
|
128
|
+
@changed_attributes.clear
|
129
|
+
end
|
130
|
+
|
131
|
+
def handle_error_response(response)
|
132
|
+
errors.add :base, response.parsed_response['message'] if response.parsed_response['success'] == false
|
133
|
+
false
|
134
|
+
end
|
135
|
+
|
136
|
+
private
|
137
|
+
|
138
|
+
def create_record
|
139
|
+
response = self.class.post "#{self.class.resource_path}/", request_options(body_for_create)
|
140
|
+
return handle_error_response response unless response.success?
|
141
|
+
|
142
|
+
update_attributes_from_response response.parsed_response
|
143
|
+
true
|
144
|
+
end
|
145
|
+
|
146
|
+
def update_record
|
147
|
+
return false if id.nil?
|
148
|
+
return true if @changed_attributes.empty?
|
149
|
+
|
150
|
+
response = self.class.put "#{self.class.resource_path}/#{id}/", request_options(body_for_update)
|
151
|
+
return handle_error_response response unless response.success?
|
152
|
+
|
153
|
+
update_attributes_from_response response.parsed_response
|
154
|
+
true
|
155
|
+
end
|
156
|
+
|
157
|
+
def request_options(body)
|
158
|
+
{ body: body.to_json, headers: { 'Content-Type' => 'application/json' } }
|
159
|
+
end
|
160
|
+
|
161
|
+
def self.filter_attributes(data)
|
162
|
+
return data unless data.is_a? Hash
|
163
|
+
|
164
|
+
defined_attributes = attribute_names.map(&:to_s)
|
165
|
+
|
166
|
+
filtered_data = {}
|
167
|
+
data.each do |key, value|
|
168
|
+
snake_case_key = key.to_s.underscore
|
169
|
+
filtered_data[snake_case_key] = value if defined_attributes.include? snake_case_key
|
170
|
+
end
|
171
|
+
|
172
|
+
filtered_data
|
173
|
+
end
|
174
|
+
|
175
|
+
def body_for_create
|
176
|
+
raise NotImplementedError, 'You must implement the body_for_create method in your subclass'
|
177
|
+
end
|
178
|
+
|
179
|
+
def body_for_update
|
180
|
+
body_for_create
|
181
|
+
end
|
182
|
+
|
183
|
+
def attribute_changed?(attribute)
|
184
|
+
@changed_attributes.key? attribute.to_s
|
185
|
+
end
|
186
|
+
|
187
|
+
def changed_attributes
|
188
|
+
@changed_attributes.keys
|
189
|
+
end
|
190
|
+
|
191
|
+
def attribute_was(attribute)
|
192
|
+
@changed_attributes[attribute.to_s]
|
193
|
+
end
|
194
|
+
|
195
|
+
def []=(attribute, value)
|
196
|
+
attribute_str = attribute.to_s
|
197
|
+
current_value = send attribute if respond_to? attribute
|
198
|
+
|
199
|
+
unless current_value == value
|
200
|
+
@changed_attributes[attribute_str] = current_value
|
201
|
+
end
|
202
|
+
|
203
|
+
send "#{attribute}=", value if respond_to? "#{attribute}="
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require_relative 'base'
|
2
|
+
require 'active_support/core_ext/object/blank'
|
3
|
+
require 'csv'
|
4
|
+
|
5
|
+
module Gophish
|
6
|
+
class Group < Base
|
7
|
+
attribute :id, :integer
|
8
|
+
attribute :name, :string
|
9
|
+
attribute :modified_date, :string
|
10
|
+
attribute :targets
|
11
|
+
|
12
|
+
validates :name, presence: true
|
13
|
+
validates :targets, presence: true
|
14
|
+
validate :validate_targets_structure
|
15
|
+
|
16
|
+
def body_for_create
|
17
|
+
{ name:, targets: }
|
18
|
+
end
|
19
|
+
|
20
|
+
def import_csv(csv_data)
|
21
|
+
targets_array = CSV.parse(csv_data, headers: true).map { |row| parse_csv_row row }
|
22
|
+
self.targets = targets_array
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def validate_targets_structure
|
28
|
+
return if targets.blank?
|
29
|
+
return errors.add :targets, 'must be an array' unless targets.is_a? Array
|
30
|
+
|
31
|
+
targets.each_with_index { |target, index| validate_target target, index }
|
32
|
+
end
|
33
|
+
|
34
|
+
def parse_csv_row(row)
|
35
|
+
{
|
36
|
+
first_name: row['First Name'],
|
37
|
+
last_name: row['Last Name'],
|
38
|
+
email: row['Email'],
|
39
|
+
position: row['Position']
|
40
|
+
}
|
41
|
+
end
|
42
|
+
|
43
|
+
def validate_target(target, index)
|
44
|
+
return errors.add :targets, "item at index #{index} must be a hash" unless target.is_a? Hash
|
45
|
+
|
46
|
+
validate_target_email target, index
|
47
|
+
validate_required_field target, index, :position
|
48
|
+
validate_required_field target, index, :first_name
|
49
|
+
validate_required_field target, index, :last_name
|
50
|
+
end
|
51
|
+
|
52
|
+
def validate_target_email(target, index)
|
53
|
+
email = target[:email] || target['email']
|
54
|
+
if email.blank?
|
55
|
+
errors.add :targets, "item at index #{index} must have an email"
|
56
|
+
elsif !valid_email_format?(email)
|
57
|
+
errors.add :targets, "item at index #{index} must have a valid email format"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def validate_required_field(target, index, field)
|
62
|
+
value = target[field] || target[field.to_s]
|
63
|
+
return unless value.blank?
|
64
|
+
|
65
|
+
errors.add :targets, "item at index #{index} must have a #{field}"
|
66
|
+
end
|
67
|
+
|
68
|
+
def valid_email_format?(email)
|
69
|
+
email.match?(/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
data/lib/gophish-ruby.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require_relative 'gophish/version'
|
2
|
+
require_relative 'gophish/configuration'
|
3
|
+
require_relative 'gophish/base'
|
4
|
+
require_relative 'gophish/group'
|
5
|
+
|
6
|
+
module Gophish
|
7
|
+
class << self
|
8
|
+
attr_writer :configuration
|
9
|
+
|
10
|
+
def configuration
|
11
|
+
@configuration ||= Configuration.new
|
12
|
+
end
|
13
|
+
|
14
|
+
def configure
|
15
|
+
yield configuration
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|