diff --git a/README.md b/README.md
index 3f97696..f52b9c3 100644
--- a/README.md
+++ b/README.md
@@ -74,6 +74,7 @@ Arguments:
Commands:
completion
+ config
help
irb
new
@@ -215,6 +216,24 @@ Save the recon results to a PDF image:
$ ronin-recon run -o output.pdf example.com
```
+Enable an optional worker by default:
+
+```shell
+$ ronin-recon config enable api/hunter_io
+```
+
+Set the default concurrency for a worker:
+
+```shell
+$ ronin-recon config set --concurrency web/spider=4
+```
+
+Set the API key for a worker:
+
+```shell
+$ ronin-recon config set --param api/hunter_io.api_key=...
+```
+
Generate a boilerplate recon worker file, with some custom information:
```shell
diff --git a/gemspec.yml b/gemspec.yml
index 76284fd..ed8804d 100644
--- a/gemspec.yml
+++ b/gemspec.yml
@@ -27,6 +27,13 @@ generated_files:
- data/completions/ronin-recon
- man/ronin-recon.1
- man/ronin-recon-completion.1
+ - man/ronin-recon-config.1
+ - man/ronin-recon-config-disable.1
+ - man/ronin-recon-config-enable.1
+ - man/ronin-recon-config-get.1
+ - man/ronin-recon-config-list.1
+ - man/ronin-recon-config-set.1
+ - man/ronin-recon-config-unset.1
- man/ronin-recon-irb.1
- man/ronin-recon-new.1
- man/ronin-recon-workers.1
diff --git a/lib/ronin/recon/cli/commands/config.rb b/lib/ronin/recon/cli/commands/config.rb
new file mode 100644
index 0000000..8523e19
--- /dev/null
+++ b/lib/ronin/recon/cli/commands/config.rb
@@ -0,0 +1,92 @@
+# frozen_string_literal: true
+#
+# ronin-recon - A micro-framework and tool for performing reconnaissance.
+#
+# Copyright (c) 2023-2024 Hal Brodigan (postmodern.mod3@gmail.com)
+#
+# ronin-recon is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# ronin-recon is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with ronin-recon. If not, see .
+#
+
+require_relative '../command'
+
+require 'command_kit/commands/auto_load'
+
+module Ronin
+ module Recon
+ class CLI
+ module Commands
+ #
+ # Get and set ronin-recon configuration.
+ #
+ # ## Usage
+ #
+ # ronin-recon config [options] [COMMAND [ARGS...]]
+ #
+ # ## Options
+ #
+ # -h, --help Print help information
+ #
+ # ## Arguments
+ #
+ # [COMMAND] The command name to run
+ # [ARGS ...] Additional arguments for the command
+ #
+ # ## Commands
+ #
+ # disable
+ # enable
+ # get
+ # help
+ # list
+ # set
+ # unset
+ #
+ # ## Examples
+ #
+ # ronin-recon config list
+ # ronin-recon config enable api/hunter_io
+ # ronin-recon config disable api/hunter_io
+ # ronin-recon config set --param api/hunter_io.api_key=...
+ # ronin-recon config set --concurrency web/spider=10
+ # ronin-recon config unset --param web/spider.proxy
+ # ronin-recon config unset --concurrency web/spider
+ #
+ # @since 0.2.0
+ #
+ class Config < Command
+
+ include CommandKit::Commands::AutoLoad.new(
+ dir: "#{__dir__}/config",
+ namespace: "#{self}"
+ )
+
+ examples [
+ 'list',
+ 'enable api/hunter_io',
+ 'disable api/hunter_io',
+ 'set --param api/hunter_io.api_key=...',
+ 'set --concurrency web/spider=10',
+ 'unset --param web/spider.proxy',
+ 'unset --concurrency web/spider'
+ ]
+
+ description 'Get and set ronin-recon configuration'
+
+ man_page 'ronin-recon-config.1'
+
+ end
+ end
+ end
+ end
+end
diff --git a/lib/ronin/recon/cli/commands/config/disable.rb b/lib/ronin/recon/cli/commands/config/disable.rb
new file mode 100644
index 0000000..2d4e491
--- /dev/null
+++ b/lib/ronin/recon/cli/commands/config/disable.rb
@@ -0,0 +1,74 @@
+# frozen_string_literal: true
+#
+# ronin-recon - A micro-framework and tool for performing reconnaissance.
+#
+# Copyright (c) 2023-2024 Hal Brodigan (postmodern.mod3@gmail.com)
+#
+# ronin-recon is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# ronin-recon is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with ronin-recon. If not, see .
+#
+
+require_relative '../../config_command'
+
+module Ronin
+ module Recon
+ class CLI
+ module Commands
+ class Config < Command
+ #
+ # Disables a worker in the configuration file.
+ #
+ # ## Usage
+ #
+ # ronin-recon config disable [options] WORKER
+ #
+ # ## Options
+ #
+ # -C, --config-file FILE Loads the configuration file
+ # -h, --help Print help information
+ #
+ # ## Arguments
+ #
+ # WORKER The worker ID to disable
+ #
+ # @since 0.2.0
+ #
+ class Disable < ConfigCommand
+
+ argument :worker, required: true,
+ desc: 'The worker ID to disable'
+
+ description "Disables a worker in the configuration file"
+
+ man_page 'ronin-recon-config-disable.1'
+
+ #
+ # Runs the `ronin-recon config disable` command.
+ #
+ # @param [String] worker
+ # The worker ID to disable.
+ #
+ def run(worker)
+ load_config
+
+ @config.workers.delete(worker)
+
+ save_config
+ end
+
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/ronin/recon/cli/commands/config/enable.rb b/lib/ronin/recon/cli/commands/config/enable.rb
new file mode 100644
index 0000000..afa3310
--- /dev/null
+++ b/lib/ronin/recon/cli/commands/config/enable.rb
@@ -0,0 +1,73 @@
+# frozen_string_literal: true
+#
+# ronin-recon - A micro-framework and tool for performing reconnaissance.
+#
+# Copyright (c) 2023-2024 Hal Brodigan (postmodern.mod3@gmail.com)
+#
+# ronin-recon is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# ronin-recon is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with ronin-recon. If not, see .
+#
+
+require_relative '../../config_command'
+
+module Ronin
+ module Recon
+ class CLI
+ module Commands
+ class Config < Command
+ #
+ # Enables a worker in the configuration file.
+ #
+ # ## Usage
+ #
+ # ronin-recon config enable [options] WORKER
+ #
+ # ## Options
+ #
+ # -C, --config-file FILE Loads the configuration file
+ # -h, --help Print help information
+ #
+ # ## Arguments
+ #
+ # WORKER The worker ID to enable
+ #
+ # @since 0.2.0
+ #
+ class Enable < ConfigCommand
+
+ argument :worker, required: true,
+ desc: 'The worker ID to enable'
+
+ description "Enables a worker in the configuration file"
+
+ man_page 'ronin-recon-config-enable.1'
+
+ #
+ # Runs the `ronin-recon config enable` command.
+ #
+ # @param [String] worker
+ #
+ def run(worker)
+ load_config
+
+ @config.workers.add(worker)
+
+ save_config
+ end
+
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/ronin/recon/cli/commands/config/get.rb b/lib/ronin/recon/cli/commands/config/get.rb
new file mode 100644
index 0000000..57eeea3
--- /dev/null
+++ b/lib/ronin/recon/cli/commands/config/get.rb
@@ -0,0 +1,115 @@
+# frozen_string_literal: true
+#
+# ronin-recon - A micro-framework and tool for performing reconnaissance.
+#
+# Copyright (c) 2023-2024 Hal Brodigan (postmodern.mod3@gmail.com)
+#
+# ronin-recon is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# ronin-recon is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with ronin-recon. If not, see .
+#
+
+require_relative '../../config_command'
+
+module Ronin
+ module Recon
+ class CLI
+ module Commands
+ class Config < Command
+ #
+ # Gets the concurrency or a param for a worker.
+ #
+ # ## Usage
+ #
+ # ronin-recon config get [options] {--concurrency WORKER | --param WORKER.NAME}
+ #
+ # ## Options
+ #
+ # -C, --config-file FILE Loads the configuration file
+ # -c, --concurrency WORKER Gets the concurrency of a worker
+ # -p, --param WORKER.PARAM Gets a param for a worker
+ # -h, --help Print help information
+ #
+ # @since 0.2.0
+ #
+ class Get < ConfigCommand
+
+ usage '[options] {--concurrency WORKER | --param WORKER.NAME}'
+
+ option :concurrency, short: '-c',
+ value: {
+ type: String,
+ usage: 'WORKER'
+ },
+ desc: 'Gets the concurrency for the worker' do |worker|
+ @mode = :concurrency
+ @worker = worker
+ end
+
+ option :param, short: '-p',
+ value: {
+ type: /\A([^\.\=\s]+)\.([^=\s]+)\z/,
+ usage: 'WORKER.PARAM'
+ },
+ desc: 'Gets the param for the worker' do |str,worker,param|
+ @mode = :param
+ @worker = worker
+ @param = param.to_sym
+ end
+
+ description 'Gets the concurrency or a param for a worker'
+
+ man_page 'ronin-recon-config-get.1'
+
+ # Specifies whether to unset the worker's concurrency or param.
+ #
+ # @return [:concurrency, :param, nil]
+ attr_reader :mode
+
+ # The worker name.
+ #
+ # @return [String, nil]
+ attr_reader :worker
+
+ # The param name to unset.
+ #
+ # @return [Symbol, nil]
+ attr_reader :param
+
+ #
+ # Runs the `ronin-recon config set` command.
+ #
+ def run
+ load_config
+
+ case @mode
+ when :concurrency
+ if (concurrency = @config.concurrency[@worker])
+ puts concurrency
+ end
+ when :param
+ if (params = @config.params[@worker]) &&
+ (value = params[@param])
+ puts value
+ end
+ else
+ print_error "--concurrency or --param options must be given"
+ exit(-1)
+ end
+ end
+
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/ronin/recon/cli/commands/config/list.rb b/lib/ronin/recon/cli/commands/config/list.rb
new file mode 100644
index 0000000..0a574df
--- /dev/null
+++ b/lib/ronin/recon/cli/commands/config/list.rb
@@ -0,0 +1,85 @@
+# frozen_string_literal: true
+#
+# ronin-recon - A micro-framework and tool for performing reconnaissance.
+#
+# Copyright (c) 2023-2024 Hal Brodigan (postmodern.mod3@gmail.com)
+#
+# ronin-recon is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# ronin-recon is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with ronin-recon. If not, see .
+#
+
+require_relative '../../config_command'
+
+module Ronin
+ module Recon
+ class CLI
+ module Commands
+ class Config < Command
+ #
+ # Lists the values in the configuration file.
+ #
+ # ## Usage
+ #
+ # ronin-recon config list [options]
+ #
+ # ## Options
+ #
+ # -C, --config-file FILE Loads the configuration file
+ # -h, --help Print help information
+ #
+ # @since 0.2.0
+ #
+ class List < ConfigCommand
+
+ description "Lists the values in the configuration file"
+
+ man_page 'ronin-recon-config-list.1'
+
+ #
+ # Runs the `ronin-recon config list` command.
+ #
+ def run
+ load_config
+
+ puts "Workers:"
+ @config.workers.each do |worker_id|
+ puts " * #{worker_id}"
+ end
+
+ unless @config.concurrency.empty?
+ puts
+ puts "Concurrency:"
+ @config.concurrency.each do |worker_id,concurrency|
+ puts " * #{worker_id}=#{concurrency}"
+ end
+ end
+
+ unless @config.params.empty?
+ puts
+ puts "Params:"
+ @config.params.each do |worker_id,params|
+ puts " * #{worker_id}"
+
+ params.each do |name,value|
+ puts " * #{name}=#{value}"
+ end
+ end
+ end
+ end
+
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/ronin/recon/cli/commands/config/set.rb b/lib/ronin/recon/cli/commands/config/set.rb
new file mode 100644
index 0000000..305df21
--- /dev/null
+++ b/lib/ronin/recon/cli/commands/config/set.rb
@@ -0,0 +1,120 @@
+# frozen_string_literal: true
+#
+# ronin-recon - A micro-framework and tool for performing reconnaissance.
+#
+# Copyright (c) 2023-2024 Hal Brodigan (postmodern.mod3@gmail.com)
+#
+# ronin-recon is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# ronin-recon is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with ronin-recon. If not, see .
+#
+
+require_relative '../../config_command'
+
+module Ronin
+ module Recon
+ class CLI
+ module Commands
+ class Config < Command
+ #
+ # Sets the concurrency or a param for a worker.
+ #
+ # ## Usage
+ #
+ # ronin-recon config set [options]
+ #
+ # ## Options
+ #
+ # -C, --config-file FILE Loads the configuration file
+ # -c, --concurrency WORKER=NUM Sets the concurrency of a worker
+ # -p, --param WORKER.NAME=VALUE Sets a param for a worker
+ # -h, --help Print help information
+ #
+ # @since 0.2.0
+ #
+ class Set < ConfigCommand
+
+ option :concurrency, short: '-c',
+ value: {
+ type: /\A([^\.\=\s]+)=(\d+)\z/,
+ usage: 'WORKER=NUM'
+ },
+ desc: 'Gets the concurrency for the worker' do |str,worker,concurrency|
+ @mode = :concurrency
+ @worker = worker
+ @concurrency = concurrency.to_i
+ end
+
+ option :param, short: '-p',
+ value: {
+ type: /\A([^\.\=\s]+)\.([^=\s]+)=(.+)\z/,
+ usage: 'WORKER.NAME=VALUE'
+ },
+ desc: 'Gets the param for the worker' do |str,worker,param_name,param_value|
+ @mode = :param
+ @worker = worker
+ @param_name = param_name.to_sym
+ @param_value = param_value
+ end
+
+ description "Sets the concurrency or a param for a worker"
+
+ man_page 'ronin-recon-config-set.1'
+
+ # The worker name.
+ #
+ # @return [String, nil]
+ attr_reader :worker
+
+ # The concurrency value to set.
+ #
+ # @return [Integer, nil]
+ attr_reader :concurrency
+
+ # The param name to set.
+ #
+ # @return [Symbol, nil]
+ attr_reader :param_name
+
+ # The param value to set.
+ #
+ # @return [String, nil]
+ attr_reader :param_value
+
+ #
+ # Runs the `ronin-recon config set` command.
+ #
+ def run
+ load_config
+
+ if @concurrency
+ @config.concurrency[@worker] = @concurrency
+ elsif @param_name
+ if (params = @config.params[@worker])
+ params[@param_name] = @param_value
+ else
+ @config.params[@worker] = {@param_name => @param_value}
+ end
+ else
+ print_error "--concurrency or --param options must be given"
+ exit(-1)
+ end
+
+ save_config
+ end
+
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/ronin/recon/cli/commands/config/unset.rb b/lib/ronin/recon/cli/commands/config/unset.rb
new file mode 100644
index 0000000..7984654
--- /dev/null
+++ b/lib/ronin/recon/cli/commands/config/unset.rb
@@ -0,0 +1,114 @@
+# frozen_string_literal: true
+#
+# ronin-recon - A micro-framework and tool for performing reconnaissance.
+#
+# Copyright (c) 2023-2024 Hal Brodigan (postmodern.mod3@gmail.com)
+#
+# ronin-recon is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# ronin-recon is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with ronin-recon. If not, see .
+#
+
+require_relative '../../config_command'
+
+module Ronin
+ module Recon
+ class CLI
+ module Commands
+ class Config < Command
+ #
+ # Unsets the concurrency or params for a worker.
+ #
+ # ## Usage
+ #
+ # ronin-recon config unset [options] {--concurrency WORKER | --param WORKER.NAME}
+ #
+ # ## Options
+ #
+ # -C, --config-file FILE Loads the configuration file
+ # -c, --concurrency WORKER Gets the concurrency of a worker
+ # -p, --param WORKER.PARAM Gets a param for a worker
+ # -h, --help Print help information
+ #
+ # @since 0.2.0
+ #
+ class Unset < ConfigCommand
+
+ usage '[options] {--concurrency WORKER | --param WORKER.NAME}'
+
+ option :concurrency, short: '-c',
+ value: {
+ type: String,
+ usage: 'WORKER'
+ },
+ desc: 'Gets the concurrency for the worker' do |worker|
+ @mode = :concurrency
+ @worker = worker
+ end
+
+ option :param, short: '-p',
+ value: {
+ type: /\A([^\.\=\s]+)\.([^=\s]+)\z/,
+ usage: 'WORKER.PARAM'
+ },
+ desc: 'Gets the param for the worker' do |str,worker,param|
+ @mode = :param
+ @worker = worker
+ @param = param.to_sym
+ end
+
+ description 'Unsets the concurrency or params for a worker'
+
+ man_page 'ronin-recon-config-unset.1'
+
+ # Specifies whether to unset the worker's concurrency or param.
+ #
+ # @return [:concurrency, :param, nil]
+ attr_reader :mode
+
+ # The worker name.
+ #
+ # @return [String, nil]
+ attr_reader :worker
+
+ # The param name to unset.
+ #
+ # @return [String, nil]
+ attr_reader :param
+
+ #
+ # Runs the `ronin-recon config unset` command.
+ #
+ def run
+ load_config
+
+ case @mode
+ when :concurrency
+ @config.concurrency.delete(@worker)
+ when :param
+ if (params = @config.params[@worker])
+ params.delete(@param)
+ end
+ else
+ print_error "--concurrency or --param options must be given"
+ exit(-1)
+ end
+
+ save_config
+ end
+
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/ronin/recon/cli/config_command.rb b/lib/ronin/recon/cli/config_command.rb
new file mode 100644
index 0000000..88c1bfc
--- /dev/null
+++ b/lib/ronin/recon/cli/config_command.rb
@@ -0,0 +1,51 @@
+# frozen_string_literal: true
+#
+# ronin-recon - A micro-framework and tool for performing reconnaissance.
+#
+# Copyright (c) 2023-2024 Hal Brodigan (postmodern.mod3@gmail.com)
+#
+# ronin-recon is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# ronin-recon is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with ronin-recon. If not, see .
+#
+
+require_relative 'command'
+require_relative 'config_file_option'
+
+module Ronin
+ module Recon
+ class CLI
+ #
+ # Base class for all `ronin-recon config` sub-commands.
+ #
+ # @since 0.2.0
+ #
+ class ConfigCommand < Command
+
+ include ConfigFileOption
+
+ #
+ # Saves the configuration back out to either the `--config-file`
+ # path or `~/.config/ronin-recon/config.yml`.
+ #
+ def save_config
+ if (config_file = options[:config_file])
+ @config.save(config_file)
+ else
+ @config.save
+ end
+ end
+
+ end
+ end
+ end
+end
diff --git a/man/ronin-recon-config-disable.1.md b/man/ronin-recon-config-disable.1.md
new file mode 100644
index 0000000..b9ac58a
--- /dev/null
+++ b/man/ronin-recon-config-disable.1.md
@@ -0,0 +1,40 @@
+# ronin-recon-config-disable 1 "2024-09-03" Ronin Recon "User Manuals"
+
+## NAME
+
+ronin-recon-config-disable - Disables a worker in the configuration file
+
+## SYNOPSIS
+
+`ronin-recon config disable` [*options*] *WORKER*
+
+## DESCRIPTION
+
+Disables a worker in the configuration file. This will prevent the worker from
+running by default when `ronin-recon run` is ran.
+
+## ARGUMENTS
+
+*WORKER*
+: The worker ID to disable.
+
+## OPTIONS
+
+`-C`, `--config-file` *FILE*
+: Loads the configuration file from another file.
+
+`-h`, `--help`
+: Print help information
+
+## FILES
+
+`~/.config/ronin-recon/config.yml`
+: The path to the default configuration file for `ronin-recon`.
+
+## AUTHOR
+
+Postmodern
+
+## SEE ALSO
+
+[ronin-recon-config-enable](ronin-recon-config-enable.1.md) [ronin-recon-config-list](ronin-recon-config-list.1.md)
diff --git a/man/ronin-recon-config-enable.1.md b/man/ronin-recon-config-enable.1.md
new file mode 100644
index 0000000..a372843
--- /dev/null
+++ b/man/ronin-recon-config-enable.1.md
@@ -0,0 +1,40 @@
+# ronin-recon-config-enable 1 "2024-09-03" Ronin Recon "User Manuals"
+
+## NAME
+
+ronin-recon-config-enable - Enables a worker in the configuration file
+
+## SYNOPSIS
+
+`ronin-recon config enable` [*options*] *WORKER*
+
+## DESCRIPTION
+
+Enables a worker in the configuration file. This will cause the worker to
+automatically run by default when `ronin-recon run` is ran.
+
+## ARGUMENTS
+
+*WORKER*
+: The worker ID to enable.
+
+## OPTIONS
+
+`-C`, `--config-file` *FILE*
+: Loads the configuration file from another file.
+
+`-h`, `--help`
+: Print help information
+
+## FILES
+
+`~/.config/ronin-recon/config.yml`
+: The path to the default configuration file for `ronin-recon`.
+
+## AUTHOR
+
+Postmodern
+
+## SEE ALSO
+
+[ronin-recon-config-disable](ronin-recon-config-disable.1.md) [ronin-recon-config-list](ronin-recon-config-list.1.md)
diff --git a/man/ronin-recon-config-get.1.md b/man/ronin-recon-config-get.1.md
new file mode 100644
index 0000000..6bf8d56
--- /dev/null
+++ b/man/ronin-recon-config-get.1.md
@@ -0,0 +1,40 @@
+# ronin-recon-config-get 1 "2024-09-03" Ronin Recon "User Manuals"
+
+## NAME
+
+ronin-recon-config-get - Gets the concurrency or a param for a worker
+
+## SYNOPSIS
+
+`ronin-recon config get` [*options*] {`--concurrency` *WORKER* \| `--param` *WORKER*`.`*NAME*}
+
+## DESCRIPTION
+
+Gets the concurrency setting for a *WORKER* or a param value for the *WORKER*.
+
+## OPTIONS
+
+`-C`, `--config-file` *FILE*
+: Loads the configuration file from another file.
+
+`-c`, `--concurrency` *WORKER*
+: Gets the concurrency of the *WORKER*.
+
+`-p`, `--param` *WORKER*`.`*PARAM*
+: Get the param value for the *PARAM* and *WORKER*.
+
+`-h`, `--help`
+: Print help information
+
+## FILES
+
+`~/.config/ronin-recon/config.yml`
+: The path to the default configuration file for `ronin-recon`.
+
+## AUTHOR
+
+Postmodern
+
+## SEE ALSO
+
+[ronin-recon-config-list](ronin-recon-config-list.1.md) [ronin-recon-config-set](ronin-recon-config-set.1.md) [ronin-recon-config-unset](ronin-recon-config-unset.1.md)
diff --git a/man/ronin-recon-config-list.1.md b/man/ronin-recon-config-list.1.md
new file mode 100644
index 0000000..fd08e0e
--- /dev/null
+++ b/man/ronin-recon-config-list.1.md
@@ -0,0 +1,35 @@
+# ronin-recon-config-list 1 "2024-09-03" Ronin Recon "User Manuals"
+
+## NAME
+
+ronin-recon-config-list - Lists the values in the configuration file
+
+## SYNOPSIS
+
+`ronin-recon config list` [*options*]
+
+## DESCRIPTION
+
+Prints the enabled workers, concurrency settings, and params for each worker,
+set in the configuration file.
+
+## OPTIONS
+
+`-C`, `--config-file` *FILE*
+: Loads the configuration file from another file.
+
+`-h`, `--help`
+: Print help information
+
+## FILES
+
+`~/.config/ronin-recon/config.yml`
+: The path to the default configuration file for `ronin-recon`.
+
+## AUTHOR
+
+Postmodern
+
+## SEE ALSO
+
+[ronin-recon-config-disable](ronin-recon-config-disable.1.md) [ronin-recon-config-enable](ronin-recon-config-enable.1.md) [ronin-recon-config-get](ronin-recon-config-get.1.md) [ronin-recon-config-set](ronin-recon-config-set.1.md) [ronin-recon-config-unset](ronin-recon-config-unset.1.md)
diff --git a/man/ronin-recon-config-set.1.md b/man/ronin-recon-config-set.1.md
new file mode 100644
index 0000000..f04561c
--- /dev/null
+++ b/man/ronin-recon-config-set.1.md
@@ -0,0 +1,40 @@
+# ronin-recon-config-set 1 "2024-09-03" Ronin Recon "User Manuals"
+
+## NAME
+
+ronin-recon-config-set - Sets the concurrency or a param for a worker
+
+## SYNOPSIS
+
+`ronin-recon config set` [*options*] {`--concurrency` *WORKER*`=`*NUM* \| `--param` *WORKER*`.`*NAME*`=`*VALUE*}
+
+## DESCRIPTION
+
+Sets the concurrency setting for a *WORKER* or a param value for the *WORKER*.
+
+## OPTIONS
+
+`-C`, `--config-file` *FILE*
+: Loads the configuration file from another file.
+
+`-c`, `--concurrency` *WORKER*`=`*NUM*
+: Sets the concurrency for the *WORKER*.
+
+`-p`, `--param` *WORKER*`.`*PARAM*`=`*VALUE*
+: Set the param value for the *PARAM* and *WORKER*.
+
+`-h`, `--help`
+: Print help information
+
+## FILES
+
+`~/.config/ronin-recon/config.yml`
+: The path to the default configuration file for `ronin-recon`.
+
+## AUTHOR
+
+Postmodern
+
+## SEE ALSO
+
+[ronin-recon-config-list](ronin-recon-config-list.1.md) [ronin-recon-config-get](ronin-recon-config-get.1.md) [ronin-recon-config-unset](ronin-recon-config-unset.1.md)
diff --git a/man/ronin-recon-config-unset.1.md b/man/ronin-recon-config-unset.1.md
new file mode 100644
index 0000000..3bbd6e4
--- /dev/null
+++ b/man/ronin-recon-config-unset.1.md
@@ -0,0 +1,42 @@
+# ronin-recon-config-unset 1 "2024-09-03" Ronin Recon "User Manuals"
+
+## NAME
+
+ronin-recon-config-unset - Unsets the concurrency or params for a worker
+
+## SYNOPSIS
+
+`ronin-recon config unset` [*options*] {`--concurrency` *WORKER* \| `--param` *WORKER*`.`*NAME*}
+
+## DESCRIPTION
+
+Unsets the concurrency setting for a *WORKER* or a param value for the *WORKER*.
+This will cause the *WORKER* to revert to using the default concurrency value
+or the default param value.
+
+## OPTIONS
+
+`-C`, `--config-file` *FILE*
+: Loads the configuration file from another file.
+
+`-c`, `--concurrency` *WORKER*
+: Unsets the concurrency of the *WORKER*.
+
+`-p`, `--param` *WORKER*`.`*PARAM*
+: Unsets the param value for the *PARAM* and *WORKER*.
+
+`-h`, `--help`
+: Print help information
+
+## FILES
+
+`~/.config/ronin-recon/config.yml`
+: The path to the default configuration file for `ronin-recon`.
+
+## AUTHOR
+
+Postmodern
+
+## SEE ALSO
+
+[ronin-recon-config-list](ronin-recon-config-list.1.md) [ronin-recon-config-get](ronin-recon-config-get.1.md) [ronin-recon-config-set](ronin-recon-config-set.1.md)
diff --git a/man/ronin-recon-config.1.md b/man/ronin-recon-config.1.md
new file mode 100644
index 0000000..ff516f4
--- /dev/null
+++ b/man/ronin-recon-config.1.md
@@ -0,0 +1,55 @@
+# ronin-recon-config 1 "2024-09-03" Ronin Recon "User Manuals"
+
+## NAME
+
+ronin-recon-config - Get and set ronin-recon configuration
+
+## SYNOPSIS
+
+`ronin-recon config` [*options*] [*COMMAND* [...]]
+
+## DESCRIPTION
+
+Runs a `ronin-recon config` *COMMAND* that can get or set `ronin-recon`
+configuration settings.
+
+## ARGUMENTS
+
+*COMMAND*
+: The `ronin-recon config` command to execute.
+
+## OPTIONS
+
+`-V`, `--version`
+: Prints the `ronin-recon` version and exits.
+
+`-h`, `--help`
+: Print help information
+
+## COMMANDS
+
+*disable*
+: Disables a worker in the configuration file.
+
+*enable*
+: Enables a worker in the configuration file.
+
+*get*
+: Gets the concurrency or a param for a worker.
+
+*list*
+: Lists the values in the configuration file.
+
+*set*
+: Sets the concurrency or a param for a worker.
+
+*unset*
+: Unsets the concurrency or params for a worker.
+
+## AUTHOR
+
+Postmodern
+
+## SEE ALSO
+
+[ronin-recon-config-disable](ronin-recon-config-disable.1.md) [ronin-recon-config-enable](ronin-recon-config-enable.1.md) [ronin-recon-config-get](ronin-recon-config-get.1.md) [ronin-recon-config-list](ronin-recon-config-list.1.md) [ronin-recon-config-set](ronin-recon-config-set.1.md) [ronin-recon-config-unset](ronin-recon-config-unset.1.md)
diff --git a/man/ronin-recon.1.md b/man/ronin-recon.1.md
index fa7410d..ff7030e 100644
--- a/man/ronin-recon.1.md
+++ b/man/ronin-recon.1.md
@@ -30,6 +30,9 @@ Runs a `ronin-recon` *COMMAND*.
*completion*
: Manages the shell completion rules for `ronin-recon`.
+*config*
+: Get and set ronin-recon configuration.
+
*help*
: Lists available commands or shows help about a specific command.
@@ -57,4 +60,4 @@ Postmodern
## SEE ALSO
-[ronin-recon-completion](ronin-recon-completion.1.md) [ronin-recon-new](ronin-recon-new.1.md) [ronin-recon-test](ronin-recon-test.1.md) [ronin-recon-worker](ronin-recon-worker.1.md) [ronin-recon-workers](ronin-recon-workers.1.md)
+[ronin-recon-completion](ronin-recon-completion.1.md) [ronin-recon-config](ronin-recon-config.1.md) [ronin-recon-new](ronin-recon-new.1.md) [ronin-recon-test](ronin-recon-test.1.md) [ronin-recon-worker](ronin-recon-worker.1.md) [ronin-recon-workers](ronin-recon-workers.1.md)
diff --git a/spec/cli/commands/config/disable_spec.rb b/spec/cli/commands/config/disable_spec.rb
new file mode 100644
index 0000000..3489e96
--- /dev/null
+++ b/spec/cli/commands/config/disable_spec.rb
@@ -0,0 +1,33 @@
+require 'spec_helper'
+require 'ronin/recon/cli/commands/config/disable'
+
+require_relative '../man_page_example'
+
+require 'tempfile'
+
+describe Ronin::Recon::CLI::Commands::Config::Disable do
+ include_examples "man_page"
+
+ describe "#run" do
+ let(:tempfile) { Tempfile.new(['ronin-recon-config-','.yml']) }
+ let(:config_file) { tempfile.path }
+
+ let(:worker) { 'dns/reverse_lookup' }
+
+ before do
+ config = Ronin::Recon::Config.new
+ config.save(config_file)
+ end
+
+ before do
+ subject.options[:config_file] = config_file
+ end
+
+ it "must disable the worker in the config file" do
+ subject.run(worker)
+
+ config = Ronin::Recon::Config.load(config_file)
+ expect(config.workers).to_not include(worker)
+ end
+ end
+end
diff --git a/spec/cli/commands/config/enable_spec.rb b/spec/cli/commands/config/enable_spec.rb
new file mode 100644
index 0000000..63baf58
--- /dev/null
+++ b/spec/cli/commands/config/enable_spec.rb
@@ -0,0 +1,34 @@
+require 'spec_helper'
+require 'ronin/recon/cli/commands/config/enable'
+
+require_relative '../man_page_example'
+
+require 'tempfile'
+
+describe Ronin::Recon::CLI::Commands::Config::Enable do
+ include_examples "man_page"
+
+ describe "#run" do
+ let(:tempfile) { Tempfile.new(['ronin-recon-config-','.yml']) }
+ let(:config_file) { tempfile.path }
+
+ let(:worker) { 'test/worker1' }
+
+ before do
+ config = Ronin::Recon::Config.new
+ config.workers.add(worker)
+ config.save(config_file)
+ end
+
+ before do
+ subject.options[:config_file] = config_file
+ end
+
+ it "must enable the worker in the config file" do
+ subject.run(worker)
+
+ config = Ronin::Recon::Config.load(config_file)
+ expect(config.workers).to include(worker)
+ end
+ end
+end
diff --git a/spec/cli/commands/config/get_spec.rb b/spec/cli/commands/config/get_spec.rb
new file mode 100644
index 0000000..012256d
--- /dev/null
+++ b/spec/cli/commands/config/get_spec.rb
@@ -0,0 +1,118 @@
+require 'spec_helper'
+require 'ronin/recon/cli/commands/config/get'
+
+require_relative '../man_page_example'
+
+require 'tempfile'
+
+describe Ronin::Recon::CLI::Commands::Config::Get do
+ include_examples "man_page"
+
+ describe "#run" do
+ let(:tempfile) { Tempfile.new(['ronin-recon-config-','.yml']) }
+ let(:config_file) { tempfile.path }
+
+ let(:worker) { 'test/worker1' }
+
+ context "when the --concurrency option is given" do
+ let(:concurrency) { 10 }
+
+ before do
+ config = Ronin::Recon::Config.new(concurrency: {worker => concurrency})
+ config.save(config_file)
+ end
+
+ before do
+ subject.option_parser.parse(
+ [
+ '--config-file', config_file,
+ '--concurrency', worker
+ ]
+ )
+ end
+
+ it "must print the concurrency value for the worker to stdout" do
+ expect {
+ subject.run
+ }.to output("#{concurrency}#{$/}").to_stdout
+ end
+
+ context "but the concurrency is not set" do
+ before do
+ subject.option_parser.parse(
+ [
+ '--config-file', config_file,
+ '--concurrency', "test/does_not_exist"
+ ]
+ )
+ end
+
+ it "must not print anything" do
+ expect {
+ subject.run
+ }.to_not output.to_stdout
+ end
+ end
+ end
+
+ context "when the --param option is given" do
+ let(:param_name) { :foo }
+ let(:param_value) { 'bar' }
+
+ before do
+ config = Ronin::Recon::Config.new(
+ params: {
+ worker => {
+ param_name => param_value
+ }
+ }
+ )
+ config.save(config_file)
+ end
+
+ before do
+ subject.option_parser.parse(
+ [
+ '--config-file', config_file,
+ '--param', "#{worker}.#{param_name}"
+ ]
+ )
+ end
+
+ it "must print the param valeu for the worker to stdout" do
+ expect {
+ subject.run
+ }.to output("#{param_value}#{$/}").to_stdout
+ end
+
+ context "but the param is not set" do
+ before do
+ subject.option_parser.parse(
+ [
+ '--config-file', config_file,
+ '--param', "#{worker}.does_not_exist"
+ ]
+ )
+ end
+
+ it "must not print anything" do
+ expect {
+ subject.run
+ }.to_not output.to_stdout
+ end
+ end
+ end
+
+ context "when neither the --concurrency or --param options are given" do
+ it "must print an error and exit with 1" do
+ expect(subject).to receive(:print_error).with("--concurrency or --param options must be given")
+
+ expect {
+ subject.run
+ }.to raise_error(SystemExit) do |error|
+ expect(error.status).to eq(-1)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/cli/commands/config/list_spec.rb b/spec/cli/commands/config/list_spec.rb
new file mode 100644
index 0000000..c56646e
--- /dev/null
+++ b/spec/cli/commands/config/list_spec.rb
@@ -0,0 +1,166 @@
+require 'spec_helper'
+require 'ronin/recon/cli/commands/config/list'
+
+require_relative '../man_page_example'
+
+require 'tempfile'
+
+describe Ronin::Recon::CLI::Commands::Config::List do
+ include_examples "man_page"
+
+ describe "#run" do
+ let(:tempfile) { Tempfile.new(['ronin-recon-config-','.yml']) }
+ let(:config_file) { tempfile.path }
+
+ before do
+ subject.options[:config_file] = config_file
+ end
+
+ context "when the config file is empty" do
+ before do
+ config = Ronin::Recon::Config.new
+ config.save(config_file)
+ end
+
+ it "must print the default workers" do
+ expect {
+ subject.run
+ }.to output(
+ [
+ "Workers:",
+ *Ronin::Recon::Config::Workers::DEFAULT.map { |worker|
+ " * #{worker}"
+ },
+ ''
+ ].join($/)
+ ).to_stdout
+ end
+ end
+
+ context "when the config file has workers enabled or disalbed" do
+ let(:enabled_worker1) { 'test/worker1' }
+ let(:enabled_worker2) { 'test/worker2' }
+ let(:enabled_worker3) { 'test/worker3' }
+ let(:disabled_worker1) { 'dns/reverse_lookup' }
+ let(:disabled_worker2) { 'dns/subdomain_enum' }
+
+ before do
+ config = Ronin::Recon::Config.new
+ config.workers.add(enabled_worker1)
+ config.workers.add(enabled_worker2)
+ config.workers.add(enabled_worker3)
+ config.workers.delete(disabled_worker1)
+ config.workers.delete(disabled_worker2)
+ config.save(config_file)
+ end
+
+ it "must print the enabled workers in addition to the default workers that were not disabled" do
+ config = Ronin::Recon::Config.load(config_file)
+
+ expect {
+ subject.run
+ }.to output(
+ [
+ "Workers:",
+ *config.workers.map { |worker|
+ " * #{worker}"
+ },
+ ''
+ ].join($/)
+ ).to_stdout
+ end
+ end
+
+ context "when the config file has concurrency values set" do
+ let(:worker1) { 'test/worker1' }
+ let(:worker2) { 'test/worker2' }
+ let(:worker3) { 'test/worker3' }
+
+ let(:concurrency1) { 2 }
+ let(:concurrency2) { 10 }
+ let(:concurrency3) { 42 }
+
+ before do
+ config = Ronin::Recon::Config.new(
+ concurrency: {
+ worker1 => concurrency1,
+ worker2 => concurrency2,
+ worker3 => concurrency3
+ }
+ )
+ config.save(config_file)
+ end
+
+ it "must print the concurrency values for the workers" do
+ config = Ronin::Recon::Config.load(config_file)
+
+ expect {
+ subject.run
+ }.to output(
+ [
+ "Workers:",
+ *config.workers.map { |worker|
+ " * #{worker}"
+ },
+ '',
+ 'Concurrency:',
+ " * #{worker1}=#{concurrency1}",
+ " * #{worker2}=#{concurrency2}",
+ " * #{worker3}=#{concurrency3}",
+ ''
+ ].join($/)
+ ).to_stdout
+ end
+ end
+
+ context "when the config file has param values set" do
+ let(:worker1) { 'test/worker1' }
+ let(:worker2) { 'test/worker2' }
+
+ let(:param_name1) { :foo }
+ let(:param_value1) { true }
+ let(:param_name2) { :bar }
+ let(:param_value2) { 42 }
+ let(:param_name3) { :baz }
+ let(:param_value3) { 'xyz' }
+
+ before do
+ config = Ronin::Recon::Config.new(
+ params: {
+ worker1 => {
+ param_name1 => param_value1,
+ param_name2 => param_value2
+ },
+ worker2 => {
+ param_name3 => param_value3
+ }
+ }
+ )
+ config.save(config_file)
+ end
+
+ it "must print the concurrency values for the workers" do
+ config = Ronin::Recon::Config.load(config_file)
+
+ expect {
+ subject.run
+ }.to output(
+ [
+ "Workers:",
+ *config.workers.map { |worker|
+ " * #{worker}"
+ },
+ '',
+ 'Params:',
+ " * #{worker1}",
+ " * #{param_name1}=#{param_value1}",
+ " * #{param_name2}=#{param_value2}",
+ " * #{worker2}",
+ " * #{param_name3}=#{param_value3}",
+ ''
+ ].join($/)
+ ).to_stdout
+ end
+ end
+ end
+end
diff --git a/spec/cli/commands/config/set_spec.rb b/spec/cli/commands/config/set_spec.rb
new file mode 100644
index 0000000..5f5217c
--- /dev/null
+++ b/spec/cli/commands/config/set_spec.rb
@@ -0,0 +1,80 @@
+require 'spec_helper'
+require 'ronin/recon/cli/commands/config/set'
+
+require_relative '../man_page_example'
+
+require 'tempfile'
+
+describe Ronin::Recon::CLI::Commands::Config::Set do
+ include_examples "man_page"
+
+ describe "#run" do
+ let(:tempfile) { Tempfile.new(['ronin-recon-config-','.yml']) }
+ let(:config_file) { tempfile.path }
+
+ let(:worker) { 'test/worker1' }
+
+ context "when the --concurrency option is given" do
+ let(:concurrency) { 10 }
+
+ before do
+ config = Ronin::Recon::Config.new
+ config.save(config_file)
+ end
+
+ before do
+ subject.option_parser.parse(
+ [
+ '--config-file', config_file,
+ '--concurrency', "#{worker}=#{concurrency}"
+ ]
+ )
+ end
+
+ it "must print the concurrency value for the worker to stdout" do
+ subject.run
+
+ config = Ronin::Recon::Config.load(config_file)
+ expect(config.concurrency[worker]).to eq(concurrency)
+ end
+ end
+
+ context "when the --param option is given" do
+ let(:param_name) { :foo }
+ let(:param_value) { 'bar' }
+
+ before do
+ config = Ronin::Recon::Config.new
+ config.save(config_file)
+ end
+
+ before do
+ subject.option_parser.parse(
+ [
+ '--config-file', config_file,
+ '--param', "#{worker}.#{param_name}=#{param_value}"
+ ]
+ )
+ end
+
+ it "must print the param valeu for the worker to stdout" do
+ subject.run
+
+ config = Ronin::Recon::Config.load(config_file)
+ expect(config.params[worker][param_name]).to eq(param_value)
+ end
+ end
+
+ context "when neither the --concurrency or --param options are given" do
+ it "must print an error and exit with 1" do
+ expect(subject).to receive(:print_error).with("--concurrency or --param options must be given")
+
+ expect {
+ subject.run
+ }.to raise_error(SystemExit) do |error|
+ expect(error.status).to eq(-1)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/cli/commands/config/unset_spec.rb b/spec/cli/commands/config/unset_spec.rb
new file mode 100644
index 0000000..7b6bd38
--- /dev/null
+++ b/spec/cli/commands/config/unset_spec.rb
@@ -0,0 +1,86 @@
+require 'spec_helper'
+require 'ronin/recon/cli/commands/config/unset'
+
+require_relative '../man_page_example'
+
+require 'tempfile'
+
+describe Ronin::Recon::CLI::Commands::Config::Unset do
+ include_examples "man_page"
+
+ describe "#run" do
+ let(:tempfile) { Tempfile.new(['ronin-recon-config-','.yml']) }
+ let(:config_file) { tempfile.path }
+
+ let(:worker) { 'test/worker1' }
+
+ context "when the --concurrency option is given" do
+ let(:concurrency) { 10 }
+
+ before do
+ config = Ronin::Recon::Config.new(concurrency: {worker => concurrency})
+ config.save(config_file)
+ end
+
+ before do
+ subject.option_parser.parse(
+ [
+ '--config-file', config_file,
+ '--concurrency', worker
+ ]
+ )
+ end
+
+ it "must print the concurrency value for the worker to stdout" do
+ subject.run
+
+ config = Ronin::Recon::Config.load(config_file)
+ expect(config.concurrency).to_not have_key(worker)
+ end
+ end
+
+ context "when the --param option is given" do
+ let(:param_name) { :foo }
+ let(:param_value) { 'bar' }
+
+ before do
+ config = Ronin::Recon::Config.new(
+ params: {
+ worker => {
+ param_name => param_value
+ }
+ }
+ )
+ config.save(config_file)
+ end
+
+ before do
+ subject.option_parser.parse(
+ [
+ '--config-file', config_file,
+ '--param', "#{worker}.#{param_name}"
+ ]
+ )
+ end
+
+ it "must print the param valeu for the worker to stdout" do
+ subject.run
+
+ config = Ronin::Recon::Config.load(config_file)
+ expect(config.params[worker]).to_not have_key(param_name)
+ end
+ end
+
+ context "when neither the --concurrency or --param options are given" do
+ it "must print an error and exit with 1" do
+ expect(subject).to receive(:print_error).with("--concurrency or --param options must be given")
+
+ expect {
+ subject.run
+ }.to raise_error(SystemExit) do |error|
+ expect(error.status).to eq(-1)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/cli/commands/config_spec.rb b/spec/cli/commands/config_spec.rb
new file mode 100644
index 0000000..16b6813
--- /dev/null
+++ b/spec/cli/commands/config_spec.rb
@@ -0,0 +1,8 @@
+require 'spec_helper'
+require 'ronin/recon/cli/commands/config'
+
+require_relative 'man_page_example'
+
+describe Ronin::Recon::CLI::Commands::Config do
+ include_examples "man_page"
+end