Skip to content

Commit

Permalink
Add web/screenshot recon worker
Browse files Browse the repository at this point in the history
  • Loading branch information
moozzi committed Aug 29, 2024
1 parent 2338010 commit 568df24
Show file tree
Hide file tree
Showing 4 changed files with 160 additions and 0 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,7 @@ end
* [ronin-repos] ~> 0.1
* [ronin-nmap] ~> 0.1
* [ronin-web-spider] ~> 0.2
* [ronin-web-browser] ~> 0.1

## Install

Expand Down Expand Up @@ -392,3 +393,4 @@ along with ronin-recon. If not, see <https://www.gnu.org/licenses/>.
[ronin-masscan]: https://github.com/ronin-rb/ronin-masscan#readme
[ronin-nmap]: https://github.com/ronin-rb/ronin-nmap#readme
[ronin-web-spider]: https://github.com/ronin-rb/ronin-web-spider#readme
[ronin-web-browser]: https://github.com/ronin-rb/ronin-web-browser#readme
1 change: 1 addition & 0 deletions gemspec.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ dependencies:
ronin-repos: ~> 0.1
ronin-nmap: ~> 0.1
ronin-web-spider: ~> 0.2
ronin-web-browser: ~> 0.1

development_dependencies:
bundler: ~> 2.0
107 changes: 107 additions & 0 deletions lib/ronin/recon/builtin/web/screenshot.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# frozen_string_literal: true
#
# ronin-recon - A micro-framework and tool for performing reconnaissance.
#
# Copyright (c) 2023-2024 Hal Brodigan ([email protected])
#
# 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 <https://www.gnu.org/licenses/>.
#

require 'ronin/recon/worker'

require 'ronin/web/browser'

module Ronin
module Recon
module Web
#
# A recon worker that takes a screenshot of a page.
#
# @since 0.2.0
#
class Screenshot < Worker

register 'web/screenshot'

summary 'Visits a website and takes a screenshot of it'
description <<~DESC
Visits a website and takes a screenshot of it.
DESC

accepts URL
outputs nil
concurrency 1

param :output_dir, String, required: true,
desc: 'The directory you want to save the screenshot to.'

param :format, String, required: true,
default: 'png',
desc: 'The screenshot format.'

# The Web::Browser instance
#
# @return [Web::Browser]
#
# @api private
attr_reader :browser

#
# Initializes the `web/screenshot` worker.
#
# @param [Hash{Symbol => Object}] kwargs
# Additional keyword arguments.
#
# @api private
#
def initialize(**kwargs)
super(**kwargs)

@browser = Ronin::Web::Browser.new
end

#
# Visits a website and takes a screenshot of it.
#
# @param [Values::URL] url
# The URL of the website you want to screenshot.
#
def process(url)
browser.go_to(url)

path = path_for(browser.page.url)
FileUtils.mkdir_p(File.dirname(path))

browser.screenshot(path: path)
end

#
# Generates the file path for a given URL.
#
# @param [String] url
# The given url.
#
# @return [String]
# The relative file path that represents the URL.
#
def path_for(url)
page_url = URI(url)
path = File.join(params[:output_dir], page_url.host, page_url.request_uri)
path << 'index' if path.end_with?('/')
path << ".#{params[:format]}"
end
end
end
end
end
50 changes: 50 additions & 0 deletions spec/builtin/web/screenshot_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
require 'spec_helper'
require 'ronin/recon/builtin/web/screenshot'

require 'webmock/rspec'

describe Ronin::Recon::Web::Screenshot do
let(:dir) { Dir.mktmpdir('test-ronin-recon-web-screenshot') }

subject { described_class.new(params: { output_dir: dir }) }

before do
WebMock.disable_net_connect!(allow_localhost: true)
end

describe "#process" do
let(:url) { Ronin::Recon::Values::URL.new('https://www.example.com') }
let(:path) { File.join(dir,"www.example.com","index.png") }

before do
stub_request(:get, 'https://www.example.com')
.to_return(status: 200, body: "")
end

it "must visit a website and take a screenshot of it" do
subject.process(url)

expect(File.exist?(path)).to be(true)
end
end

describe "#path_for" do
context "when url ends with '/'" do
let(:url) { 'https://www.example.com/' }
let(:expected_path) { File.join(dir,'www.example.com','index.png') }

it "must add 'index' to the returned path" do
expect(subject.path_for(url)).to eq(expected_path)
end
end

context "when url does not ends with '/'" do
let(:url) { 'https://www.example.com/foo/bar.php' }
let(:expected_path) { File.join(dir, 'www.example.com','foo','bar.php.png') }

it "must return path" do
expect(subject.path_for(url)).to eq(expected_path)
end
end
end
end

0 comments on commit 568df24

Please sign in to comment.