ronin-core 0.1.0.beta1
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/.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
|
+
[](https://github.com/ronin-rb/ronin-core/actions/workflows/ruby.yml)
|
|
4
|
+
[](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
|