ronin-core 0.1.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.document +5 -0
- data/.github/workflows/ruby.yml +41 -0
- data/.gitignore +12 -0
- data/.rspec +1 -0
- data/.rubocop.yml +160 -0
- data/.ruby-version +1 -0
- data/.yardopts +1 -0
- data/COPYING.txt +165 -0
- data/ChangeLog.md +11 -0
- data/Gemfile +30 -0
- data/README.md +299 -0
- data/Rakefile +34 -0
- data/examples/ruby_shell.rb +11 -0
- data/gemspec.yml +28 -0
- data/lib/ronin/core/class_registry.rb +246 -0
- data/lib/ronin/core/cli/command.rb +87 -0
- data/lib/ronin/core/cli/command_shell/command.rb +110 -0
- data/lib/ronin/core/cli/command_shell.rb +345 -0
- data/lib/ronin/core/cli/generator/options/author.rb +106 -0
- data/lib/ronin/core/cli/generator/options/description.rb +54 -0
- data/lib/ronin/core/cli/generator/options/reference.rb +60 -0
- data/lib/ronin/core/cli/generator/options/summary.rb +54 -0
- data/lib/ronin/core/cli/generator.rb +238 -0
- data/lib/ronin/core/cli/logging.rb +59 -0
- data/lib/ronin/core/cli/options/param.rb +68 -0
- data/lib/ronin/core/cli/options/values/arches.rb +45 -0
- data/lib/ronin/core/cli/options/values/oses.rb +32 -0
- data/lib/ronin/core/cli/printing/arch.rb +71 -0
- data/lib/ronin/core/cli/printing/metadata.rb +113 -0
- data/lib/ronin/core/cli/printing/os.rb +54 -0
- data/lib/ronin/core/cli/printing/params.rb +69 -0
- data/lib/ronin/core/cli/ruby_shell.rb +131 -0
- data/lib/ronin/core/cli/shell.rb +186 -0
- data/lib/ronin/core/git.rb +73 -0
- data/lib/ronin/core/home.rb +86 -0
- data/lib/ronin/core/metadata/authors/author.rb +241 -0
- data/lib/ronin/core/metadata/authors.rb +120 -0
- data/lib/ronin/core/metadata/description.rb +100 -0
- data/lib/ronin/core/metadata/id.rb +88 -0
- data/lib/ronin/core/metadata/references.rb +87 -0
- data/lib/ronin/core/metadata/summary.rb +78 -0
- data/lib/ronin/core/metadata/version.rb +74 -0
- data/lib/ronin/core/params/exceptions.rb +38 -0
- data/lib/ronin/core/params/mixin.rb +317 -0
- data/lib/ronin/core/params/param.rb +137 -0
- data/lib/ronin/core/params/types/boolean.rb +64 -0
- data/lib/ronin/core/params/types/enum.rb +107 -0
- data/lib/ronin/core/params/types/float.rb +68 -0
- data/lib/ronin/core/params/types/integer.rb +100 -0
- data/lib/ronin/core/params/types/numeric.rb +106 -0
- data/lib/ronin/core/params/types/regexp.rb +67 -0
- data/lib/ronin/core/params/types/string.rb +118 -0
- data/lib/ronin/core/params/types/type.rb +54 -0
- data/lib/ronin/core/params/types/uri.rb +72 -0
- data/lib/ronin/core/params/types.rb +62 -0
- data/lib/ronin/core/params.rb +19 -0
- data/lib/ronin/core/version.rb +24 -0
- data/ronin-core.gemspec +59 -0
- data/spec/class_registry_spec.rb +224 -0
- data/spec/cli/command_shell/command_spec.rb +113 -0
- data/spec/cli/command_shell_spec.rb +1114 -0
- data/spec/cli/command_spec.rb +16 -0
- data/spec/cli/fixtures/irb_command +8 -0
- data/spec/cli/fixtures/template/dir/file1.txt +1 -0
- data/spec/cli/fixtures/template/dir/file2.txt +1 -0
- data/spec/cli/fixtures/template/file.erb +1 -0
- data/spec/cli/fixtures/template/file.txt +1 -0
- data/spec/cli/generator/options/author_spec.rb +121 -0
- data/spec/cli/generator/options/description_spec.rb +45 -0
- data/spec/cli/generator/options/reference_spec.rb +53 -0
- data/spec/cli/generator/options/summary_spec.rb +45 -0
- data/spec/cli/generator_spec.rb +244 -0
- data/spec/cli/logging_spec.rb +95 -0
- data/spec/cli/options/param_spec.rb +67 -0
- data/spec/cli/options/values/arches_spec.rb +62 -0
- data/spec/cli/printing/arch_spec.rb +130 -0
- data/spec/cli/printing/metadata_spec.rb +211 -0
- data/spec/cli/printing/os_spec.rb +64 -0
- data/spec/cli/printing/params_spec.rb +63 -0
- data/spec/cli/ruby_shell.rb +99 -0
- data/spec/cli/shell_spec.rb +211 -0
- data/spec/fixtures/example_class_registry/base_class.rb +9 -0
- data/spec/fixtures/example_class_registry/classes/loaded_class.rb +9 -0
- data/spec/fixtures/example_class_registry/classes/name_mismatch.rb +9 -0
- data/spec/fixtures/example_class_registry/classes/no_module.rb +4 -0
- data/spec/fixtures/example_class_registry.rb +8 -0
- data/spec/git_spec.rb +58 -0
- data/spec/home_spec.rb +64 -0
- data/spec/metadata/authors/author_spec.rb +335 -0
- data/spec/metadata/authors_spec.rb +126 -0
- data/spec/metadata/description_spec.rb +74 -0
- data/spec/metadata/id_spec.rb +92 -0
- data/spec/metadata/references_spec.rb +100 -0
- data/spec/metadata/summary_spec.rb +74 -0
- data/spec/metadata/version_spec.rb +72 -0
- data/spec/params/mixin_spec.rb +484 -0
- data/spec/params/param_spec.rb +164 -0
- data/spec/params/types/boolean_spec.rb +56 -0
- data/spec/params/types/enum_spec.rb +94 -0
- data/spec/params/types/float_spec.rb +107 -0
- data/spec/params/types/integer_spec.rb +155 -0
- data/spec/params/types/numeric_spec.rb +138 -0
- data/spec/params/types/regexp_spec.rb +64 -0
- data/spec/params/types/string_spec.rb +174 -0
- data/spec/params/types/type_spec.rb +14 -0
- data/spec/params/types/uri_spec.rb +62 -0
- data/spec/spec_helper.rb +11 -0
- metadata +252 -0
data/README.md
ADDED
@@ -0,0 +1,299 @@
|
|
1
|
+
# ronin-core
|
2
|
+
|
3
|
+
[![CI](https://github.com/ronin-rb/ronin-core/actions/workflows/ruby.yml/badge.svg)](https://github.com/ronin-rb/ronin-core/actions/workflows/ruby.yml)
|
4
|
+
[![Code Climate](https://codeclimate.com/github/ronin-rb/ronin-core.svg)](https://codeclimate.com/github/ronin-rb/ronin-core)
|
5
|
+
|
6
|
+
* [Website](https://ronin-rb.dev/)
|
7
|
+
* [Source](https://github.com/ronin-rb/ronin-core)
|
8
|
+
* [Issues](https://github.com/ronin-rb/ronin-core/issues)
|
9
|
+
* [Documentation](https://ronin-rb.dev/docs/ronin-core/frames)
|
10
|
+
* [Discord](https://discord.gg/6WAb3PsVX9) |
|
11
|
+
[Twitter](https://twitter.com/ronin_rb) |
|
12
|
+
[Mastodon](https://infosec.exchange/@ronin_rb)
|
13
|
+
|
14
|
+
## Description
|
15
|
+
|
16
|
+
ronin-core is a core library providing common functionality for all ronin
|
17
|
+
libraries.
|
18
|
+
|
19
|
+
ronin-core is part of the [ronin-rb] project, a toolkit for security research
|
20
|
+
and development.
|
21
|
+
|
22
|
+
## Features
|
23
|
+
|
24
|
+
* Provides access to the XDG directories (`~/.config/`, `~/.cache/`,
|
25
|
+
`~/.local/share`).
|
26
|
+
* Allows querying `~/.gitconfig` for common git settings.
|
27
|
+
* Provides a common `Command` base class for all ronin libraries.
|
28
|
+
* Provides a `Shell` and `CommandShell` base classes for writing interactive
|
29
|
+
shells.
|
30
|
+
* Provides a `Params` API for adding user configurable parameters to classes.
|
31
|
+
* Has 85% documentation coverage.
|
32
|
+
* Has 99% test coverage.
|
33
|
+
|
34
|
+
## Requirements
|
35
|
+
|
36
|
+
* [Ruby] >= 3.0.0
|
37
|
+
* [reline] ~> 0.1
|
38
|
+
* [command_kit] ~> 0.4
|
39
|
+
* [irb] ~> 1.0
|
40
|
+
|
41
|
+
## Install
|
42
|
+
|
43
|
+
### Gemfile
|
44
|
+
|
45
|
+
```ruby
|
46
|
+
gem 'ronin-core', '~> 0.1'
|
47
|
+
```
|
48
|
+
|
49
|
+
### gemspec
|
50
|
+
|
51
|
+
```ruby
|
52
|
+
gem.add_depedency 'ronin-core', '~> 0.1'
|
53
|
+
```
|
54
|
+
|
55
|
+
### [gemspec.yml]
|
56
|
+
|
57
|
+
```yaml
|
58
|
+
dependencies:
|
59
|
+
ronin-core: ~> 0.1
|
60
|
+
```
|
61
|
+
|
62
|
+
## Examples
|
63
|
+
|
64
|
+
### Params
|
65
|
+
|
66
|
+
```ruby
|
67
|
+
class BaseClass
|
68
|
+
|
69
|
+
include Ronin::Core::Params::Mixin
|
70
|
+
|
71
|
+
end
|
72
|
+
```
|
73
|
+
|
74
|
+
```ruby
|
75
|
+
class MyModule < BaseClass
|
76
|
+
|
77
|
+
param :str, desc: 'A basic string param'
|
78
|
+
|
79
|
+
param :feature_flag, Boolean, desc: 'A boolean param'
|
80
|
+
|
81
|
+
param :enum, Enum[:one, :two, :three],
|
82
|
+
desc: 'An enum param'
|
83
|
+
|
84
|
+
param :num1, Integer, desc: 'An integer param'
|
85
|
+
|
86
|
+
param :num2, Integer, default: 42,
|
87
|
+
desc: 'A param with a default value'
|
88
|
+
|
89
|
+
param :num3, Integer, default: ->{ rand(42) },
|
90
|
+
desc: 'A param with a dynamic default value'
|
91
|
+
|
92
|
+
param :float, Float, 'Floating point param'
|
93
|
+
|
94
|
+
param :url, URI, desc: 'URL param'
|
95
|
+
|
96
|
+
param :pattern, Regexp, desc: 'Regular Expression param'
|
97
|
+
|
98
|
+
end
|
99
|
+
|
100
|
+
mod = MyModule.new(params: {num1: 1, enum: :two})
|
101
|
+
mod.params
|
102
|
+
# => {:num2=>42, :num3=>25, :num1=>1, :enum=>:two}
|
103
|
+
```
|
104
|
+
|
105
|
+
### CLI
|
106
|
+
|
107
|
+
Define a main command for `ronin-foo`:
|
108
|
+
|
109
|
+
```ruby
|
110
|
+
# lib/ronin/foo/cli.rb
|
111
|
+
require 'command_kit/commands'
|
112
|
+
require 'command_kit/commands/auto_load'
|
113
|
+
|
114
|
+
module Ronin
|
115
|
+
module Foo
|
116
|
+
class CLI
|
117
|
+
|
118
|
+
include CommandKit::Commands
|
119
|
+
include CommandKit::Commands::AutoLoad.new(
|
120
|
+
dir: "#{__dir__}/cli/commands",
|
121
|
+
namespace: "#{self}::Commands"
|
122
|
+
)
|
123
|
+
|
124
|
+
command_name 'ronin-foo'
|
125
|
+
|
126
|
+
command_aliases['ls'] = 'list'
|
127
|
+
# ...
|
128
|
+
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
```
|
133
|
+
|
134
|
+
Add a `bin/ronin-foo` file (don't forget to `chmod +x` it) that invokes the
|
135
|
+
main command:
|
136
|
+
|
137
|
+
```ruby
|
138
|
+
#!/usr/bin/env ruby
|
139
|
+
|
140
|
+
root = File.expand_path(File.join(__dir__,'..'))
|
141
|
+
if File.file?(File.join(root,'Gemfile.lock'))
|
142
|
+
Dir.chdir(root) do
|
143
|
+
begin
|
144
|
+
require 'bundler/setup'
|
145
|
+
rescue LoadError => e
|
146
|
+
warn e.message
|
147
|
+
warn "Run `gem install bundler` to install Bundler"
|
148
|
+
exit -1
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
require 'ronin/foo/cli'
|
154
|
+
Ronin::Foo::CLI.start
|
155
|
+
```
|
156
|
+
|
157
|
+
Define a common command class for all `ronin-foo`'s commands:
|
158
|
+
|
159
|
+
```ruby
|
160
|
+
# lib/ronin/foo/cli/command.rb
|
161
|
+
require 'ronin/core/cli/command'
|
162
|
+
|
163
|
+
module Ronin
|
164
|
+
module Foo
|
165
|
+
class CLI
|
166
|
+
class Command < Core::CLI::Command
|
167
|
+
|
168
|
+
man_dir File.join(__dir__,'..','..','..','..','man')
|
169
|
+
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
```
|
175
|
+
|
176
|
+
Define a `list` sub-command under the `ronin-foo` main command:
|
177
|
+
|
178
|
+
```ruby
|
179
|
+
# lib/ronin/foo/cli/commands/list.rb
|
180
|
+
require 'ronin/foo/cli/command'
|
181
|
+
|
182
|
+
module Ronin
|
183
|
+
module Foo
|
184
|
+
class CLI
|
185
|
+
module Commands
|
186
|
+
class List < Command
|
187
|
+
|
188
|
+
usage '[options] [NAME]'
|
189
|
+
|
190
|
+
argument :name, required: false,
|
191
|
+
desc: 'Optional name to list'
|
192
|
+
|
193
|
+
description 'Lists all things'
|
194
|
+
|
195
|
+
man_page 'ronin-foo-list.1'
|
196
|
+
|
197
|
+
def run(name=nil)
|
198
|
+
# ...
|
199
|
+
end
|
200
|
+
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
```
|
207
|
+
|
208
|
+
Test it out:
|
209
|
+
|
210
|
+
```shell
|
211
|
+
$ ./bin/ronin-foo
|
212
|
+
Usage: ronin-foo [options] [COMMAND [ARGS...]]
|
213
|
+
|
214
|
+
Options:
|
215
|
+
-h, --help Print help information
|
216
|
+
|
217
|
+
Arguments:
|
218
|
+
[COMMAND] The command name to run
|
219
|
+
[ARGS ...] Additional arguments for the command
|
220
|
+
|
221
|
+
Commands:
|
222
|
+
help
|
223
|
+
list, ls
|
224
|
+
$ ./bin/ronin-foo ls
|
225
|
+
```
|
226
|
+
|
227
|
+
### CLI::CommandShell
|
228
|
+
|
229
|
+
Define a custom command shell:
|
230
|
+
|
231
|
+
```ruby
|
232
|
+
class HTTPShell < Ronin::Core::CLI::CommandShell
|
233
|
+
|
234
|
+
shell_name 'http'
|
235
|
+
|
236
|
+
command :get, usage: 'PATH [HEADERS...]',
|
237
|
+
summary: 'Sends a GET request'
|
238
|
+
def get(path,*headers)
|
239
|
+
# ...
|
240
|
+
end
|
241
|
+
|
242
|
+
command :post, usage: 'PATH DATA [HEADERS...]',
|
243
|
+
summary: 'Sends a POST request'
|
244
|
+
def post(path,data,*headers)
|
245
|
+
# ...
|
246
|
+
end
|
247
|
+
|
248
|
+
end
|
249
|
+
```
|
250
|
+
|
251
|
+
Then start it:
|
252
|
+
|
253
|
+
```ruby
|
254
|
+
HTTPShell.start
|
255
|
+
```
|
256
|
+
|
257
|
+
```
|
258
|
+
http> get /foo
|
259
|
+
...
|
260
|
+
http> post /foo var=bar
|
261
|
+
...
|
262
|
+
```
|
263
|
+
|
264
|
+
## Development
|
265
|
+
|
266
|
+
1. [Fork It!](https://github.com/ronin-rb/ronin-core/fork)
|
267
|
+
2. Clone It!
|
268
|
+
3. `cd ronin-core/`
|
269
|
+
4. `bundle install`
|
270
|
+
5. `git checkout -b my_feature`
|
271
|
+
6. Code It!
|
272
|
+
7. `bundle exec rake spec`
|
273
|
+
8. `git push origin my_feature`
|
274
|
+
|
275
|
+
## License
|
276
|
+
|
277
|
+
Copyright (c) 2021-2022 Hal Brodigan (postmodern.mod3@gmail.com)
|
278
|
+
|
279
|
+
ronin-core is free software: you can redistribute it and/or modify
|
280
|
+
it under the terms of the GNU Lesser General Public License as published
|
281
|
+
by the Free Software Foundation, either version 3 of the License, or
|
282
|
+
(at your option) any later version.
|
283
|
+
|
284
|
+
ronin-core is distributed in the hope that it will be useful,
|
285
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
286
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
287
|
+
GNU Lesser General Public License for more details.
|
288
|
+
|
289
|
+
You should have received a copy of the GNU Lesser General Public License
|
290
|
+
along with ronin-core. If not, see <https://www.gnu.org/licenses/>.
|
291
|
+
|
292
|
+
[ronin-rb]: https://ronin-rb.dev/
|
293
|
+
|
294
|
+
[Ruby]: https://www.ruby-lang.org
|
295
|
+
[command_kit]: https://github.com/postmodern/command_kit.rb#readme
|
296
|
+
[reline]: https://github.com/ruby/reline#readme
|
297
|
+
[irb]: https://github.com/ruby/irb#readme
|
298
|
+
|
299
|
+
[gemspec.yml]: https://github.com/postmodern/gemspec.yml#readme
|
data/Rakefile
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'bundler'
|
5
|
+
rescue LoadError => e
|
6
|
+
warn e.message
|
7
|
+
warn "Run `gem install bundler` to install Bundler"
|
8
|
+
exit(-1)
|
9
|
+
end
|
10
|
+
|
11
|
+
begin
|
12
|
+
Bundler.setup(:development)
|
13
|
+
rescue Bundler::BundlerError => e
|
14
|
+
warn e.message
|
15
|
+
warn "Run `bundle install` to install missing gems"
|
16
|
+
exit e.status_code
|
17
|
+
end
|
18
|
+
|
19
|
+
require 'rake'
|
20
|
+
|
21
|
+
require 'rubygems/tasks'
|
22
|
+
Gem::Tasks.new(sign: {checksum: true, pgp: true})
|
23
|
+
|
24
|
+
require 'rspec/core/rake_task'
|
25
|
+
RSpec::Core::RakeTask.new
|
26
|
+
task :test => :spec
|
27
|
+
task :default => :spec
|
28
|
+
|
29
|
+
require 'yard'
|
30
|
+
YARD::Rake::YardocTask.new
|
31
|
+
task :docs => :yard
|
32
|
+
|
33
|
+
require 'kramdown/man/task'
|
34
|
+
Kramdown::Man::Task.new
|
data/gemspec.yml
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
name: ronin-core
|
2
|
+
summary: A core library for all ronin libraries.
|
3
|
+
description: |
|
4
|
+
ronin-core is a core library providing common functionality for all ronin
|
5
|
+
libraries.
|
6
|
+
|
7
|
+
license: LGPL-3.0
|
8
|
+
authors: Postmodern
|
9
|
+
email: postmodern.mod3@gmail.com
|
10
|
+
homepage: https://ronin-rb.dev/
|
11
|
+
has_yard: true
|
12
|
+
|
13
|
+
metadata:
|
14
|
+
documentation_uri: https://rubydoc.info/gems/ronin-core
|
15
|
+
source_code_uri: https://github.com/ronin-rb/ronin-core
|
16
|
+
bug_tracker_uri: https://github.com/ronin-rb/ronin-core/issues
|
17
|
+
changelog_uri: https://github.com/ronin-rb/ronin-core/blob/main/ChangeLog.md
|
18
|
+
rubygems_mfa_required: 'true'
|
19
|
+
|
20
|
+
required_ruby_version: ">= 3.0.0"
|
21
|
+
|
22
|
+
dependencies:
|
23
|
+
reline: ~> 0.1
|
24
|
+
command_kit: ~> 0.4
|
25
|
+
irb: ~> 1.0
|
26
|
+
|
27
|
+
development_dependencies:
|
28
|
+
bundler: ~> 2.0
|
@@ -0,0 +1,246 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
#
|
3
|
+
# Copyright (c) 2021-2022 Hal Brodigan (postmodern.mod3 at gmail.com)
|
4
|
+
#
|
5
|
+
# ronin-core is free software: you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU Lesser General Public License as published
|
7
|
+
# by the Free Software Foundation, either version 3 of the License, or
|
8
|
+
# (at your option) any later version.
|
9
|
+
#
|
10
|
+
# ronin-core is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# GNU Lesser General Public License for more details.
|
14
|
+
#
|
15
|
+
# You should have received a copy of the GNU Lesser General Public License
|
16
|
+
# along with ronin-core. If not, see <https://www.gnu.org/licenses/>.
|
17
|
+
#
|
18
|
+
|
19
|
+
module Ronin
|
20
|
+
module Core
|
21
|
+
#
|
22
|
+
# A mixin that adds a class registry to a library:
|
23
|
+
#
|
24
|
+
# ### Example
|
25
|
+
#
|
26
|
+
# `lib/ronin/exploits.rb`:
|
27
|
+
#
|
28
|
+
# require 'ronin/core/class_registry'
|
29
|
+
#
|
30
|
+
# module Ronin
|
31
|
+
# module Exploits
|
32
|
+
# include Ronin::Core::ClassRegistry
|
33
|
+
#
|
34
|
+
# class_dir "#{__dir__}/classes"
|
35
|
+
# end
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# `lib/ronin/exploits/exploit.rb`:
|
39
|
+
#
|
40
|
+
# module Ronin
|
41
|
+
# module Exploits
|
42
|
+
# class Exploit
|
43
|
+
#
|
44
|
+
# def self.register(name)
|
45
|
+
# Exploits.register(name,self)
|
46
|
+
# end
|
47
|
+
#
|
48
|
+
# end
|
49
|
+
# end
|
50
|
+
# end
|
51
|
+
#
|
52
|
+
# `lib/ronin/exploits/my_exploit.rb`:
|
53
|
+
#
|
54
|
+
# require 'ronin/exploits/exploit'
|
55
|
+
#
|
56
|
+
# module Ronin
|
57
|
+
# module Exploits
|
58
|
+
# class MyExploit < Exploit
|
59
|
+
#
|
60
|
+
# register 'my_exploit'
|
61
|
+
#
|
62
|
+
# end
|
63
|
+
# end
|
64
|
+
# end
|
65
|
+
#
|
66
|
+
# @api semipublic
|
67
|
+
#
|
68
|
+
module ClassRegistry
|
69
|
+
class ClassNotFound < RuntimeError
|
70
|
+
end
|
71
|
+
|
72
|
+
#
|
73
|
+
# Extends {ClassMethods}.
|
74
|
+
#
|
75
|
+
# @param [Module] namespace
|
76
|
+
# The module that is including {ClassRegistry}.
|
77
|
+
#
|
78
|
+
def self.included(namespace)
|
79
|
+
namespace.extend ClassMethods
|
80
|
+
end
|
81
|
+
|
82
|
+
module ClassMethods
|
83
|
+
#
|
84
|
+
# Gets or sets the class directory path.
|
85
|
+
#
|
86
|
+
# @param [String, nil] new_dir
|
87
|
+
# The new class directory path.
|
88
|
+
#
|
89
|
+
# @return [String]
|
90
|
+
# The class directory path.
|
91
|
+
#
|
92
|
+
# @raise [NotImplementedError]
|
93
|
+
# The `class_dir` method was not defined in the module.
|
94
|
+
#
|
95
|
+
# @example
|
96
|
+
# class_dir "#{__dir__}/classes"
|
97
|
+
#
|
98
|
+
def class_dir(new_dir=nil)
|
99
|
+
if new_dir
|
100
|
+
@class_dir = new_dir
|
101
|
+
else
|
102
|
+
@class_dir || raise(NotImplementedError,"#{self} did not define a class_dir")
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
#
|
107
|
+
# Lists all class files within {#class_dir}.
|
108
|
+
#
|
109
|
+
# @return [Array<String>]
|
110
|
+
# The list of class paths within {#class_dir}.
|
111
|
+
#
|
112
|
+
def list_files
|
113
|
+
paths = Dir.glob('{**/}*.rb', base: class_dir)
|
114
|
+
paths.each { |path| path.chomp!('.rb') }
|
115
|
+
return paths
|
116
|
+
end
|
117
|
+
|
118
|
+
#
|
119
|
+
# The class registry.
|
120
|
+
#
|
121
|
+
# @return [Hash{String => Class}]
|
122
|
+
# The mapping of class `id` and classes.
|
123
|
+
#
|
124
|
+
def registry
|
125
|
+
@registry ||= {}
|
126
|
+
end
|
127
|
+
|
128
|
+
#
|
129
|
+
# Registers a class with the registry.
|
130
|
+
#
|
131
|
+
# @param [String] id
|
132
|
+
# The class `id` to be registered.
|
133
|
+
#
|
134
|
+
# @param [Class] mod
|
135
|
+
# The class to be registered.
|
136
|
+
#
|
137
|
+
# @example
|
138
|
+
# Exploits.register('myexploit',MyExploit)
|
139
|
+
#
|
140
|
+
def register(id,mod)
|
141
|
+
registry[id] = mod
|
142
|
+
end
|
143
|
+
|
144
|
+
#
|
145
|
+
# Finds the path for the class `id`.
|
146
|
+
#
|
147
|
+
# @param [String] id
|
148
|
+
# The class `id`.
|
149
|
+
#
|
150
|
+
# @return [String, nil]
|
151
|
+
# The path for the module. If the module file does not exist in
|
152
|
+
# {#class_dir} then `nil` will be returned.
|
153
|
+
#
|
154
|
+
# @example
|
155
|
+
# Exploits.path_for('my_exploit')
|
156
|
+
# # => "/path/to/lib/ronin/exploits/classes/my_exploit.rb"
|
157
|
+
#
|
158
|
+
def path_for(id)
|
159
|
+
path = File.join(class_dir,"#{id}.rb")
|
160
|
+
|
161
|
+
if File.file?(path)
|
162
|
+
return path
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
#
|
167
|
+
# Loads a class from a file.
|
168
|
+
#
|
169
|
+
# @param [String] file
|
170
|
+
# The file to load.
|
171
|
+
#
|
172
|
+
# @return [Class]
|
173
|
+
# The loaded class.
|
174
|
+
#
|
175
|
+
# @raise [ClassNotFound]
|
176
|
+
# The file does not exist or the class `id` was not found within the
|
177
|
+
# file.
|
178
|
+
#
|
179
|
+
# @raise [LoadError]
|
180
|
+
# A load error curred while requiring the other files required by
|
181
|
+
# the class file.
|
182
|
+
#
|
183
|
+
def load_class_from_file(file)
|
184
|
+
file = File.expand_path(file)
|
185
|
+
|
186
|
+
unless File.file?(file)
|
187
|
+
raise(ClassNotFound,"no such file or directory: #{file.inspect}")
|
188
|
+
end
|
189
|
+
|
190
|
+
previous_entries = registry.keys
|
191
|
+
require(file)
|
192
|
+
new_entries = registry.keys - previous_entries
|
193
|
+
|
194
|
+
if new_entries.empty?
|
195
|
+
raise(ClassNotFound,"file did not register a class: #{file.inspect}")
|
196
|
+
end
|
197
|
+
|
198
|
+
return registry[new_entries.last]
|
199
|
+
end
|
200
|
+
|
201
|
+
#
|
202
|
+
# Loads a class from the {#class_dir}.
|
203
|
+
#
|
204
|
+
# @param [String] id
|
205
|
+
# The class `id` to load.
|
206
|
+
#
|
207
|
+
# @return [Class]
|
208
|
+
# The loaded class.
|
209
|
+
#
|
210
|
+
# @raise [ClassNotFound]
|
211
|
+
# The class file could not be found within {#class_dir}.or has
|
212
|
+
# a file/registered-name mismatch.
|
213
|
+
#
|
214
|
+
# @raise [LoadError]
|
215
|
+
# A load error curred while requiring the other files required by
|
216
|
+
# the class file.
|
217
|
+
#
|
218
|
+
def load_class(id)
|
219
|
+
# short-circuit if the module is already loaded
|
220
|
+
if (klass = registry[id])
|
221
|
+
return klass
|
222
|
+
end
|
223
|
+
|
224
|
+
unless (path = path_for(id))
|
225
|
+
raise(ClassNotFound,"could not find file for #{id.inspect}")
|
226
|
+
end
|
227
|
+
|
228
|
+
previous_entries = registry.keys
|
229
|
+
require(path)
|
230
|
+
|
231
|
+
unless (klass = registry[id])
|
232
|
+
new_entries = registry.keys - previous_entries
|
233
|
+
|
234
|
+
if new_entries.empty?
|
235
|
+
raise(ClassNotFound,"file did not register a class: #{path.inspect}")
|
236
|
+
else
|
237
|
+
raise(ClassNotFound,"file registered a class with a different id (#{new_entries.map(&:inspect).join(', ')}): #{path.inspect}")
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
return klass
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
#
|
3
|
+
# Copyright (c) 2021-2022 Hal Brodigan (postmodern.mod3 at gmail.com)
|
4
|
+
#
|
5
|
+
# ronin-core is free software: you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU Lesser General Public License as published
|
7
|
+
# by the Free Software Foundation, either version 3 of the License, or
|
8
|
+
# (at your option) any later version.
|
9
|
+
#
|
10
|
+
# ronin-core is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
# GNU Lesser General Public License for more details.
|
14
|
+
#
|
15
|
+
# You should have received a copy of the GNU Lesser General Public License
|
16
|
+
# along with ronin-core. If not, see <https://www.gnu.org/licenses/>.
|
17
|
+
#
|
18
|
+
|
19
|
+
require 'command_kit/command'
|
20
|
+
require 'command_kit/help/man'
|
21
|
+
require 'command_kit/bug_report'
|
22
|
+
|
23
|
+
module Ronin
|
24
|
+
module Core
|
25
|
+
module CLI
|
26
|
+
#
|
27
|
+
# Common base class for all CLI commands.
|
28
|
+
#
|
29
|
+
# ## Example
|
30
|
+
#
|
31
|
+
# Define a common CLI command base class for all commands in the
|
32
|
+
# `ronin-foo` library:
|
33
|
+
#
|
34
|
+
# # lib/ronin/foo/cli/command.rb
|
35
|
+
# require 'ronin/core/cli/command'
|
36
|
+
#
|
37
|
+
# module Ronin
|
38
|
+
# module Foo
|
39
|
+
# class CLI
|
40
|
+
# class Command < Core::CLI::Command
|
41
|
+
#
|
42
|
+
# man_dir File.join(__dir__,'..','..','..','..','man')
|
43
|
+
#
|
44
|
+
# end
|
45
|
+
# end
|
46
|
+
# end
|
47
|
+
# end
|
48
|
+
#
|
49
|
+
# Define a sub-command named `list` under the `ronin-foo` main command:
|
50
|
+
#
|
51
|
+
# # lib/ronin/foo/cli/commands/list.rb
|
52
|
+
# require 'ronin/foo/cli/command'
|
53
|
+
#
|
54
|
+
# module Ronin
|
55
|
+
# module Foo
|
56
|
+
# class CLI
|
57
|
+
# module Commands
|
58
|
+
# class List < Command
|
59
|
+
#
|
60
|
+
# usage '[options] [NAME]'
|
61
|
+
#
|
62
|
+
# argument :name, required: false,
|
63
|
+
# desc: 'Optional name to list'
|
64
|
+
#
|
65
|
+
# description 'Lists all things'
|
66
|
+
#
|
67
|
+
# man_page 'ronin-foo-list.1'
|
68
|
+
#
|
69
|
+
# def run(name=nil)
|
70
|
+
# # ...
|
71
|
+
# end
|
72
|
+
#
|
73
|
+
# end
|
74
|
+
# end
|
75
|
+
# end
|
76
|
+
# end
|
77
|
+
# end
|
78
|
+
#
|
79
|
+
class Command < CommandKit::Command
|
80
|
+
|
81
|
+
include CommandKit::Help::Man
|
82
|
+
include CommandKit::BugReport
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|