nexpose_ticketing 1.4.2 → 1.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +25 -7
- data/bin/nexpose_ticketing +16 -12
- data/lib/nexpose_ticketing/config/encryption.config +20 -0
- data/lib/nexpose_ticketing/config/ticket_service.config +5 -0
- data/lib/nexpose_ticketing/helpers/base_helper.rb +1 -1
- data/lib/nexpose_ticketing/helpers/jira_helper.rb +1 -1
- data/lib/nexpose_ticketing/helpers/remedy_helper.rb +1 -1
- data/lib/nexpose_ticketing/helpers/servicedesk_helper.rb +1 -1
- data/lib/nexpose_ticketing/helpers/servicenow_helper.rb +1 -1
- data/lib/nexpose_ticketing/modes/base_mode.rb +1 -1
- data/lib/nexpose_ticketing/ticket_repository.rb +1 -1
- data/lib/nexpose_ticketing/ticket_service.rb +5 -8
- data/lib/nexpose_ticketing/utilities/config_parser.rb +140 -0
- data/lib/nexpose_ticketing/{nx_logger.rb → utilities/nx_logger.rb} +0 -0
- data/lib/nexpose_ticketing/version.rb +1 -1
- metadata +26 -5
- data/Gemfile.lock +0 -69
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d1458f962f3e9bd3d18d9d2286438b3525d41811
|
4
|
+
data.tar.gz: 8eb1e53fe25c1562148ca9c83d04d79771cf68df
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c81d2388596d93be2da301efafbbb96d9baf84a690cb5b75208839749ced211e690b477410b1a09bc0101f077584f138f5eb554e597ce18c09b30c2648f4ea2c
|
7
|
+
data.tar.gz: d1d3a1394b6de2bc5627f2ee0520dc61369f2ced8dbaa4ac37c89c73e53c340b4c85d911797477bf344f66562b2443eda2dd293c8e03e6a8c442b024c2c4f9ab
|
data/README.md
CHANGED
@@ -49,20 +49,33 @@ Please refer to your particular Ruby documentation for actual installation folde
|
|
49
49
|
A logger is also implemented by default, and the log can be found under `<install_location>/lib/nexpose_ticketing/logs/`
|
50
50
|
Please refer to the log file in case of an error.
|
51
51
|
|
52
|
+
### Encryption Settings
|
53
|
+
|
54
|
+
The usernames and passwords within the configuration files are automatically encrypted when the integration runs. The key and IV files used during encryption/decryption are saved within the config folder by default.
|
55
|
+
|
56
|
+
#### Setting Custom Locations for Encryption Files
|
57
|
+
|
58
|
+
To set custom locations for the key and IV files, update the following values within the encryption.config file:
|
59
|
+
|
60
|
+
- key_filename - The absolute path to where the key file will be created.
|
61
|
+
- iv_file - The absolute path to where the IV file will be created.
|
62
|
+
|
63
|
+
To set a custom path after the integration has already executed, the files must be moved to the new location manually.
|
64
|
+
|
52
65
|
## Contributions
|
53
66
|
|
54
67
|
To develop your own implementation for Ticketing service 'foo':
|
55
68
|
|
56
69
|
1. Create a helper class that implements the following methods:
|
57
|
-
|
58
|
-
|
59
|
-
|
70
|
+
* Initialize: This is the constructor that will take the implementation options and the service options. It should inherit from the base_helper class.
|
71
|
+
* create_ticket(tickets) - This method should implement the transport class for the 'foo' service (https, smtp, SOAP, etc).
|
72
|
+
* prepare_create_tickets(vulnerability_list, nexpose_identifier_id) - This method will take the vulnerability_list in CSV format and transform it into 'foo' accepted data (JSON, XML, etc). The implemented helpers group data into a single ticket according to the current ticketing mode: Per IP in IP mode and per vulnerability in Vulnerability mode.
|
60
73
|
|
61
74
|
2. For full functionality (updating and closing tickets), also implement the following methods:
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
75
|
+
* update_tickets(tickets) - This method should implement the transport class for the 'foo' service (https, smtp, SOAP, etc), to send updated ticket descriptions to the service for specific existing tickets.
|
76
|
+
* prepare_update_tickets(vulnerability_list, nexpose_identifier_id) - This method will take the vulnerability_list in CSV format and transform it into 'foo' accepted data (JSON, XML, etc) for updating exisiting tickets.
|
77
|
+
* close_tickets(tickets) - This method should implement the transport class for the 'foo' service (https, smtp, SOAP, etc), to send closure messages to the service for a specific exisiting ticket.
|
78
|
+
* prepare_close_tickets(vulnerability_list, nexpose_identifier_id) - This method will take the vulnerability_list in CSV format and transform it into 'foo' accepted data (JSON, XML, etc) containing information about the tickets to close.
|
66
79
|
|
67
80
|
3. A configuration file will be needed in the config folder for service specific options. This is loaded at the start of operation. Please refer to the existing configuration files, as certain options are common to all services.
|
68
81
|
|
@@ -77,6 +90,11 @@ We welcome contributions to this package. We ask only that pull requests and pat
|
|
77
90
|
|
78
91
|
## Changelog
|
79
92
|
|
93
|
+
### 1.5.0
|
94
|
+
16-05-17
|
95
|
+
Added an encryption configuration file.
|
96
|
+
Usernames and passwords within the configuration files are now encrypted when the application runs.
|
97
|
+
|
80
98
|
### 1.4.2
|
81
99
|
10-05-17
|
82
100
|
|
data/bin/nexpose_ticketing
CHANGED
@@ -1,13 +1,14 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
require 'yaml'
|
3
3
|
require 'nexpose_ticketing'
|
4
|
-
require 'nexpose_ticketing/nx_logger'
|
4
|
+
require 'nexpose_ticketing/utilities/nx_logger'
|
5
5
|
require 'nexpose_ticketing/version'
|
6
6
|
require 'optparse'
|
7
|
+
require_relative '../lib/nexpose_ticketing/utilities/config_parser'
|
7
8
|
|
8
9
|
options = {}
|
9
10
|
OptionParser.new do |opts|
|
10
|
-
opts.banner =
|
11
|
+
opts.banner = 'Usage: nexpose_ticketing [service name]'
|
11
12
|
end.parse!
|
12
13
|
|
13
14
|
if ARGV.count == 0
|
@@ -16,20 +17,23 @@ if ARGV.count == 0
|
|
16
17
|
end
|
17
18
|
|
18
19
|
system = ARGV.first
|
19
|
-
|
20
|
-
|
20
|
+
config_dir = File.join(File.dirname(__FILE__),
|
21
|
+
'../lib/nexpose_ticketing/config/')
|
22
|
+
config_path = File.join(config_dir, "#{system}.config")
|
23
|
+
service_config_path = File.join(config_dir, 'ticket_service.config')
|
21
24
|
|
22
25
|
unless File.exists? config_path
|
23
26
|
puts "Configuration file could not be found at #{config_path}"
|
24
27
|
exit -1
|
25
28
|
end
|
26
29
|
|
27
|
-
#
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
30
|
+
# We need to load the general config to get the encryption details location
|
31
|
+
# This is because the ticket gem uses two configs at a time
|
32
|
+
ticket_service = YAML.load_file(service_config_path)
|
33
|
+
enc_path = ticket_service[:encryption_options][:directory]
|
34
|
+
|
35
|
+
# Now we can load the config as normal
|
36
|
+
service_options = ConfigParser.get_config(config_path, enc_path)
|
33
37
|
|
34
38
|
log = NexposeTicketing::NxLogger.instance
|
35
39
|
log.setup_statistics_collection(service_options[:vendor],
|
@@ -37,9 +41,9 @@ log.setup_statistics_collection(service_options[:vendor],
|
|
37
41
|
NexposeTicketing::VERSION)
|
38
42
|
log.setup_logging(true, 'info')
|
39
43
|
|
40
|
-
current_encoding = Encoding.default_external=Encoding.find(
|
44
|
+
current_encoding = Encoding.default_external=Encoding.find('UTF-8')
|
41
45
|
|
42
46
|
log.log_message("Current Encoding set to: #{current_encoding}")
|
43
47
|
|
44
|
-
# Initialize Ticket Service
|
48
|
+
# Initialize Ticket Service.
|
45
49
|
NexposeTicketing.start(service_options)
|
@@ -0,0 +1,20 @@
|
|
1
|
+
#
|
2
|
+
# Symmetric Encryption for Ruby
|
3
|
+
#
|
4
|
+
---
|
5
|
+
production:
|
6
|
+
# Since the encryption key must NOT be stored along with the
|
7
|
+
# source code, only store the key encryption key here.
|
8
|
+
private_rsa_key:
|
9
|
+
|
10
|
+
# List Symmetric Key Ciphers in the order of current / newest first
|
11
|
+
ciphers:
|
12
|
+
-
|
13
|
+
# Name of the file containing the encrypted key and iv.
|
14
|
+
key_filename: <absolute/path/to/filename>.key
|
15
|
+
iv_filename: <absolute/path/to/filename>.iv
|
16
|
+
|
17
|
+
cipher: aes-256-cbc
|
18
|
+
encoding: base64strict
|
19
|
+
version: 1
|
20
|
+
always_add_header: true
|
@@ -5,7 +5,7 @@ module NexposeTicketing
|
|
5
5
|
require 'nexpose'
|
6
6
|
require 'nexpose_ticketing/queries'
|
7
7
|
require 'nexpose_ticketing/report_helper'
|
8
|
-
require 'nexpose_ticketing/nx_logger'
|
8
|
+
require 'nexpose_ticketing/utilities/nx_logger'
|
9
9
|
require 'nexpose_ticketing/version'
|
10
10
|
|
11
11
|
API_VERSION = '1.2.0'
|
@@ -53,22 +53,19 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
53
53
|
require 'fileutils'
|
54
54
|
require 'nexpose_ticketing/ticket_repository'
|
55
55
|
require 'nexpose_ticketing'
|
56
|
-
require 'nexpose_ticketing/nx_logger'
|
56
|
+
require 'nexpose_ticketing/utilities/nx_logger'
|
57
57
|
require 'nexpose_ticketing/version'
|
58
58
|
require 'nexpose_ticketing/store'
|
59
|
+
require_relative './utilities/config_parser'
|
59
60
|
|
60
|
-
TICKET_SERVICE_CONFIG_PATH = File.join(File.dirname(__FILE__),
|
61
|
+
TICKET_SERVICE_CONFIG_PATH = File.join(File.dirname(__FILE__),
|
62
|
+
'/config/ticket_service.config')
|
61
63
|
LOGGER_FILE = File.join(File.dirname(__FILE__), '/logs/ticket_service.log')
|
62
64
|
|
63
65
|
attr_accessor :helper_data, :nexpose_data, :options, :ticket_repository, :first_time
|
64
66
|
|
65
67
|
def setup(helper_data)
|
66
|
-
|
67
|
-
service_data = begin
|
68
|
-
YAML.load_file(TICKET_SERVICE_CONFIG_PATH)
|
69
|
-
rescue ArgumentError => e
|
70
|
-
raise "Could not parse YAML #{TICKET_SERVICE_CONFIG_PATH} : #{e.message}"
|
71
|
-
end
|
68
|
+
service_data = ConfigParser.get_config(TICKET_SERVICE_CONFIG_PATH)
|
72
69
|
|
73
70
|
@helper_data = helper_data
|
74
71
|
@nexpose_data = service_data[:nexpose_data]
|
@@ -0,0 +1,140 @@
|
|
1
|
+
require 'erb'
|
2
|
+
require 'yaml'
|
3
|
+
require 'fileutils'
|
4
|
+
require 'symmetric-encryption'
|
5
|
+
|
6
|
+
class ConfigParser
|
7
|
+
ENCRYPTED_FORMAT = '<%%= SymmetricEncryption.try_decrypt "%s" %%>'
|
8
|
+
PLACEHOLDER = '<absolute/path/to/filename>'
|
9
|
+
# The environment to use, defined within the encryption config
|
10
|
+
STANZA = 'production'
|
11
|
+
# The line width of the YAML file before line-wrapping occurs
|
12
|
+
WIDTH = 120
|
13
|
+
|
14
|
+
# Encrypts a configuration file and returns the unencrypted hash.
|
15
|
+
def self.get_config(config_path, enc_path=nil)
|
16
|
+
# Try to load a path from the provided config
|
17
|
+
custom_enc_path = get_enc_directory(config_path)
|
18
|
+
enc_path = custom_enc_path unless custom_enc_path.nil?
|
19
|
+
|
20
|
+
enc_path = File.expand_path(enc_path, __FILE__)
|
21
|
+
config_path = File.expand_path(config_path, __FILE__)
|
22
|
+
|
23
|
+
generate_keys(enc_path, config_path)
|
24
|
+
encrypt_config(enc_path, config_path)
|
25
|
+
decrypt_config(enc_path, config_path)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Writes the YAML to file with custom formatting options
|
29
|
+
def self.save_config(config_details, config_path)
|
30
|
+
yaml = config_details.to_yaml(line_width: WIDTH)
|
31
|
+
File.open(config_path, 'w') {|f| f.write yaml }
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.encrypt_field(value)
|
35
|
+
encrypted_value = SymmetricEncryption.encrypt value
|
36
|
+
ENCRYPTED_FORMAT % encrypted_value
|
37
|
+
end
|
38
|
+
|
39
|
+
# Retrieves the custom directory of the encryption config
|
40
|
+
def self.get_enc_directory(config_path)
|
41
|
+
settings = YAML.load_file(config_path)
|
42
|
+
return nil if settings[:encryption_options].nil?
|
43
|
+
|
44
|
+
enc_dir = settings[:encryption_options][:directory]
|
45
|
+
return nil if (enc_dir.nil? || enc_dir == '')
|
46
|
+
|
47
|
+
File.expand_path(enc_dir, __FILE__)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Generates the RSA key, associated files and directories.
|
51
|
+
def self.generate_keys(enc_path, config_path)
|
52
|
+
settings = YAML.load_file(enc_path)
|
53
|
+
key = settings[STANZA]['private_rsa_key']
|
54
|
+
|
55
|
+
# Recognise an existing key
|
56
|
+
return unless (key.nil? || key == '')
|
57
|
+
|
58
|
+
# Generate a new RSA key and store the details
|
59
|
+
new_rsa_key = SymmetricEncryption::KeyEncryptionKey.generate
|
60
|
+
settings[STANZA]['private_rsa_key'] = new_rsa_key
|
61
|
+
save_config(settings, enc_path)
|
62
|
+
|
63
|
+
# Populate the placeholder values within the config
|
64
|
+
populate_ciphers(enc_path, config_path)
|
65
|
+
|
66
|
+
# Need to create a folder (specified by the user) to store the key files
|
67
|
+
dir = File.dirname(settings[STANZA]['ciphers'].first['key_filename'])
|
68
|
+
|
69
|
+
begin
|
70
|
+
unless File.directory?(dir) || PLACEHOLDER.include?(dir)
|
71
|
+
puts "Creating folder: #{dir}"
|
72
|
+
FileUtils::mkdir_p dir
|
73
|
+
end
|
74
|
+
rescue Exception => e
|
75
|
+
msg = "Unable to create the folders used to store encryption details.\n"\
|
76
|
+
'Please ensure the user has permissions to create folders in the ' \
|
77
|
+
"path specified in the encryption config: #{enc_path}\n"
|
78
|
+
handle_error(msg, e)
|
79
|
+
end
|
80
|
+
|
81
|
+
SymmetricEncryption.generate_symmetric_key_files(enc_path, STANZA)
|
82
|
+
end
|
83
|
+
|
84
|
+
# Replace placeholder values for the key and iv file paths,
|
85
|
+
# placing them in the config folder by default.
|
86
|
+
def self.populate_ciphers(enc_path, config_path)
|
87
|
+
settings = YAML.load_file(enc_path)
|
88
|
+
ciphers = settings[STANZA]['ciphers'].first
|
89
|
+
config_folder = File.dirname(config_path)
|
90
|
+
config_name = File.basename(config_path, File.extname(config_path))
|
91
|
+
|
92
|
+
%w(key iv).each do |file|
|
93
|
+
label = "#{file}_filename"
|
94
|
+
file_path = ciphers[label]
|
95
|
+
next unless file_path.include? PLACEHOLDER
|
96
|
+
|
97
|
+
filename = ".#{config_name}.#{file}"
|
98
|
+
ciphers[label] = File.join(config_folder, filename)
|
99
|
+
end
|
100
|
+
|
101
|
+
save_config(settings, enc_path)
|
102
|
+
end
|
103
|
+
|
104
|
+
def self.encrypt_config(enc_path, config_path)
|
105
|
+
SymmetricEncryption.load!(enc_path, STANZA)
|
106
|
+
|
107
|
+
# Read the config in as an array of strings
|
108
|
+
f = File.open(config_path)
|
109
|
+
config_lines = f.readlines
|
110
|
+
f.close
|
111
|
+
|
112
|
+
# Define the regex that can find relevant fields
|
113
|
+
regex = /^(?<label>\s*:?\w*(passw|pwd|user|usr)\w*:?\s)(?<value>.*)$/
|
114
|
+
|
115
|
+
# Line by line, write the line to file, encrypting sensitive fields
|
116
|
+
File.open(config_path, 'w+') do |f|
|
117
|
+
config_lines.each do |l|
|
118
|
+
matches = l.match(regex)
|
119
|
+
|
120
|
+
# Encrypt fields with username/password labels that are in plaintext
|
121
|
+
unless matches.nil? || matches['value'].include?('SymmetricEncryption')
|
122
|
+
l = "#{matches['label']}#{encrypt_field(matches['value'])}"
|
123
|
+
end
|
124
|
+
|
125
|
+
f.puts l
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
# Returns a hash containing the decrypted details from a config file.
|
131
|
+
def self.decrypt_config(enc_path, config_path)
|
132
|
+
SymmetricEncryption.load!(enc_path, STANZA)
|
133
|
+
return YAML.load(ERB.new(File.new(config_path).read).result)
|
134
|
+
end
|
135
|
+
|
136
|
+
def self.handle_error(message, error)
|
137
|
+
puts message
|
138
|
+
raise error
|
139
|
+
end
|
140
|
+
end
|
File without changes
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nexpose_ticketing
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Damian Finol
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2017-05-
|
14
|
+
date: 2017-05-16 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: nexpose
|
@@ -81,6 +81,26 @@ dependencies:
|
|
81
81
|
- - ">="
|
82
82
|
- !ruby/object:Gem::Version
|
83
83
|
version: 1.1.2
|
84
|
+
- !ruby/object:Gem::Dependency
|
85
|
+
name: symmetric-encryption
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - "~>"
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '3.9'
|
91
|
+
- - ">="
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: 3.9.0
|
94
|
+
type: :runtime
|
95
|
+
prerelease: false
|
96
|
+
version_requirements: !ruby/object:Gem::Requirement
|
97
|
+
requirements:
|
98
|
+
- - "~>"
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
version: '3.9'
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 3.9.0
|
84
104
|
- !ruby/object:Gem::Dependency
|
85
105
|
name: rspec
|
86
106
|
requirement: !ruby/object:Gem::Requirement
|
@@ -132,10 +152,10 @@ extra_rdoc_files:
|
|
132
152
|
- README.md
|
133
153
|
files:
|
134
154
|
- Gemfile
|
135
|
-
- Gemfile.lock
|
136
155
|
- README.md
|
137
156
|
- bin/nexpose_ticketing
|
138
157
|
- lib/nexpose_ticketing.rb
|
158
|
+
- lib/nexpose_ticketing/config/encryption.config
|
139
159
|
- lib/nexpose_ticketing/config/jira.config
|
140
160
|
- lib/nexpose_ticketing/config/remedy.config
|
141
161
|
- lib/nexpose_ticketing/config/remedy_wsdl/HPD_IncidentInterface_Create_WS.xml
|
@@ -153,13 +173,14 @@ files:
|
|
153
173
|
- lib/nexpose_ticketing/modes/default_mode.rb
|
154
174
|
- lib/nexpose_ticketing/modes/ip_mode.rb
|
155
175
|
- lib/nexpose_ticketing/modes/vulnerability_mode.rb
|
156
|
-
- lib/nexpose_ticketing/nx_logger.rb
|
157
176
|
- lib/nexpose_ticketing/queries.rb
|
158
177
|
- lib/nexpose_ticketing/report_helper.rb
|
159
178
|
- lib/nexpose_ticketing/store.rb
|
160
179
|
- lib/nexpose_ticketing/ticket_metrics.rb
|
161
180
|
- lib/nexpose_ticketing/ticket_repository.rb
|
162
181
|
- lib/nexpose_ticketing/ticket_service.rb
|
182
|
+
- lib/nexpose_ticketing/utilities/config_parser.rb
|
183
|
+
- lib/nexpose_ticketing/utilities/nx_logger.rb
|
163
184
|
- lib/nexpose_ticketing/version.rb
|
164
185
|
homepage: https://github.com/rapid7/nexpose_ticketing
|
165
186
|
licenses:
|
@@ -181,7 +202,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
181
202
|
version: '0'
|
182
203
|
requirements: []
|
183
204
|
rubyforge_project:
|
184
|
-
rubygems_version: 2.
|
205
|
+
rubygems_version: 2.6.7
|
185
206
|
signing_key:
|
186
207
|
specification_version: 4
|
187
208
|
summary: Ruby Nexpose Ticketing Engine.
|
data/Gemfile.lock
DELETED
@@ -1,69 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
nexpose_ticketing (1.3.0)
|
5
|
-
nexpose (~> 3.1, >= 3.1.0)
|
6
|
-
nokogiri (~> 1.6)
|
7
|
-
savon (~> 2.1)
|
8
|
-
|
9
|
-
GEM
|
10
|
-
remote: https://rubygems.org/
|
11
|
-
specs:
|
12
|
-
akami (1.2.2)
|
13
|
-
gyoku (>= 0.4.0)
|
14
|
-
nokogiri
|
15
|
-
builder (3.2.2)
|
16
|
-
diff-lcs (1.2.5)
|
17
|
-
gyoku (1.1.1)
|
18
|
-
builder (>= 2.1.2)
|
19
|
-
httpi (2.1.1)
|
20
|
-
rack
|
21
|
-
rubyntlm (~> 0.3.2)
|
22
|
-
macaddr (1.7.1)
|
23
|
-
systemu (~> 2.6.2)
|
24
|
-
mini_portile2 (2.0.0)
|
25
|
-
nexpose (3.3.0)
|
26
|
-
nokogiri (1.6.7.2)
|
27
|
-
mini_portile2 (~> 2.0.0.rc2)
|
28
|
-
nori (2.4.0)
|
29
|
-
rack (1.6.4)
|
30
|
-
rspec (3.4.0)
|
31
|
-
rspec-core (~> 3.4.0)
|
32
|
-
rspec-expectations (~> 3.4.0)
|
33
|
-
rspec-mocks (~> 3.4.0)
|
34
|
-
rspec-core (3.4.4)
|
35
|
-
rspec-support (~> 3.4.0)
|
36
|
-
rspec-expectations (3.4.0)
|
37
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
38
|
-
rspec-support (~> 3.4.0)
|
39
|
-
rspec-mocks (3.4.1)
|
40
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
41
|
-
rspec-support (~> 3.4.0)
|
42
|
-
rspec-support (3.4.1)
|
43
|
-
rubyntlm (0.3.4)
|
44
|
-
savon (2.5.1)
|
45
|
-
akami (~> 1.2.0)
|
46
|
-
builder (>= 2.1.2)
|
47
|
-
gyoku (~> 1.1.0)
|
48
|
-
httpi (~> 2.1.0)
|
49
|
-
nokogiri (>= 1.4.0)
|
50
|
-
nori (~> 2.4.0)
|
51
|
-
uuid (~> 2.3.7)
|
52
|
-
wasabi (~> 3.3.0)
|
53
|
-
systemu (2.6.5)
|
54
|
-
uuid (2.3.8)
|
55
|
-
macaddr (~> 1.0)
|
56
|
-
wasabi (3.3.1)
|
57
|
-
httpi (~> 2.0)
|
58
|
-
nokogiri (>= 1.4.0)
|
59
|
-
|
60
|
-
PLATFORMS
|
61
|
-
ruby
|
62
|
-
|
63
|
-
DEPENDENCIES
|
64
|
-
nexpose_ticketing!
|
65
|
-
rspec (~> 3.2, >= 3.2.0)
|
66
|
-
rspec-mocks (~> 3.2, >= 3.2.0)
|
67
|
-
|
68
|
-
BUNDLED WITH
|
69
|
-
1.12.5
|