diff --git a/lib/ronin/recon/output_formats.rb b/lib/ronin/recon/output_formats.rb index 823910e..c8ef06f 100644 --- a/lib/ronin/recon/output_formats.rb +++ b/lib/ronin/recon/output_formats.rb @@ -23,6 +23,8 @@ require_relative 'output_formats/svg' require_relative 'output_formats/png' require_relative 'output_formats/pdf' +require_relative 'output_formats/archive' +require_relative 'output_formats/git_archive' require 'ronin/core/output_formats' @@ -35,15 +37,17 @@ module Recon module OutputFormats include Core::OutputFormats - register :txt, '.txt', TXT - register :csv, '.csv', CSV - register :json, '.json', JSON - register :ndjson, '.ndjson', NDJSON - register :dir, '', Dir - register :dot, '.dot', Dot - register :svg, '.svg', SVG - register :png, '.png', PNG - register :pdf, '.pdf', PDF + register :txt, '.txt', TXT + register :csv, '.csv', CSV + register :json, '.json', JSON + register :ndjson, '.ndjson', NDJSON + register :dir, '', Dir + register :dot, '.dot', Dot + register :svg, '.svg', SVG + register :png, '.png', PNG + register :pdf, '.pdf', PDF + register :web_archive, '', Archive + register :web_git_archive, '', GitArchive end end end diff --git a/lib/ronin/recon/output_formats/archive.rb b/lib/ronin/recon/output_formats/archive.rb new file mode 100644 index 0000000..f4cbe88 --- /dev/null +++ b/lib/ronin/recon/output_formats/archive.rb @@ -0,0 +1,56 @@ +# 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 'ronin/web/spider/archive' + +module Ronin + module Recon + module OutputFormats + # + # Represents a web archive directory. + # + class Archive + + # + # Initializes new archive. + # + # @param [String] root + # The path to the root directory. + # + def initialize(root) + @archive = Ronin::Web::Spider::Archive.new(root) + end + + # + # Writes a new URL to it's specific file. + # + # @param [Value] value + # The value to write. + # + def <<(value) + if Values::URL === value + @archive.write(value.uri, value.body) + end + end + + end + end + end +end diff --git a/lib/ronin/recon/output_formats/git_archive.rb b/lib/ronin/recon/output_formats/git_archive.rb new file mode 100644 index 0000000..02d7857 --- /dev/null +++ b/lib/ronin/recon/output_formats/git_archive.rb @@ -0,0 +1,57 @@ +# 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 'ronin/web/spider/git_archive' + +module Ronin + module Recon + module OutputFormats + # + # Represents a web archive directory that is backed by Git. + # + class GitArchive + + # + # Initializes new Git repository. + # + # @param [String] root + # The path to the root directory. + # + def initialize(root) + @git_archive = Ronin::Web::Spider::GitArchive.new(root) + @git_archive.init unless @git_archive.git? + end + + # + # Writes a new URL to it's specific file in Git archive. + # + # @param [Value] value + # The value to write. + # + def <<(value) + if Values::URL === value + @git_archive.write(value.uri, value.body) + end + end + + end + end + end +end diff --git a/spec/output_formats/archive_spec.rb b/spec/output_formats/archive_spec.rb new file mode 100644 index 0000000..8694786 --- /dev/null +++ b/spec/output_formats/archive_spec.rb @@ -0,0 +1,34 @@ +require 'spec_helper' +require 'ronin/recon/output_formats/archive' +require 'ronin/recon/values/url' +require 'ronin/recon/values/domain' +require 'tmpdir' + +describe Ronin::Recon::OutputFormats::Archive do + subject { described_class.new(path) } + + let(:path) { Dir.mktmpdir('ronin-recon-output-archive') } + + describe "#<<" do + context "for Values::URL" do + let(:value) { Ronin::Recon::Values::URL.new('https://www.example.com/foo.html') } + let(:expected_path) { File.join(path,value.path) } + + it "must create a new file with webpage" do + subject << value + + expect(File.exist?(expected_path)).to be(true) + end + end + + context "for other values" do + let(:value) { Ronin::Recon::Values::Domain.new('example.com') } + + it "must not create any files" do + subject << value + + expect(Dir.glob("#{path}/*")).to be_empty + end + end + end +end diff --git a/spec/output_formats/git_archive_spec.rb b/spec/output_formats/git_archive_spec.rb new file mode 100644 index 0000000..1ec3967 --- /dev/null +++ b/spec/output_formats/git_archive_spec.rb @@ -0,0 +1,34 @@ +require 'spec_helper' +require 'ronin/recon/output_formats/git_archive' +require 'ronin/recon/values/url' +require 'ronin/recon/values/domain' +require 'tmpdir' + +describe Ronin::Recon::OutputFormats::GitArchive do + subject { described_class.new(path) } + + let(:path) { Dir.mktmpdir('ronin-recon-output-git-archive') } + + describe "#<<" do + context "for Values::URL" do + let(:value) { Ronin::Recon::Values::URL.new('https://www.example.com/foo.html') } + let(:expected_path) { File.join(path,value.path) } + + it "must create a new file with webpage" do + subject << value + + expect(File.exist?(expected_path)).to be(true) + end + end + + context "for other values" do + let(:value) { Ronin::Recon::Values::Domain.new('example.com') } + + it "must not create any files" do + subject << value + + expect(Dir.glob("#{path}/*")).to be_empty + end + end + end +end