Skip to content

Commit 33a5d69

Browse files
committed
Added Ronin::Recon::CLI::ConfigFileOption (issue #178).
1 parent 0aedf2b commit 33a5d69

File tree

3 files changed

+182
-17
lines changed

3 files changed

+182
-17
lines changed

lib/ronin/recon/cli/commands/run.rb

+3-17
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#
2020

2121
require_relative '../command'
22+
require_relative '../config_file_option'
2223
require_relative '../debug_option'
2324
require_relative '../printing'
2425
require_relative '../../value/parser'
@@ -65,19 +66,13 @@ module Commands
6566
class Run < Command
6667

6768
include DebugOption
69+
include ConfigFileOption
6870
include Printing
6971
include Core::CLI::Logging
7072
include DB::CLI::DatabaseOptions
7173

7274
usage '[options] {IP | IP-range | DOMAIN | HOST | WILDCARD | WEBSITE} ...'
7375

74-
option :config_file, short: '-C',
75-
value: {
76-
type: String,
77-
usage: 'FILE'
78-
},
79-
desc: 'Loads the configuration file'
80-
8176
option :worker, short: '-w',
8277
value: {
8378
type: String,
@@ -203,11 +198,6 @@ class Run < Command
203198
# @return [Set<String>]
204199
attr_reader :worker_files
205200

206-
# The loaded configuration for the {Engine}.
207-
#
208-
# @return [Config]
209-
attr_reader :config
210-
211201
# The loaded workers for the {Engine}.
212202
#
213203
# @return [Workers]
@@ -339,11 +329,7 @@ def parse_value(value)
339329
# the `--config-file` option or `~/.config/ronin-recon/config.yml`.
340330
#
341331
def load_config
342-
@config = if (path = options[:config_file])
343-
Config.load(path)
344-
else
345-
Config.default
346-
end
332+
super()
347333

348334
unless @only_workers.empty?
349335
@config.workers = @only_workers
+83
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
# frozen_string_literal: true
2+
#
3+
# ronin-recon - A micro-framework and tool for performing reconnaissance.
4+
#
5+
# Copyright (c) 2023-2024 Hal Brodigan ([email protected])
6+
#
7+
# ronin-recon is free software: you can redistribute it and/or modify
8+
# it under the terms of the GNU Lesser General Public License as published
9+
# by the Free Software Foundation, either version 3 of the License, or
10+
# (at your option) any later version.
11+
#
12+
# ronin-recon is distributed in the hope that it will be useful,
13+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
# GNU Lesser General Public License for more details.
16+
#
17+
# You should have received a copy of the GNU Lesser General Public License
18+
# along with ronin-recon. If not, see <https://www.gnu.org/licenses/>.
19+
#
20+
21+
require_relative '../config'
22+
23+
module Ronin
24+
module Recon
25+
class CLI
26+
#
27+
# Defines the `-C, --config-file` option.
28+
#
29+
# @since 0.2.0
30+
#
31+
module ConfigFileOption
32+
#
33+
# Defines the `-C, --config-file` option on the command class that
34+
# included {ConfigFileOption}.
35+
#
36+
# @param [Class] command
37+
# The command class that included {ConfigFileOption}.
38+
#
39+
def self.included(command)
40+
command.option :config_file, short: '-C',
41+
value: {
42+
type: String,
43+
usage: 'FILE'
44+
},
45+
desc: 'Loads the configuration file'
46+
end
47+
48+
# The loaded configuration for the {Engine}.
49+
#
50+
# @return [Config]
51+
attr_reader :config
52+
53+
#
54+
# Loads the recon configuration file from either
55+
# the `--config-file` option or `~/.config/ronin-recon/config.yml`.
56+
#
57+
# @note
58+
# * If the `--config-file` path is missing an error will be printed
59+
# and the command will exit with -1.
60+
# * If the config file is invalid an error will be printed and the
61+
# command will exit with -2.
62+
#
63+
def load_config
64+
@config = begin
65+
if (path = options[:config_file])
66+
unless File.file?(path)
67+
print_error("no such file or directory: #{path}")
68+
exit(-1)
69+
end
70+
71+
Config.load(path)
72+
else
73+
Config.default
74+
end
75+
rescue InvalidConfigFile => error
76+
print_error(error.message)
77+
exit(-2)
78+
end
79+
end
80+
end
81+
end
82+
end
83+
end

spec/cli/config_file_option_spec.rb

+96
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
require 'spec_helper'
2+
require 'ronin/recon/cli/config_file_option'
3+
require 'ronin/recon/cli/command'
4+
5+
describe Ronin::Recon::CLI::ConfigFileOption do
6+
module TestConfigFileOption
7+
class TestCommand < Ronin::Recon::CLI::Command
8+
9+
include Ronin::Recon::CLI::ConfigFileOption
10+
11+
end
12+
end
13+
14+
let(:test_command) { TestConfigFileOption::TestCommand }
15+
subject { test_command.new }
16+
17+
describe ".included" do
18+
subject { test_command }
19+
20+
it "must define a '-C, --config-file' option" do
21+
expect(subject.options[:config_file]).to_not be(nil)
22+
expect(subject.options[:config_file].short).to eq('-C')
23+
expect(subject.options[:config_file].value).to_not be(nil)
24+
expect(subject.options[:config_file].value.type).to be(String)
25+
expect(subject.options[:config_file].desc).to eq('Loads the configuration file')
26+
end
27+
end
28+
29+
describe "#load_config" do
30+
let(:fixtures) { File.join(__dir__,'..','fixtures') }
31+
32+
context "when the '-C, --config-file' option is not given" do
33+
before { subject.load_config }
34+
35+
it "must set @config to `Config.default`" do
36+
expect(subject.config).to eq(Ronin::Recon::Config.default)
37+
end
38+
end
39+
40+
context "when the '-C, --config-file' option is given" do
41+
context "and the config file exists and is valid" do
42+
let(:config_file) { File.join(fixtures,'config.yml') }
43+
44+
before do
45+
subject.options[:config_file] = config_file
46+
47+
subject.load_config
48+
end
49+
50+
it "must load the config file and set @config" do
51+
expect(subject.config).to eq(
52+
Ronin::Recon::Config.load(config_file)
53+
)
54+
end
55+
end
56+
57+
context "but the config file does not exist" do
58+
let(:config_file) { 'does/not/exist.yml' }
59+
60+
before do
61+
subject.options[:config_file] = config_file
62+
end
63+
64+
it "must print an error and exit with -1" do
65+
expect(subject).to receive(:print_error).with("no such file or directory: #{config_file}")
66+
67+
expect {
68+
subject.load_config
69+
}.to raise_error(SystemExit) do |error|
70+
expect(error.status).to eq(-1)
71+
end
72+
end
73+
end
74+
75+
context "but the config file is invalid" do
76+
let(:fixtures_dir) { File.join(__dir__,'..','fixtures') }
77+
let(:config_file) { File.join(fixtures_dir,'config','does_not_contain_a_hash.yml') }
78+
let(:yaml) { YAML.load_file(config_file) }
79+
80+
before do
81+
subject.options[:config_file] = config_file
82+
end
83+
84+
it "must print an error and exit with -2" do
85+
expect(subject).to receive(:print_error).with("invalid config file (#{config_file.inspect}): must contain a Hash: #{yaml.inspect}")
86+
87+
expect {
88+
subject.load_config
89+
}.to raise_error(SystemExit) do |error|
90+
expect(error.status).to eq(-2)
91+
end
92+
end
93+
end
94+
end
95+
end
96+
end

0 commit comments

Comments
 (0)