lib/ronin/web/server/base.rb
# frozen_string_literal: true
#
# ronin-web-server - A custom Ruby web server based on Sinatra.
#
# Copyright (c) 2006-2024 Hal Brodigan (postmodern.mod3 at gmail.com)
#
# ronin-web-server 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-web-server 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-web-server. If not, see <https://www.gnu.org/licenses/>.
#
require_relative 'request'
require_relative 'response'
require_relative 'routing'
require_relative 'helpers'
require_relative 'conditions'
require 'rack'
require 'sinatra/base'
require 'rack/user_agent'
module Ronin
module Web
module Server
#
# The base-class for all Ronin Web Servers. Extends
# [Sinatra::Base](http://rubydoc.info/gems/sinatra/Sinatra/Base)
# with additional {Routing routing methods}, {Helpers helper methods} and
# Sinatra {Conditions conditions}.
#
# ## Routing Methods
#
# * {Routing::ClassMethods#any any}: registers a route that responds to
# `GET`, `POST`, `PUT`, `PATCH`, `DELETE` and `OPTIONS` requests.
# * {Routing::ClassMethods#default default}: registers the default route.
# * {Routing::ClassMethods#basic_auth basic_auth}: enables Basic-Auth
# authentication for the whole app.
# * {Routing::ClassMethods#redirect redirect}: adds a route that simply
# redirects to another URL.
# * {Routing::ClassMethods#file file}: mounts a file at the given path.
# a given file.
# * {Routing::ClassMethods#directory directory}: mounts a directory at
# the given path.
# * {Routing::ClassMethods#public_dir public_dir}: mounts a directory
# at the root.
# * {Routing::ClassMethods#vhost vhost}: mounts a Rack app for the given
# vhost.
# * {Routing::ClassMethods#mount mount}: mounts a Rack app at the given
# path.
#
# ## Helper Methods
#
# * {Helpers#h h}: escapes HTML entities.
# * {Helpers#file file}: sends a file.
# * {Helpers#mime_type_for mime_type_for}: returns the MIME type for the
# file.
# * {Helpers#content_type_for content_type_for}: sets the `Content-Type`
# for the file.
#
# ## Routing Conditions
#
# * {Conditions::ClassMethods#client_ip client_ip}: filters requests
# based on their client IP address.
# * {Conditions::ClassMethods#asn asn}: filters requests by the client
# IP's ASN number.
# * {Conditions::ClassMethods#country_code country_code}: filters requests
# by the client IP's ASN country code.
# * {Conditions::ClassMethods#asn_name asn_name}: filters requests by the
# client IP's ASN company/ISP name.
# * {Conditions::ClassMethods#host host}: filters requests based on the
# `Host` header.
# * {Conditions::ClassMethods#referer referer}: filters requests based on
# the `Referer` header.
# * {Conditions::ClassMethods#user_agent user_agent}: filters requests
# based on the `User-Agent` header.
# * {Conditions::ClassMethods#browser browser}: filters requests based on
# the browser name within the `User-Agent` header.
# * {Conditions::ClassMethods#browser_version browser_version}: filters
# requests based on the browser version within the `User-Agent` header.
# * {Conditions::ClassMethods#device_type device_type}: filters requests
# based on the device type within the `User-Agent` header.
# * {Conditions::ClassMethods#os os}: filters requests based on the OS
# within the `User-Agent` header.
# * {Conditions::ClassMethods#os_version os_version}: filters requests
# based on the OS version within the `User-Agent` header.
#
# ## Examples
#
# require 'ronin/web/server'
#
# class App < Ronin::Web::Server::Base
#
# # mount a file
# file '/sitemap.xml', './files/sitemap.xml'
#
# # mount a directory
# directory '/downloads/', '/tmp/downloads/'
#
# get '/' do
# # renders views/index.erb
# erb :index
# end
#
# get '/test' do
# "raw text here"
# end
#
# end
#
# App.run!
#
class Base < Sinatra::Base
include Server::Routing
include Server::Helpers
include Server::Conditions
# Default interface to run the Web Server on
DEFAULT_HOST = '0.0.0.0'
# Default port to run the Web Server on
DEFAULT_PORT = 8000
use Rack::UserAgent
set :bind, DEFAULT_HOST
set :port, DEFAULT_PORT
before do
@request = Request.new(@env)
@response = Response.new
end
not_found { [404, {'Content-Type' => 'text/html'}, ['']] }
#
# Run the web server.
#
# @param [Hash] options Additional options.
#
# @option options [String] :host
# The host the server will listen on.
#
# @option options [Integer] :port
# The port the server will bind to.
#
# @option options [String] :server
# The Web Server to run on.
#
# @option options [Boolean] :background (false)
# Specifies wether the server will run in the background or run
# in the foreground.
#
# @raise [Errno::EADDRINUSE]
# The port is already in use.
#
# @api public
#
def self.run!(options={},&block)
if options[:background]
Thread.new(options) { |options| super(options) }
else
super(options,&block)
end
end
end
end
end
end