diff --git a/.gitignore b/.gitignore
index f6ae618bd..fac755a6b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
/coverage
+/data/completions/ronin
/doc
/pkg
/man/*.[1-9]
diff --git a/Gemfile b/Gemfile
index 9e9580934..0410074c6 100644
--- a/Gemfile
+++ b/Gemfile
@@ -14,8 +14,8 @@ if RUBY_VERSION >= '3.1.0'
gem 'net-imap', '~> 0.1', group: :net, platform: :mri
end
-# gem 'command_kit', '~> 0.4', github: 'postmodern/command_kit.rb',
-# branch: '0.4.0'
+# gem 'command_kit', '~> 0.5', github: 'postmodern/command_kit.rb',
+# branch: 'main'
group :database do
gem 'sqlite3', '~> 1.0', platform: :mri
@@ -25,10 +25,10 @@ end
# Library dependencies
gem 'ronin-support', '~> 1.1', github: "ronin-rb/ronin-support",
branch: '1.1.0'
-gem 'ronin-core', '~> 0.2', github: "ronin-rb/ronin-core",
+gem 'ronin-core', '~> 0.2', github: 'ronin-rb/ronin-core',
+ branch: '0.2.0'
+gem 'ronin-repos', '~> 0.1', github: 'ronin-rb/ronin-repos',
branch: '0.2.0'
-# gem 'ronin-repos', '~> 0.1', github: "ronin-rb/ronin-repos",
-# branch: 'main'
gem 'ronin-db-activerecord', '~> 0.2', github: "ronin-rb/ronin-db-activerecord",
branch: '0.2.0'
gem 'ronin-db', '~> 0.2', github: "ronin-rb/ronin-db",
@@ -39,18 +39,18 @@ gem 'ronin-listener-http', '~> 0.1', github: "ronin-rb/ronin-listener-http"
branch: 'main'
gem 'ronin-listener', '~> 0.1', github: "ronin-rb/ronin-listener",
branch: 'main'
-# gem 'ronin-fuzzer', '~> 0.1', github: 'ronin-rb/ronin-fuzzer',
-# branch: 'main'
+gem 'ronin-fuzzer', '~> 0.2', github: 'ronin-rb/ronin-fuzzer',
+ branch: '0.2.0'
# gem 'ronin-post_ex', '~> 0.1', github: 'ronin-rb/ronin-post_ex',
# branch: 'main'
# gem 'ronin-code-asm', '~> 1.0', github: 'ronin-rb/ronin-code-asm',
# branch: 'main'
# gem 'ronin-code-sql', '~> 2.0', github: 'ronin-rb/ronin-code-sql',
# branch: 'main'
-# gem 'ronin-payloads', '~> 0.1', github: 'ronin-rb/ronin-payloads',
-# branch: 'main'
-# gem 'ronin-exploits', '~> 1.0', github: 'ronin-rb/ronin-exploits',
-# branch: 'main'
+gem 'ronin-payloads', '~> 0.2', github: 'ronin-rb/ronin-payloads',
+ branch: '0.2.0'
+gem 'ronin-exploits', '~> 1.1', github: 'ronin-rb/ronin-exploits',
+ branch: '1.1.0'
gem 'ronin-vulns', '~> 0.2', github: 'ronin-rb/ronin-vulns',
branch: '0.2.0'
# gem 'ronin-web-server', '~> 0.1', github: 'ronin-rb/ronin-web-server',
@@ -98,4 +98,6 @@ group :development do
gem 'rubocop', require: false, platform: :mri
gem 'rubocop-ronin', require: false, platform: :mri
gem 'pry', require: false
+
+ gem 'command_kit-completion', '~> 0.1', require: false
end
diff --git a/README.md b/README.md
index ff949d4bd..13d5bb52d 100644
--- a/README.md
+++ b/README.md
@@ -79,6 +79,7 @@ Commands:
cert-dump
cert-gen
cert-grab
+ completion
decode, dec
decrypt
dns
diff --git a/Rakefile b/Rakefile
index b95871af2..0dea54f0a 100644
--- a/Rakefile
+++ b/Rakefile
@@ -41,3 +41,10 @@ task :docs => [:yard]
require 'kramdown/man/task'
Kramdown::Man::Task.new
+
+require 'command_kit/completion/task'
+CommandKit::Completion::Task.new(
+ class_file: 'ronin/cli',
+ class_name: 'Ronin::CLI',
+ output_file: 'data/completions/ronin'
+)
diff --git a/gemspec.yml b/gemspec.yml
index a1789dfbb..9c2babfdc 100644
--- a/gemspec.yml
+++ b/gemspec.yml
@@ -37,6 +37,7 @@ metadata:
rubygems_mfa_required: 'true'
generated_files:
+ - data/completions/ronin
- man/ronin.1
- man/ronin-asn.1
- man/ronin-banner-grab.1
@@ -45,6 +46,7 @@ generated_files:
- man/ronin-cert-dump.1
- man/ronin-cert-gen.1
- man/ronin-cert-grab.1
+ - man/ronin-completion.1
- man/ronin-decode.1
- man/ronin-decrypt.1
- man/ronin-dns.1
@@ -103,13 +105,13 @@ dependencies:
ronin-support: ~> 1.1
ronin-dns-proxy: ~> 0.1
ronin-core: ~> 0.2
- ronin-repos: ~> 0.1
- ronin-db: ~> 0.1
+ ronin-repos: ~> 0.2
+ ronin-db: ~> 0.2
ronin-listener: ~> 0.1
ronin-nmap: ~> 0.1
ronin-masscan: ~> 0.1
ronin-recon: ~> 0.1
- ronin-fuzzer: ~> 0.1
+ ronin-fuzzer: ~> 0.2
ronin-web: ~> 2.0
ronin-code-asm: ~> 1.0
ronin-code-sql: ~> 2.0
diff --git a/lib/ronin/cli/commands/banner_grab.rb b/lib/ronin/cli/commands/banner_grab.rb
index 0509950cc..e5ae84eae 100644
--- a/lib/ronin/cli/commands/banner_grab.rb
+++ b/lib/ronin/cli/commands/banner_grab.rb
@@ -45,6 +45,8 @@ class BannerGrab < ValueProcessorCommand
include HostAndPort
+ command_name 'banner-grab'
+
usage '[options] {HOST:PORT} ...'
option :with_host_port, desc: 'Print the service with the banner'
diff --git a/lib/ronin/cli/commands/cert_dump.rb b/lib/ronin/cli/commands/cert_dump.rb
index 7dd2fa5b6..b085de419 100644
--- a/lib/ronin/cli/commands/cert_dump.rb
+++ b/lib/ronin/cli/commands/cert_dump.rb
@@ -64,6 +64,8 @@ class CertDump < ValueProcessorCommand
include CommandKit::Printing::Lists
include HostAndPort
+ command_name 'cert-dump'
+
usage '[options] {HOST:PORT | URL | FILE} ...'
option :common_name, short: '-C',
diff --git a/lib/ronin/cli/commands/cert_gen.rb b/lib/ronin/cli/commands/cert_gen.rb
index 9d8b33c64..152c99c34 100644
--- a/lib/ronin/cli/commands/cert_gen.rb
+++ b/lib/ronin/cli/commands/cert_gen.rb
@@ -72,6 +72,8 @@ class CertGen < Command
include Core::CLI::Logging
+ command_name 'cert-gen'
+
option :version, value: {
type: Integer,
usage: 'NUM',
diff --git a/lib/ronin/cli/commands/cert_grab.rb b/lib/ronin/cli/commands/cert_grab.rb
index 8fc2af6a1..04c232077 100644
--- a/lib/ronin/cli/commands/cert_grab.rb
+++ b/lib/ronin/cli/commands/cert_grab.rb
@@ -52,6 +52,8 @@ class CertGrab < ValueProcessorCommand
include HostAndPort
+ command_name 'cert-grab'
+
usage '[options] {HOST:PORT | URL} ...'
argument :target, required: true,
diff --git a/lib/ronin/cli/commands/completion.rb b/lib/ronin/cli/commands/completion.rb
new file mode 100644
index 000000000..7ba22f284
--- /dev/null
+++ b/lib/ronin/cli/commands/completion.rb
@@ -0,0 +1,113 @@
+# frozen_string_literal: true
+#
+# Copyright (c) 2006-2023 Hal Brodigan (postmodern.mod3 at gmail.com)
+#
+# Ronin is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ronin 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ronin. If not, see .
+#
+
+require 'ronin/core/cli/completion_command'
+require 'ronin/repos/cli/commands/completion'
+require 'ronin/db/cli/commands/completion'
+require 'ronin/fuzzer/cli/commands/completion'
+require 'ronin/web/cli/commands/completion'
+require 'ronin/vulns/cli/commands/completion'
+require 'ronin/payloads/cli/commands/completion'
+require 'ronin/exploits/cli/commands/completion'
+require 'ronin/listener/cli/commands/completion'
+require 'ronin/nmap/cli/commands/completion'
+require 'ronin/masscan/cli/commands/completion'
+require 'ronin/recon/cli/commands/completion'
+require 'ronin/root'
+
+module Ronin
+ class CLI
+ module Commands
+ #
+ # Manages the shell completion rule for `ronin` and all other `ronin-*`
+ # commands.
+ #
+ # ## Usage
+ #
+ # ronin completion [options]
+ #
+ # ## Options
+ #
+ # --print Prints the shell completion file
+ # --install Installs the shell completion file
+ # --uninstall Uninstalls the shell completion file
+ # -h, --help Print help information
+ #
+ # ## Examples
+ #
+ # ronin completion --print
+ # ronin completion --install
+ # ronin completion --uninstall
+ #
+ # @since 2.1.0
+ #
+ class Completion < Core::CLI::CompletionCommand
+
+ man_dir File.join(ROOT,'man')
+ man_page 'ronin-completion.1'
+
+ description 'Manages the shell completion rules for ronin and all other ronin-* commands'
+
+ # All shell completion files for `ronin` and the other `ronin-*`
+ # commands.
+ COMPLETION_FILES = [
+ File.join(ROOT,'data','completions','ronin'),
+
+ Repos::CLI::Commands::Completion.completion_file,
+ DB::CLI::Commands::Completion.completion_file,
+ Fuzzer::CLI::Commands::Completion.completion_file,
+ Web::CLI::Commands::Completion.completion_file,
+ Vulns::CLI::Commands::Completion.completion_file,
+ Payloads::CLI::Commands::Completion.completion_file,
+ Exploits::CLI::Commands::Completion.completion_file,
+ Listener::CLI::Commands::Completion.completion_file,
+ Nmap::CLI::Commands::Completion.completion_file,
+ Masscan::CLI::Commands::Completion.completion_file,
+ Recon::CLI::Commands::Completion.completion_file
+ ]
+
+ #
+ # Prints all completion files.
+ #
+ def print_completion_file
+ COMPLETION_FILES.each do |completion_file|
+ super(completion_file)
+ end
+ end
+
+ #
+ # Installs all completion files.
+ #
+ def install_completion_file
+ COMPLETION_FILES.each do |completion_file|
+ super(completion_file)
+ end
+ end
+
+ #
+ # Uninstall all completion files.
+ #
+ def uninstall_completion_file
+ COMPLETION_FILES.each do |completion_file|
+ super(completion_file)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/ronin/cli/commands/new/dns_listener.rb b/lib/ronin/cli/commands/new/dns_listener.rb
index 69df3fad6..67761313d 100644
--- a/lib/ronin/cli/commands/new/dns_listener.rb
+++ b/lib/ronin/cli/commands/new/dns_listener.rb
@@ -26,7 +26,11 @@ class New < Command
# An alias for `ronin-listener new dns`.
#
# @since 2.1.0
- DnsListener = Ronin::Listener::CLI::Commands::New::Dns
+ class DnsListener < Ronin::Listener::CLI::Commands::New::Dns
+
+ command_name 'dns-listener'
+
+ end
end
end
end
diff --git a/lib/ronin/cli/commands/new/dns_proxy.rb b/lib/ronin/cli/commands/new/dns_proxy.rb
index f70421e62..9c6c7e1dd 100644
--- a/lib/ronin/cli/commands/new/dns_proxy.rb
+++ b/lib/ronin/cli/commands/new/dns_proxy.rb
@@ -51,6 +51,8 @@ class DnsProxy < Command
template_dir File.join(ROOT,'data','templates')
+ command_name 'dns-proxy'
+
usage 'PATH'
option :host, short: '-H',
diff --git a/lib/ronin/cli/commands/new/exploit.rb b/lib/ronin/cli/commands/new/exploit.rb
index f96b98dc7..275c6d9a3 100644
--- a/lib/ronin/cli/commands/new/exploit.rb
+++ b/lib/ronin/cli/commands/new/exploit.rb
@@ -26,7 +26,8 @@ class New < Command
# An alias for `ronin-exploits new`.
#
# @since 2.1.0
- Exploit = Ronin::Exploits::CLI::Commands::New
+ class Exploit < Ronin::Exploits::CLI::Commands::New
+ end
end
end
end
diff --git a/lib/ronin/cli/commands/new/http_listener.rb b/lib/ronin/cli/commands/new/http_listener.rb
index 7e3504e0f..5a8a520c2 100644
--- a/lib/ronin/cli/commands/new/http_listener.rb
+++ b/lib/ronin/cli/commands/new/http_listener.rb
@@ -26,7 +26,11 @@ class New < Command
# An alias for `ronin-listener new http`.
#
# @since 2.1.0
- HttpListener = Ronin::Listener::CLI::Commands::New::Http
+ class HttpListener < Ronin::Listener::CLI::Commands::New::Http
+
+ command_name 'http-listener'
+
+ end
end
end
end
diff --git a/lib/ronin/cli/commands/new/payload.rb b/lib/ronin/cli/commands/new/payload.rb
index 068cf2aad..77fee10fe 100644
--- a/lib/ronin/cli/commands/new/payload.rb
+++ b/lib/ronin/cli/commands/new/payload.rb
@@ -26,7 +26,8 @@ class New < Command
# An alias for `ronin-payloads new`.
#
# @since 2.1.0
- Payload = Ronin::Payloads::CLI::Commands::New
+ class Payload < Ronin::Payloads::CLI::Commands::New
+ end
end
end
end
diff --git a/lib/ronin/cli/commands/new/web_app.rb b/lib/ronin/cli/commands/new/web_app.rb
index e0768f35c..fd68bbe9e 100644
--- a/lib/ronin/cli/commands/new/web_app.rb
+++ b/lib/ronin/cli/commands/new/web_app.rb
@@ -26,7 +26,11 @@ class New < Command
# An alias for `ronin-web new app`.
#
# @since 2.1.0
- WebApp = Ronin::Web::CLI::Commands::New::App
+ class WebApp < Ronin::Web::CLI::Commands::New::App
+
+ command_name 'web-app'
+
+ end
end
end
end
diff --git a/lib/ronin/cli/commands/new/web_server.rb b/lib/ronin/cli/commands/new/web_server.rb
index d0d900ec2..8c172562a 100644
--- a/lib/ronin/cli/commands/new/web_server.rb
+++ b/lib/ronin/cli/commands/new/web_server.rb
@@ -26,7 +26,11 @@ class New < Command
# An alias for `ronin-web new server`.
#
# @since 2.1.0
- WebServer = Ronin::Web::CLI::Commands::New::Server
+ class WebServer < Ronin::Web::CLI::Commands::New::Server
+
+ command_name 'web-server'
+
+ end
end
end
end
diff --git a/lib/ronin/cli/commands/new/web_spider.rb b/lib/ronin/cli/commands/new/web_spider.rb
index bc90e67bb..cb8c44ca1 100644
--- a/lib/ronin/cli/commands/new/web_spider.rb
+++ b/lib/ronin/cli/commands/new/web_spider.rb
@@ -26,7 +26,11 @@ class New < Command
# An alias for `ronin-web new spider`.
#
# @since 2.1.0
- WebSpider = Ronin::Web::CLI::Commands::New::Spider
+ class WebSpider < Ronin::Web::CLI::Commands::New::Spider
+
+ command_name 'web-spider'
+
+ end
end
end
end
diff --git a/lib/ronin/cli/commands/public_suffix_list.rb b/lib/ronin/cli/commands/public_suffix_list.rb
index d985c5bf5..d47b2a8b3 100644
--- a/lib/ronin/cli/commands/public_suffix_list.rb
+++ b/lib/ronin/cli/commands/public_suffix_list.rb
@@ -46,6 +46,8 @@ class PublicSuffixList < Command
include CommandKit::Options::Verbose
include Core::CLI::Logging
+ command_name 'public-suffix-list'
+
option :update, short: '-u',
desc: 'Updates the public suffix list file'
diff --git a/lib/ronin/cli/commands/tld_list.rb b/lib/ronin/cli/commands/tld_list.rb
index 163504200..1bf7c3a7e 100644
--- a/lib/ronin/cli/commands/tld_list.rb
+++ b/lib/ronin/cli/commands/tld_list.rb
@@ -46,6 +46,8 @@ class TldList < Command
include CommandKit::Options::Verbose
include Core::CLI::Logging
+ command_name 'tld-list'
+
option :update, short: '-u',
desc: 'Updates the TLD list file'
diff --git a/man/ronin-completion.1.md b/man/ronin-completion.1.md
new file mode 100644
index 000000000..7227458d3
--- /dev/null
+++ b/man/ronin-completion.1.md
@@ -0,0 +1,80 @@
+# ronin-completion 1 "2024-01-01" Ronin "User Manuals"
+
+## NAME
+
+ronin-completion - Manages shell completion rules for `ronin-repos`
+
+## SYNOPSIS
+
+`ronin-repos completion` [*options*]
+
+## DESCRIPTION
+
+The `ronin completion` command can print, install, or uninstall shell
+completion rules for the `ronin` command and all other `ronin-*` commands.
+
+Supports installing completion rules for Bash or Zsh shells.
+Completion rules for the Fish shell is currently not supported.
+
+### ZSH SUPPORT
+
+Zsh users will have to add the following lines to their `~/.zshrc` file in
+order to enable Zsh's Bash completion compatibility layer:
+
+ autoload -Uz +X compinit && compinit
+ autoload -Uz +X bashcompinit && bashcompinit
+
+## OPTIONS
+
+`--print`
+: Prints the shell completion file.
+
+`--install`
+: Installs the shell completion file.
+
+`--uninstall`
+: Uninstalls the shell completion file.
+
+`-h`, `--help`
+: Prints help information.
+
+## ENVIRONMENT
+
+*PREFIX*
+: Specifies the root prefix for the file system.
+
+*HOME*
+: Specifies the home directory of the user. Ronin will search for the
+ `~/.cache/ronin-repos` cache directory within the home directory.
+
+*XDG_DATA_HOME*
+: Specifies the data directory to use. Defaults to `$HOME/.local/share`.
+
+## FILES
+
+`~/.local/share/bash-completion/completions/`
+: The user-local installation directory for Bash completion files.
+
+`/usr/local/share/bash-completion/completions/`
+: The system-wide installation directory for Bash completions files.
+
+`/usr/local/share/zsh/site-functions/`
+: The installation directory for Zsh completion files.
+
+## EXAMPLES
+
+`ronin completion --print`
+: Prints all shell completion rules instead of installing them.
+
+`ronin completion --install`
+: Installs all shell completion rules for `ronin` and the other `ronin-*`
+ commands.
+
+`ronin-repos completion --uninstall`
+: Uninstalls all shell completion rules for `ronin` and the other `ronin-*`
+ commands.
+
+## AUTHOR
+
+Postmodern
+
diff --git a/spec/cli/commands/completion_spec.rb b/spec/cli/commands/completion_spec.rb
new file mode 100644
index 000000000..2e99839bc
--- /dev/null
+++ b/spec/cli/commands/completion_spec.rb
@@ -0,0 +1,16 @@
+require 'spec_helper'
+require 'ronin/cli/commands/completion'
+require_relative 'man_page_example'
+
+describe Ronin::CLI::Commands::Completion do
+ it "must inherit from Ronin::Core::CLI::CompletionCommand" do
+ expect(described_class).to be < Ronin::Core::CLI::CompletionCommand
+ end
+
+ it "must set man_dir" do
+ expect(described_class.man_dir).to_not be(nil)
+ expect(File.directory?(described_class.man_dir)).to be(true)
+ end
+
+ include_examples "man_page"
+end