dradis-plugins 3.0.0 → 3.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rspec +2 -0
- data/README.md +3 -3
- data/app/controllers/dradis/plugins/export/base_controller.rb +9 -0
- data/dradis-plugins.gemspec +1 -0
- data/lib/dradis/plugins.rb +25 -48
- data/lib/dradis/plugins/base.rb +45 -0
- data/lib/dradis/plugins/configurable.rb +26 -0
- data/lib/dradis/plugins/content_service.rb +120 -20
- data/lib/dradis/plugins/engine.rb +7 -1
- data/lib/dradis/plugins/export/base.rb +12 -3
- data/lib/dradis/plugins/gem_version.rb +4 -4
- data/lib/dradis/plugins/import/filters.rb +7 -6
- data/lib/dradis/plugins/import/result.rb +4 -3
- data/lib/dradis/plugins/settings.rb +103 -0
- data/lib/dradis/plugins/template_service.rb +6 -3
- data/lib/dradis/plugins/templates.rb +31 -15
- data/lib/dradis/plugins/thor.rb +30 -0
- data/lib/dradis/plugins/thor_helper.rb +14 -0
- data/lib/dradis/plugins/upload.rb +8 -0
- data/lib/dradis/plugins/upload/base.rb +55 -40
- data/lib/dradis/plugins/upload/field_processor.rb +6 -0
- data/lib/dradis/plugins/upload/importer.rb +42 -0
- data/spec/internal/log/test.log +0 -0
- data/spec/settings_spec.rb +88 -0
- data/spec/spec_helper.rb +2 -0
- metadata +39 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 74496768f4fd445889de85903ef1470ea133c87f
|
4
|
+
data.tar.gz: 71a03d2ef7b24237a75f87b3ee9295afb963b0ec
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8f1d927b2727a5e010fcd889a37fc858520b309ab89decf49d4c32d222fe60a0654a05b9a5ad5a7f9d2d14616cf0383c8827325f100272bc8b30834354f42b35
|
7
|
+
data.tar.gz: 48f722e8962d1f4a07e26b5d975fe2b98097c7b666c0255e6424ceafc67f8f635c7925719b55d41c792265347cfe7afd190eb960bff84da3c69d5fd6d88bcba8
|
data/.rspec
ADDED
data/README.md
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
# Plugin manager for the Dradis Framework
|
2
2
|
|
3
|
-
[![Build Status](https://secure.travis-ci.org/dradis/dradis-plugins.png?branch=master)](http://travis-ci.org/dradis/dradis-plugins)
|
3
|
+
[![Build Status](https://secure.travis-ci.org/dradis/dradis-plugins.png?branch=master)](http://travis-ci.org/dradis/dradis-plugins) [![Code Climate](https://codeclimate.com/github/dradis/dradis-plugins.png)](https://codeclimate.com/github/dradis/dradis-plugins.png)
|
4
4
|
|
5
5
|
This gem contains the base classes needed to manage the plugins in Dradis.
|
6
6
|
|
7
7
|
The Dradis 3 gemified plugin Engines need to include Dradis::Plugins::Base which is defined in this class.
|
8
8
|
|
9
|
-
Warning, we
|
9
|
+
Warning, we may end up merging this gem with Dradis::Core!!
|
10
10
|
|
11
11
|
The plugin requires Dradis 3.0 or higher.
|
12
12
|
|
@@ -22,4 +22,4 @@ See the Dradis Framework's [CONTRIBUTING.md](https://github.com/dradis/dradisfra
|
|
22
22
|
|
23
23
|
## License
|
24
24
|
|
25
|
-
Dradis Framework and all its components are released under [GNU General Public License version 2.0](http://www.gnu.org/licenses/old-licenses/gpl-2.0.html) as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file.
|
25
|
+
Dradis Framework and all its components are released under [GNU General Public License version 2.0](http://www.gnu.org/licenses/old-licenses/gpl-2.0.html) as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file.
|
data/dradis-plugins.gemspec
CHANGED
@@ -22,6 +22,7 @@ Gem::Specification.new do |spec|
|
|
22
22
|
|
23
23
|
spec.add_development_dependency 'bundler', '~> 1.6'
|
24
24
|
spec.add_development_dependency 'rake', '~> 10.0'
|
25
|
+
spec.add_development_dependency 'rspec-rails'
|
25
26
|
|
26
27
|
# By not including Rails as a dependency, we can use the gem with different
|
27
28
|
# versions of Rails (a sure recipe for disaster, I'm sure), which is needed
|
data/lib/dradis/plugins.rb
CHANGED
@@ -1,53 +1,11 @@
|
|
1
|
-
require 'dradis/plugins/engine'
|
2
|
-
require 'dradis/plugins/version'
|
3
|
-
|
4
|
-
require 'dradis/plugins/content_service'
|
5
|
-
require 'dradis/plugins/template_service'
|
6
|
-
|
7
|
-
require 'dradis/plugins/export'
|
8
|
-
require 'dradis/plugins/import'
|
9
|
-
require 'dradis/plugins/upload'
|
10
|
-
|
11
|
-
require 'dradis/plugins/templates'
|
12
|
-
|
13
1
|
module Dradis
|
14
2
|
module Plugins
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
base.class_eval do
|
19
|
-
# mattr_accessor :plugin_name
|
20
|
-
|
21
|
-
@features = []
|
22
|
-
@name = 'Use plugin_info(args) with :name to provide a name for this plugin.'
|
23
|
-
Plugins::register(self)
|
24
|
-
end
|
25
|
-
|
26
|
-
# Extend the engine with other functionality
|
27
|
-
base.send :include, Dradis::Plugins::Templates
|
28
|
-
end
|
29
|
-
|
30
|
-
module ClassMethods
|
31
|
-
def description(new_description)
|
32
|
-
@description = new_description
|
33
|
-
end
|
34
|
-
|
35
|
-
def plugin_description
|
36
|
-
@description ||= "This plugin doesn't provide a :description"
|
37
|
-
end
|
3
|
+
mattr_accessor :configuration_class
|
4
|
+
mattr_accessor :base_export_controller_class
|
5
|
+
mattr_accessor :thor_helper_module
|
38
6
|
|
39
|
-
|
40
|
-
|
41
|
-
end
|
42
|
-
|
43
|
-
def provides(*list)
|
44
|
-
@features = list
|
45
|
-
end
|
46
|
-
|
47
|
-
def provides?(feature)
|
48
|
-
@features.include?(feature)
|
49
|
-
end
|
50
|
-
end
|
7
|
+
def self.setup(&block)
|
8
|
+
yield self
|
51
9
|
end
|
52
10
|
|
53
11
|
class << self
|
@@ -108,4 +66,23 @@ module Dradis
|
|
108
66
|
end
|
109
67
|
end
|
110
68
|
end
|
111
|
-
end
|
69
|
+
end
|
70
|
+
|
71
|
+
|
72
|
+
require 'dradis/plugins/engine'
|
73
|
+
require 'dradis/plugins/version'
|
74
|
+
|
75
|
+
require 'dradis/plugins/content_service'
|
76
|
+
require 'dradis/plugins/template_service'
|
77
|
+
|
78
|
+
require 'dradis/plugins/base'
|
79
|
+
require 'dradis/plugins/export'
|
80
|
+
require 'dradis/plugins/import'
|
81
|
+
require 'dradis/plugins/upload'
|
82
|
+
|
83
|
+
# Common functionality
|
84
|
+
require 'dradis/plugins/configurable'
|
85
|
+
require 'dradis/plugins/settings'
|
86
|
+
require 'dradis/plugins/templates'
|
87
|
+
require 'dradis/plugins/thor'
|
88
|
+
require 'dradis/plugins/thor_helper'
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Dradis
|
2
|
+
module Plugins
|
3
|
+
module Base
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
# mattr_accessor :plugin_name
|
8
|
+
|
9
|
+
@features = []
|
10
|
+
@name = 'Use plugin_info(args) with :name to provide a name for this plugin.'
|
11
|
+
Plugins::register(self)
|
12
|
+
|
13
|
+
# Extend the engine with other functionality
|
14
|
+
include Dradis::Plugins::Configurable
|
15
|
+
include Dradis::Plugins::Templates
|
16
|
+
include Dradis::Plugins::Thor
|
17
|
+
end
|
18
|
+
|
19
|
+
module ClassMethods
|
20
|
+
def description(new_description)
|
21
|
+
@description = new_description
|
22
|
+
end
|
23
|
+
|
24
|
+
def plugin_description
|
25
|
+
@description ||= "This plugin doesn't provide a :description"
|
26
|
+
end
|
27
|
+
|
28
|
+
def plugin_name
|
29
|
+
@plugin_name ||= self.name.split('::')[-2].underscore.to_sym
|
30
|
+
end
|
31
|
+
|
32
|
+
def provides(*list)
|
33
|
+
@features = list
|
34
|
+
if list.include?(:upload)
|
35
|
+
include Dradis::Plugins::Upload::Base
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def provides?(feature)
|
40
|
+
@features.include?(feature)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Dradis::Plugins
|
2
|
+
module Configurable
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
module ClassMethods
|
6
|
+
delegate :settings, to: :instance
|
7
|
+
|
8
|
+
def settings_namespace
|
9
|
+
@settings_namespace || plugin_name
|
10
|
+
end
|
11
|
+
|
12
|
+
def addon_settings(namespace = nil, &block)
|
13
|
+
@settings_namespace = namespace if namespace
|
14
|
+
yield self if block_given?
|
15
|
+
end
|
16
|
+
|
17
|
+
def instance
|
18
|
+
@instance ||= new
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def settings
|
23
|
+
@settings ||= Dradis::Plugins::Settings.new(self.class.settings_namespace)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -3,8 +3,21 @@ module Dradis
|
|
3
3
|
class ContentService
|
4
4
|
attr_accessor :logger, :plugin
|
5
5
|
|
6
|
+
# ----------------------------------------------------------- Initializer
|
7
|
+
#
|
8
|
+
|
9
|
+
# @option plugin [Class] the 'wrapper' module of a plugin, e.g.
|
10
|
+
# Dradis::Plugins::Nessus
|
6
11
|
def initialize(args={})
|
7
|
-
|
12
|
+
self.plugin = args.fetch(:plugin)
|
13
|
+
self.logger = args[:logger]
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
# ------------------------------------------------------ Query operations
|
18
|
+
|
19
|
+
def all_issues
|
20
|
+
class_for(:issue).where(category_id: default_issue_category.id)
|
8
21
|
end
|
9
22
|
|
10
23
|
# Create a hash with all issues where the keys correspond to the field passed
|
@@ -12,26 +25,56 @@ module Dradis
|
|
12
25
|
#
|
13
26
|
# This is use by the plugins to check whether a given issue is already in
|
14
27
|
# the project.
|
15
|
-
def all_issues_by_field(field)
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
28
|
+
# def all_issues_by_field(field)
|
29
|
+
# # we don't memoize it because we want it to reflect recently added Issues
|
30
|
+
# klass = class_for(:issue)
|
31
|
+
#
|
32
|
+
# issues_map = klass.where(category_id: default_issue_category.id).map do |issue|
|
33
|
+
# [issue.fields[field], issue]
|
34
|
+
# end
|
35
|
+
# Hash[issues_map]
|
36
|
+
# end
|
37
|
+
|
38
|
+
# Accesing the library by primary sorting key. Raise an exception unless
|
39
|
+
# the issue library cache has been initialized.
|
40
|
+
def issue_cache
|
41
|
+
@issue_cache ||= begin
|
42
|
+
klass = class_for(:issue)
|
43
|
+
|
44
|
+
issues_map = klass.where(category_id: default_issue_category.id).map do |issue|
|
45
|
+
cache_key = [
|
46
|
+
issue.fields['plugin'],
|
47
|
+
issue.fields['plugin_id']
|
48
|
+
].join('-')
|
49
|
+
|
50
|
+
[cache_key, issue]
|
51
|
+
end
|
52
|
+
Hash[issues_map]
|
21
53
|
end
|
22
|
-
Hash[issues_map]
|
23
54
|
end
|
24
55
|
|
56
|
+
def all_notes
|
57
|
+
class_for(:note).where(category_id: class_for(:category).report.id)
|
58
|
+
end
|
59
|
+
|
60
|
+
# ----------------------------------------------------- Create operations
|
61
|
+
#
|
25
62
|
|
26
63
|
def create_node(args={})
|
27
|
-
label
|
28
|
-
parent
|
64
|
+
label = args[:label] || "create_node() invoked by #{plugin} without a :label parameter"
|
65
|
+
parent = args[:parent] || default_parent_node
|
66
|
+
|
29
67
|
type_id = begin
|
30
|
-
|
31
|
-
|
68
|
+
if args[:type]
|
69
|
+
tmp_type = args[:type].to_s.upcase
|
70
|
+
class_for(:node)::Types::const_defined?(tmp_type) ? "#{class_for(:node)::Types}::#{tmp_type}".constantize : default_node_type
|
71
|
+
else
|
72
|
+
default_node_type
|
73
|
+
end
|
32
74
|
end
|
33
75
|
|
34
76
|
# FIXME: how ugly is this?
|
77
|
+
# UPGRADE: Rails 4 find_or_create_by_
|
35
78
|
if Rails::VERSION::MAJOR == 3
|
36
79
|
parent.children.find_or_create_by_label_and_type_id(label, type_id)
|
37
80
|
else
|
@@ -43,20 +86,45 @@ module Dradis
|
|
43
86
|
node = args[:node] || default_parent_node
|
44
87
|
text = args[:text] || "create_note() invoked by #{plugin} without a :text parameter"
|
45
88
|
|
46
|
-
node.notes.
|
89
|
+
note = node.notes.new(text: text, category: default_note_category, author: default_author)
|
90
|
+
if note.valid?
|
91
|
+
note.save
|
92
|
+
else
|
93
|
+
try_rescue_from_length_validation(model: note, field: :text, text: text, msg: 'Error in create_note()')
|
94
|
+
end
|
95
|
+
|
96
|
+
note
|
47
97
|
end
|
48
98
|
|
49
99
|
def create_issue(args={})
|
50
100
|
text = args[:text] || "create_issue() invoked by #{plugin} without a :text parameter"
|
101
|
+
# NOTE that ID is the unique issue identifier assigned by the plugin,
|
102
|
+
# and is not to be confused with the Issue#id primary key
|
103
|
+
id = args[:id] || "create_issue() invoked by #{plugin} without an :id parameter"
|
104
|
+
|
105
|
+
# Bail if we already have this issue in the cache
|
106
|
+
uuid = [plugin::Engine::plugin_name, id]
|
107
|
+
cache_key = uuid.join('-')
|
108
|
+
|
109
|
+
return issue_cache[cache_key] if issue_cache.key?(cache_key)
|
51
110
|
|
52
|
-
# we inject the source Plugin into the issue's text
|
53
|
-
text << "\n\n#[plugin]#\n#{
|
111
|
+
# we inject the source Plugin and unique ID into the issue's text
|
112
|
+
text << "\n\n#[plugin]#\n#{uuid[0]}\n"
|
113
|
+
text << "\n\n#[plugin_id]#\n#{uuid[1]}\n"
|
54
114
|
|
55
|
-
class_for(:issue).
|
115
|
+
issue = class_for(:issue).new(text: text) do |i|
|
56
116
|
i.author = default_author
|
57
117
|
i.node = issuelib
|
58
118
|
i.category = default_issue_category
|
59
119
|
end
|
120
|
+
|
121
|
+
if issue.valid?
|
122
|
+
issue.save
|
123
|
+
else
|
124
|
+
try_rescue_from_length_validation(model: issue, field: :text, text: text, msg: 'Error in create_issue()')
|
125
|
+
end
|
126
|
+
|
127
|
+
issue_cache.store(cache_key, issue)
|
60
128
|
end
|
61
129
|
|
62
130
|
def create_evidence(args={})
|
@@ -64,15 +132,22 @@ module Dradis
|
|
64
132
|
node = args[:node] || default_parent_node
|
65
133
|
issue = args[:issue] || create_issue(text: "#[Title]#\nAuto-generated issue.\n\n#[Description]#\ncreate_evidence() invoked by #{plugin} without an :issue parameter")
|
66
134
|
|
67
|
-
node.evidence.
|
135
|
+
evidence = node.evidence.new(issue_id: issue.id, content: content)
|
136
|
+
if evidence.valid?
|
137
|
+
evidence.save
|
138
|
+
else
|
139
|
+
try_rescue_from_length_validation(model: evidence, field: :content, text: content, msg: 'Error in create_evidence()')
|
140
|
+
end
|
141
|
+
evidence
|
68
142
|
end
|
69
143
|
|
144
|
+
|
70
145
|
private
|
146
|
+
|
71
147
|
def class_for(model)
|
72
|
-
"
|
148
|
+
"::#{model.to_s.capitalize}".constantize
|
73
149
|
end
|
74
150
|
|
75
|
-
|
76
151
|
def default_author
|
77
152
|
@default_author ||= "#{plugin::Engine.plugin_name.to_s.humanize} upload plugin"
|
78
153
|
end
|
@@ -90,12 +165,37 @@ module Dradis
|
|
90
165
|
end
|
91
166
|
|
92
167
|
def default_parent_node
|
93
|
-
@default_parent_node ||= class_for(:node).
|
168
|
+
@default_parent_node ||= class_for(:node).plugin_parent_node
|
94
169
|
end
|
95
170
|
|
96
171
|
def issuelib
|
97
172
|
@issuelib ||= class_for(:node).issue_library
|
98
173
|
end
|
174
|
+
|
175
|
+
def try_rescue_from_length_validation(args={})
|
176
|
+
model = args[:model]
|
177
|
+
field = args[:field]
|
178
|
+
text = args[:text]
|
179
|
+
msg = args[:msg]
|
180
|
+
|
181
|
+
logger.error{ "Trying to rescue from a :length error" }
|
182
|
+
|
183
|
+
if model.errors[field]
|
184
|
+
# the plugin tried to store too much information
|
185
|
+
msg = "#[Title]#\nTruncation warning!\n\n"
|
186
|
+
msg << "#[Error]#\np(alert alert-error). The plugin tried to store content that was too big for the DB. Review the source to ensure no important data was lost.\n\n"
|
187
|
+
msg << text
|
188
|
+
model.send("#{field}=", msg.truncate(65300))
|
189
|
+
else
|
190
|
+
# bail
|
191
|
+
msg = "#[Title]#\n#{msg}\n\n"
|
192
|
+
msg << "#[Description]#\nbc. #{issue.errors.inspect}\n\n"
|
193
|
+
model.send("#{field}=", msg)
|
194
|
+
end
|
195
|
+
if model.valid?
|
196
|
+
model.save
|
197
|
+
end
|
198
|
+
end
|
99
199
|
end
|
100
200
|
end
|
101
201
|
end
|
@@ -14,6 +14,12 @@ module Dradis
|
|
14
14
|
# initializer 'frontend.asset_precompile_paths' do |app|
|
15
15
|
# app.config.assets.precompile += ["dradis/frontend/manifests/*"]
|
16
16
|
# end
|
17
|
+
|
18
|
+
Dradis::Plugins::setup do |config|
|
19
|
+
config.base_export_controller_class = 'ProjectScopedController'
|
20
|
+
config.configuration_class = '::Configuration'
|
21
|
+
config.thor_helper_module = 'Dradis::Plugins::ThorHelper'
|
22
|
+
end
|
17
23
|
end
|
18
24
|
end
|
19
|
-
end
|
25
|
+
end
|
@@ -5,11 +5,15 @@ module Dradis
|
|
5
5
|
module Plugins
|
6
6
|
module Export
|
7
7
|
class Base
|
8
|
-
attr_accessor :logger
|
8
|
+
attr_accessor :content_service, :logger
|
9
9
|
|
10
10
|
def initialize(args={})
|
11
11
|
@logger = args.fetch(:logger, Rails.logger)
|
12
12
|
|
13
|
+
@content_service = args[:content_service] || default_content_service
|
14
|
+
|
15
|
+
content_service.logger = logger
|
16
|
+
|
13
17
|
post_initialize(args)
|
14
18
|
end
|
15
19
|
|
@@ -20,8 +24,13 @@ module Dradis
|
|
20
24
|
# This method can be overwriten by plugins to do initialization tasks.
|
21
25
|
def post_initialize(args={})
|
22
26
|
end
|
23
|
-
end # Base
|
24
27
|
|
28
|
+
private
|
29
|
+
def default_content_service
|
30
|
+
@content ||= Dradis::Plugins::ContentService.new
|
31
|
+
end
|
32
|
+
|
33
|
+
end # Base
|
25
34
|
end # Export
|
26
35
|
end # Plugins
|
27
|
-
end # Core
|
36
|
+
end # Core
|
@@ -16,12 +16,12 @@ module Dradis
|
|
16
16
|
# register_filter :by_osvdb_id do
|
17
17
|
# def c
|
18
18
|
# end
|
19
|
-
def add(label, filter, &block)
|
19
|
+
def add(plugin, label, filter, &block)
|
20
20
|
filter ||= Class.new(Dradis::Plugins::Import::Filters::Base)
|
21
21
|
filter.class_eval(&block) if block_given?
|
22
22
|
|
23
23
|
unless filter.method_defined?(:query)
|
24
|
-
raise NoMethodError, "query() is not declared in the #{label.inspect}
|
24
|
+
raise NoMethodError, "query() is not declared in the #{label.inspect} filter"
|
25
25
|
end
|
26
26
|
|
27
27
|
base = Dradis::Plugins::Import::Filters::Base
|
@@ -29,13 +29,14 @@ module Dradis
|
|
29
29
|
raise "#{label.inspect} is not a #{base}"
|
30
30
|
end
|
31
31
|
|
32
|
-
_filters[
|
32
|
+
_filters[plugin] = {} unless _filters.key?(plugin)
|
33
|
+
_filters[plugin][label] = filter
|
33
34
|
end
|
34
35
|
|
35
|
-
# Provides access to
|
36
|
+
# Provides access to filters by plugin
|
36
37
|
# :api: public
|
37
|
-
def [](
|
38
|
-
_filters[
|
38
|
+
def [](plugin)
|
39
|
+
_filters[plugin]
|
39
40
|
end
|
40
41
|
|
41
42
|
# :api: private
|
@@ -1,11 +1,12 @@
|
|
1
1
|
module Dradis::Plugins::Import
|
2
2
|
class Result
|
3
|
-
attr_accessor :description, :tags, :title
|
3
|
+
attr_accessor :description, :id, :tags, :title
|
4
4
|
|
5
5
|
def initialize(args={})
|
6
6
|
@description = args[:description] || "The Import plugin didn't provide a :description for this result."
|
7
|
-
@
|
8
|
-
@
|
7
|
+
@id = args[:id] || "The Import plugin didn't provide an :id for this result."
|
8
|
+
@tags = args[:tags] || []
|
9
|
+
@title = args[:title] || "The Import plugin didn't provide a :title for this result."
|
9
10
|
end
|
10
11
|
end
|
11
12
|
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
module Dradis::Plugins
|
2
|
+
class Settings
|
3
|
+
attr_reader :namespace
|
4
|
+
|
5
|
+
def initialize(namespace)
|
6
|
+
@namespace = namespace
|
7
|
+
@dirty_options ||= {}
|
8
|
+
@default_options ||= HashWithIndifferentAccess.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def respond_to?(name)
|
12
|
+
super || @dirty_options.key?(name.to_sym)
|
13
|
+
end
|
14
|
+
|
15
|
+
def all
|
16
|
+
@default_options.map do |key, value|
|
17
|
+
{
|
18
|
+
name: key.to_sym,
|
19
|
+
value: value = dirty_or_db_setting_or_default(key.to_sym),
|
20
|
+
default: is_default?(key, value)
|
21
|
+
}
|
22
|
+
end.sort_by{ |o| o[:name] }
|
23
|
+
end
|
24
|
+
|
25
|
+
def save
|
26
|
+
@dirty_options.reject{ |k, v| v.present? && v == db_setting(k) }.each{ |k, v| write_to_db(k, v) }
|
27
|
+
end
|
28
|
+
|
29
|
+
def update_settings(opts = {})
|
30
|
+
opts.select{ |k, v| @default_options.key?(k) }.each do |k, v|
|
31
|
+
@dirty_options[k.to_sym] = v
|
32
|
+
end
|
33
|
+
save
|
34
|
+
end
|
35
|
+
|
36
|
+
def reset_defaults!
|
37
|
+
@dirty_options = {}
|
38
|
+
@default_options.each do |key, value|
|
39
|
+
configuration_class.where(name: namespaced_key(key)).each(&:destroy)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def is_default?(key, value)
|
44
|
+
value.to_s == @default_options[key.to_sym].to_s
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
# ---------------------------------------------------- Method missing magic
|
50
|
+
def method_missing(name, *args, &blk)
|
51
|
+
if name.to_s =~ /^default_(.*)=$/
|
52
|
+
@default_options[$1.to_sym] = args.first
|
53
|
+
elsif name.to_s =~ /=$/
|
54
|
+
@dirty_options[$`.to_sym] = args.first
|
55
|
+
elsif @default_options.key?(name)
|
56
|
+
dirty_or_db_setting_or_default(name)
|
57
|
+
else
|
58
|
+
super
|
59
|
+
end
|
60
|
+
end
|
61
|
+
# --------------------------------------------------- /Method missing magic
|
62
|
+
|
63
|
+
# This allows us to use the same code in Community and Pro and overwrite
|
64
|
+
# the name of the class in an initializer.
|
65
|
+
def configuration_class
|
66
|
+
@klass ||= Dradis::Plugins::configuration_class.to_s.constantize
|
67
|
+
end
|
68
|
+
|
69
|
+
def write_to_db(key, value)
|
70
|
+
# FIXME: how ugly is this?
|
71
|
+
# UPGRADE: Rails 4 find_or_create_by_
|
72
|
+
db_setting = if Rails::VERSION::MAJOR == 3
|
73
|
+
configuration_class.find_or_create_by_name(namespaced_key(key))
|
74
|
+
else
|
75
|
+
configuration_class.find_or_create_by(name: namespaced_key(key))
|
76
|
+
end
|
77
|
+
db_setting.update_attribute(:value, value)
|
78
|
+
end
|
79
|
+
|
80
|
+
|
81
|
+
def db_setting(key)
|
82
|
+
configuration_class.where(name: namespaced_key(key)).first.value rescue nil
|
83
|
+
end
|
84
|
+
|
85
|
+
# This method looks up in the configuration repository DB to see if the
|
86
|
+
# user has provided a value for the given setting. If not, the default
|
87
|
+
# value is returned.
|
88
|
+
def dirty_or_db_setting_or_default(key)
|
89
|
+
if @dirty_options.key?(key)
|
90
|
+
@dirty_options[key]
|
91
|
+
elsif configuration_class.exists?(name: namespaced_key(key))
|
92
|
+
db_setting(key)
|
93
|
+
else
|
94
|
+
@default_options[key]
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# Builds namespaced key
|
99
|
+
def namespaced_key(key)
|
100
|
+
[self.namespace.to_s, key.to_s.underscore].join(":")
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -4,7 +4,7 @@ module Dradis
|
|
4
4
|
attr_accessor :logger, :template, :templates_dir
|
5
5
|
|
6
6
|
def initialize(args={})
|
7
|
-
@plugin
|
7
|
+
@plugin = args.fetch(:plugin)
|
8
8
|
@templates_dir = args[:templates_dir] || default_templates_dir
|
9
9
|
end
|
10
10
|
|
@@ -64,7 +64,7 @@ module Dradis
|
|
64
64
|
end
|
65
65
|
|
66
66
|
# This method returns the current template's source. It caches the
|
67
|
-
# template based on the file's last-modified time and
|
67
|
+
# template based on the file's last-modified time and refreshes the
|
68
68
|
# cached copy when it detects changes.
|
69
69
|
def template_source
|
70
70
|
@sources ||= {}
|
@@ -95,7 +95,10 @@ module Dradis
|
|
95
95
|
# This method returns the default location in which plugins should look
|
96
96
|
# for their templates.
|
97
97
|
def default_templates_dir
|
98
|
-
@default_templates_dir ||=
|
98
|
+
@default_templates_dir ||= begin
|
99
|
+
conf_class = Dradis::Plugins::configuration_class.constantize
|
100
|
+
File.join(conf_class.paths_templates_plugins, @plugin::meta[:name].to_s)
|
101
|
+
end
|
99
102
|
end
|
100
103
|
end
|
101
104
|
end
|
@@ -1,27 +1,29 @@
|
|
1
1
|
module Dradis
|
2
2
|
module Plugins
|
3
3
|
module Templates
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
paths['dradis/templates'] = 'templates'
|
10
|
-
end
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
# Keep track of any templates the plugin defines
|
8
|
+
paths['dradis/templates'] = 'templates'
|
11
9
|
end
|
12
10
|
|
13
11
|
module ClassMethods
|
14
12
|
def copy_templates(args={})
|
15
|
-
destination = args
|
13
|
+
destination = args.fetch(:to)
|
16
14
|
|
17
|
-
|
18
|
-
FileUtils.mkdir_p(
|
15
|
+
destination_dir = File.join(destination, plugin_name.to_s)
|
16
|
+
FileUtils.mkdir_p(destination_dir) if plugin_templates.any?
|
19
17
|
|
20
18
|
plugin_templates.each do |template|
|
21
|
-
destination_file = File.join(
|
22
|
-
next if File.exist?(destination_file)
|
19
|
+
destination_file = File.join(destination_dir, File.basename(template))
|
23
20
|
|
24
|
-
|
21
|
+
next if skip?(destination_file)
|
22
|
+
|
23
|
+
Rails.logger.info do
|
24
|
+
"Updating templates for #{plugin_name} plugin. "\
|
25
|
+
"Destination: #{destination}"
|
26
|
+
end
|
25
27
|
FileUtils.cp(template, destination_file)
|
26
28
|
end
|
27
29
|
end
|
@@ -29,13 +31,27 @@ module Dradis
|
|
29
31
|
def plugin_templates(args={})
|
30
32
|
@templates ||= begin
|
31
33
|
if paths['dradis/templates'].existent.any?
|
32
|
-
Dir["
|
34
|
+
Dir["#{paths['dradis/templates'].existent.first}/*"]
|
33
35
|
else
|
34
36
|
[]
|
35
37
|
end
|
36
38
|
end
|
37
39
|
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
# Normally we want to copy all templates so that the user always has
|
44
|
+
# the latest version.
|
45
|
+
#
|
46
|
+
# However, if it's a '.template' file, the user might have edited their
|
47
|
+
# local copy, and we don't want to override their changes. So only
|
48
|
+
# copy .template files over if the user has no copy at all (i.e. if
|
49
|
+
# this is the first time they've started Dradis since this template was
|
50
|
+
# added.)
|
51
|
+
def skip?(file_path)
|
52
|
+
File.exist?(file_path) && File.extname(file_path) == ".template"
|
53
|
+
end
|
38
54
|
end
|
39
55
|
end
|
40
56
|
end
|
41
|
-
end
|
57
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Dradis
|
2
|
+
module Plugins
|
3
|
+
module Thor
|
4
|
+
def self.included(base)
|
5
|
+
base.extend(ClassMethods)
|
6
|
+
|
7
|
+
base.class_eval do
|
8
|
+
# Keep track of any templates the plugin defines
|
9
|
+
paths['dradis/thorfiles'] = 'lib/tasks'
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
module ClassMethods
|
14
|
+
def load_thor_tasks
|
15
|
+
plugin_thorfiles.each do |thorfile|
|
16
|
+
require thorfile
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def plugin_thorfiles(args={})
|
21
|
+
if paths['dradis/thorfiles'].existent.any?
|
22
|
+
Dir["%s/thorfile.rb" % paths['dradis/thorfiles'].existent]
|
23
|
+
else
|
24
|
+
[]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Dradis
|
2
|
+
module Plugins
|
3
|
+
# Helper methods for plugin Thor tasks
|
4
|
+
module ThorHelper
|
5
|
+
def content_service_for(plugin)
|
6
|
+
Dradis::Plugins::ContentService.new(plugin: plugin)
|
7
|
+
end
|
8
|
+
|
9
|
+
def detect_and_set_project_scope
|
10
|
+
;
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -1,42 +1,57 @@
|
|
1
|
-
# This module contains basic Upload plugin functions to control template
|
2
|
-
# sample and field management for the Plugin Manager.
|
3
|
-
#
|
4
|
-
module Dradis
|
5
|
-
module Plugins
|
6
|
-
module Upload
|
7
|
-
class Base
|
8
|
-
attr_accessor :content_service, :logger, :template_service
|
9
|
-
|
10
|
-
def initialize(args={})
|
11
|
-
@logger = args.fetch(:logger, Rails.logger)
|
12
|
-
|
13
|
-
@content_service = args[:content_service] || default_content_service
|
14
|
-
@template_service = args[:template_service] || default_template_service
|
15
|
-
|
16
|
-
content_service.logger = logger
|
17
|
-
template_service.logger = logger
|
18
|
-
|
19
|
-
post_initialize(args)
|
20
|
-
end
|
21
|
-
|
22
|
-
def import(args={})
|
23
|
-
raise "The import() method is not implemented in this plugin [#{self.class.name}]."
|
24
|
-
end
|
25
|
-
|
26
|
-
# This method can be overwriten by plugins to do initialization tasks.
|
27
|
-
def post_initialize(args={})
|
28
|
-
end
|
29
1
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
2
|
+
# When you call provides :upload in your Engine, this module gets included. It
|
3
|
+
# provides two features:
|
4
|
+
#
|
5
|
+
# a) an .uploaders() class method that by default responds with a single array
|
6
|
+
# item pointing to the engine's parent. This will be used by the framework to
|
7
|
+
# locate the ::Importer object that does the upload heavy lifting.
|
8
|
+
#
|
9
|
+
# If your plugin implements more than one uploader, each one would be contained
|
10
|
+
# in its own namespace, and you should overwrite the .uploaders() method to
|
11
|
+
# return an array of all these namespaces. See method definition for an
|
12
|
+
# example.
|
13
|
+
#
|
14
|
+
# b) it adds a .meta() method to the engine's parent module, containing the
|
15
|
+
# name, description and version of the add-on.
|
16
|
+
#
|
17
|
+
# Again, if you implement more than one uploader, make sure you create a
|
18
|
+
# .meta() class-level method in each of your namespaces.
|
19
|
+
#
|
39
20
|
|
40
|
-
|
41
|
-
|
42
|
-
|
21
|
+
module Dradis::Plugins::Upload::Base
|
22
|
+
extend ActiveSupport::Concern
|
23
|
+
|
24
|
+
included do
|
25
|
+
parent.extend NamespaceClassMethods
|
26
|
+
end
|
27
|
+
|
28
|
+
module ClassMethods
|
29
|
+
# Return the list of modules that provide upload functionality. This is
|
30
|
+
# useful if one plugin provides uploading functionality for more than one
|
31
|
+
# file type (e.g. the Projects plugin allows you to upload a Package or a
|
32
|
+
# Template).
|
33
|
+
#
|
34
|
+
# The default implementation just returns this plugin's namespace (e.g.
|
35
|
+
# Dradis::Plugins::Nessus). If a plugin provides multiple uploaders, they
|
36
|
+
# can override this method:
|
37
|
+
# def self.uploders
|
38
|
+
# [
|
39
|
+
# Dradis::Plugins::Projects::Package,
|
40
|
+
# Dradis::Plugins::Projects::Template
|
41
|
+
# ]
|
42
|
+
# end
|
43
|
+
def uploaders()
|
44
|
+
[parent]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
module NamespaceClassMethods
|
49
|
+
def meta
|
50
|
+
{
|
51
|
+
name: self::Engine::plugin_name,
|
52
|
+
description: self::Engine::plugin_description,
|
53
|
+
version: self::VERSION::STRING
|
54
|
+
}
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# This module contains basic Upload plugin functions to control template
|
2
|
+
# sample and field management for the Plugin Manager.
|
3
|
+
#
|
4
|
+
module Dradis
|
5
|
+
module Plugins
|
6
|
+
module Upload
|
7
|
+
class Importer
|
8
|
+
attr_accessor :content_service, :logger, :template_service
|
9
|
+
|
10
|
+
def initialize(args={})
|
11
|
+
@logger = args.fetch(:logger, Rails.logger)
|
12
|
+
|
13
|
+
@content_service = args[:content_service] || default_content_service
|
14
|
+
@template_service = args[:template_service] || default_template_service
|
15
|
+
|
16
|
+
content_service.logger = logger
|
17
|
+
template_service.logger = logger
|
18
|
+
|
19
|
+
post_initialize(args)
|
20
|
+
end
|
21
|
+
|
22
|
+
def import(args={})
|
23
|
+
raise "The import() method is not implemented in this plugin [#{self.class.name}]."
|
24
|
+
end
|
25
|
+
|
26
|
+
# This method can be overwriten by plugins to do initialization tasks.
|
27
|
+
def post_initialize(args={})
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
def default_content_service
|
32
|
+
@content ||= Dradis::Plugins::ContentService.new
|
33
|
+
end
|
34
|
+
|
35
|
+
def default_template_service
|
36
|
+
@template ||= Dradis::Plugins::TemplateService.new
|
37
|
+
end
|
38
|
+
end # Importer
|
39
|
+
|
40
|
+
end # Upload
|
41
|
+
end # Plugins
|
42
|
+
end # Core
|
File without changes
|
@@ -0,0 +1,88 @@
|
|
1
|
+
#
|
2
|
+
# This spec must be ran from Dradis root dir
|
3
|
+
#
|
4
|
+
require 'spec_helper'
|
5
|
+
|
6
|
+
class TestEngine < ::Rails::Engine
|
7
|
+
include ::Dradis::Plugins::Base
|
8
|
+
addon_settings :test_engine do
|
9
|
+
settings.default_host = 'localhost'
|
10
|
+
settings.default_port = 80
|
11
|
+
settings.default_protocol = 'http'
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe Dradis::Plugins::Settings do
|
16
|
+
|
17
|
+
before(:each) do
|
18
|
+
TestEngine::settings.reset_defaults!
|
19
|
+
end
|
20
|
+
|
21
|
+
it "sets and return default values" do
|
22
|
+
expect(TestEngine::settings.host).to eq('localhost')
|
23
|
+
expect(TestEngine::settings.port).to eq(80)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "sets and returns user defined values" do
|
27
|
+
expect(TestEngine::settings.host).to eq('localhost')
|
28
|
+
TestEngine::settings.host = '127.0.0.1'
|
29
|
+
expect(TestEngine::settings.host).to eq('127.0.0.1')
|
30
|
+
expect(TestEngine::settings.port).to eq(80)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "sets and returns new value even if it equals default value" do
|
34
|
+
expect(TestEngine::settings.host).to eq('localhost')
|
35
|
+
TestEngine::settings.host = '127.0.0.1'
|
36
|
+
expect(TestEngine::settings.host).to eq('127.0.0.1')
|
37
|
+
TestEngine::settings.host = 'localhost'
|
38
|
+
expect(TestEngine::settings.host).to eq('localhost')
|
39
|
+
end
|
40
|
+
|
41
|
+
it "saves to db and returns persisted values" do
|
42
|
+
expect(TestEngine::settings.host).to eq('localhost')
|
43
|
+
TestEngine::settings.host = '127.0.0.1'
|
44
|
+
expect_any_instance_of(TestEngine::settings::send(:configuration_class)).to receive(:update_attribute)
|
45
|
+
expect(TestEngine::settings.save).to eq( { host: '127.0.0.1'} )
|
46
|
+
expect(TestEngine::settings.host).to eq('127.0.0.1')
|
47
|
+
end
|
48
|
+
|
49
|
+
it "reads from db after saving" do
|
50
|
+
expect(TestEngine::settings.host).to eq('localhost')
|
51
|
+
TestEngine::settings.host = '127.0.0.1'
|
52
|
+
expect(TestEngine::settings.save).to eq( { host: '127.0.0.1'} )
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
describe Dradis::Plugins::Settings, '#is_default?' do
|
58
|
+
it 'knows if a string value equals its default integer value' do
|
59
|
+
TestEngine::settings.is_default?(:port, '80')
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe Dradis::Plugins::Settings, '#all' do
|
64
|
+
it 'returns values from db, dirty state or default as needed and tells which one is default' do
|
65
|
+
TestEngine::settings.host = '127.0.0.1'
|
66
|
+
TestEngine::settings.save
|
67
|
+
TestEngine::settings.protocol = 'https'
|
68
|
+
expect(TestEngine::settings.all).to eq([
|
69
|
+
{
|
70
|
+
name: :host,
|
71
|
+
value: '127.0.0.1',
|
72
|
+
default: false
|
73
|
+
},
|
74
|
+
{
|
75
|
+
name: :port,
|
76
|
+
value: 80,
|
77
|
+
default: true
|
78
|
+
},
|
79
|
+
{
|
80
|
+
name: :protocol,
|
81
|
+
value: 'https',
|
82
|
+
default: false
|
83
|
+
},
|
84
|
+
])
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
|
data/spec/spec_helper.rb
ADDED
metadata
CHANGED
@@ -1,43 +1,57 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dradis-plugins
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Martin
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-06-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - ~>
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '1.6'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - ~>
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '1.6'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - ~>
|
31
|
+
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '10.0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - ~>
|
38
|
+
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec-rails
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
41
55
|
description: Required dependency for Dradis Framework.
|
42
56
|
email:
|
43
57
|
- etd@nomejortu.com
|
@@ -45,15 +59,19 @@ executables: []
|
|
45
59
|
extensions: []
|
46
60
|
extra_rdoc_files: []
|
47
61
|
files:
|
48
|
-
- .gitignore
|
62
|
+
- ".gitignore"
|
63
|
+
- ".rspec"
|
49
64
|
- CONTRIBUTING.md
|
50
65
|
- Gemfile
|
51
66
|
- LICENSE
|
52
67
|
- README.md
|
53
68
|
- Rakefile
|
69
|
+
- app/controllers/dradis/plugins/export/base_controller.rb
|
54
70
|
- dradis-plugins.gemspec
|
55
71
|
- lib/dradis-plugins.rb
|
56
72
|
- lib/dradis/plugins.rb
|
73
|
+
- lib/dradis/plugins/base.rb
|
74
|
+
- lib/dradis/plugins/configurable.rb
|
57
75
|
- lib/dradis/plugins/content_service.rb
|
58
76
|
- lib/dradis/plugins/engine.rb
|
59
77
|
- lib/dradis/plugins/export.rb
|
@@ -63,12 +81,19 @@ files:
|
|
63
81
|
- lib/dradis/plugins/import/filters.rb
|
64
82
|
- lib/dradis/plugins/import/filters/base.rb
|
65
83
|
- lib/dradis/plugins/import/result.rb
|
84
|
+
- lib/dradis/plugins/settings.rb
|
66
85
|
- lib/dradis/plugins/template_service.rb
|
67
86
|
- lib/dradis/plugins/templates.rb
|
87
|
+
- lib/dradis/plugins/thor.rb
|
88
|
+
- lib/dradis/plugins/thor_helper.rb
|
68
89
|
- lib/dradis/plugins/upload.rb
|
69
90
|
- lib/dradis/plugins/upload/base.rb
|
70
91
|
- lib/dradis/plugins/upload/field_processor.rb
|
92
|
+
- lib/dradis/plugins/upload/importer.rb
|
71
93
|
- lib/dradis/plugins/version.rb
|
94
|
+
- spec/internal/log/test.log
|
95
|
+
- spec/settings_spec.rb
|
96
|
+
- spec/spec_helper.rb
|
72
97
|
homepage: http://dradisframework.org
|
73
98
|
licenses:
|
74
99
|
- GPL-2
|
@@ -79,18 +104,21 @@ require_paths:
|
|
79
104
|
- lib
|
80
105
|
required_ruby_version: !ruby/object:Gem::Requirement
|
81
106
|
requirements:
|
82
|
-
- -
|
107
|
+
- - ">="
|
83
108
|
- !ruby/object:Gem::Version
|
84
109
|
version: '0'
|
85
110
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
86
111
|
requirements:
|
87
|
-
- -
|
112
|
+
- - ">="
|
88
113
|
- !ruby/object:Gem::Version
|
89
114
|
version: '0'
|
90
115
|
requirements: []
|
91
116
|
rubyforge_project:
|
92
|
-
rubygems_version: 2.3
|
117
|
+
rubygems_version: 2.2.3
|
93
118
|
signing_key:
|
94
119
|
specification_version: 4
|
95
120
|
summary: Plugin manager for the Dradis Framework project.
|
96
|
-
test_files:
|
121
|
+
test_files:
|
122
|
+
- spec/internal/log/test.log
|
123
|
+
- spec/settings_spec.rb
|
124
|
+
- spec/spec_helper.rb
|