ronin-web-server 0.1.0.beta1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/gemspec.yml ADDED
@@ -0,0 +1,31 @@
1
+ name: ronin-web-server
2
+ summary: A custom Ruby web server based on Sinatra.
3
+ description: |
4
+ ronin-web-server is a custom Ruby web server based on Sinatra tailored for
5
+ security research and development.
6
+
7
+ license: LGPL-3.0
8
+ authors: Postmodern
9
+ email: postmodern.mod3@gmail.com
10
+ homepage: https://ronin-rb.dev/
11
+ has_yard: true
12
+
13
+ metadata:
14
+ documentation_uri: https://rubydoc.info/gems/ronin-web-server
15
+ source_code_uri: https://github.com/postmodern/ronin-web-server
16
+ bug_tracker_uri: https://github.com/postmodern/ronin-web-server/issues
17
+ changelog_uri: https://github.com/postmodern/ronin-web-server/blob/master/ChangeLog.md
18
+ rubygems_mfa_required: 'true'
19
+
20
+ required_ruby_version: ">= 3.0.0"
21
+
22
+ dependencies:
23
+ webrick: ~> 1.0
24
+ rack: ~> 2.2
25
+ rack-user_agent: ~> 0.5
26
+ sinatra: ~> 3.0
27
+ # Ronin dependencies:
28
+ ronin-support: ~> 1.0.0.beta1
29
+
30
+ development_dependencies:
31
+ bundler: ~> 2.0
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # ronin-web-server - A custom Ruby web server based on Sinatra.
4
+ #
5
+ # Copyright (c) 2006-2022 Hal Brodigan (postmodern.mod3 at gmail.com)
6
+ #
7
+ # ronin-web-server is free software: you can redistribute it and/or modify
8
+ # it under the terms of the GNU Lesser General Public License as published
9
+ # by the Free Software Foundation, either version 3 of the License, or
10
+ # (at your option) any later version.
11
+ #
12
+ # ronin-web-server is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ # GNU Lesser General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU Lesser General Public License
18
+ # along with ronin-web-server. If not, see <https://www.gnu.org/licenses/>.
19
+ #
20
+
21
+ require 'ronin/web/server/base'
22
+
23
+ module Ronin
24
+ module Web
25
+ module Server
26
+ #
27
+ # The main Web Server class used by {Web.server}.
28
+ #
29
+ class App < Base
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,214 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # ronin-web-server - A custom Ruby web server based on Sinatra.
4
+ #
5
+ # Copyright (c) 2006-2022 Hal Brodigan (postmodern.mod3 at gmail.com)
6
+ #
7
+ # ronin-web-server is free software: you can redistribute it and/or modify
8
+ # it under the terms of the GNU Lesser General Public License as published
9
+ # by the Free Software Foundation, either version 3 of the License, or
10
+ # (at your option) any later version.
11
+ #
12
+ # ronin-web-server is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ # GNU Lesser General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU Lesser General Public License
18
+ # along with ronin-web-server. If not, see <https://www.gnu.org/licenses/>.
19
+ #
20
+
21
+ require 'ronin/web/server/request'
22
+ require 'ronin/web/server/response'
23
+ require 'ronin/web/server/routing'
24
+ require 'ronin/web/server/helpers'
25
+ require 'ronin/web/server/conditions'
26
+
27
+ require 'rack'
28
+ require 'sinatra/base'
29
+ require 'rack/user_agent'
30
+
31
+ module Ronin
32
+ module Web
33
+ module Server
34
+ #
35
+ # The base-class for all Ronin Web Servers. Extends
36
+ # [Sinatra::Base](http://rubydoc.info/gems/sinatra/Sinatra/Base)
37
+ # with additional {Routing routing methods}, {Helpers helper methods} and
38
+ # Sinatra {Conditions conditions}.
39
+ #
40
+ # ## Routing Methods
41
+ #
42
+ # * {Routing::ClassMethods#any any}: registers a route that responds to
43
+ # `GET`, `POST`, `PUT`, `PATCH`, `DELETE` and `OPTIONS` requests.
44
+ # * {Routing::ClassMethods#default default}: registers the default route.
45
+ # * {Routing::ClassMethods#basic_auth basic_auth}: enables Basic-Auth
46
+ # authentication for the whole app.
47
+ # * {Routing::ClassMethods#redirect redirect}: adds a route that simply
48
+ # redirects to another URL.
49
+ # * {Routing::ClassMethods#file file}: mounts a file at the given path.
50
+ # a given file.
51
+ # * {Routing::ClassMethods#directory directory}: mounts a directory at
52
+ # the given path.
53
+ # * {Routing::ClassMethods#public_dir public_dir}: mounts a directory
54
+ # at the root.
55
+ # * {Routing::ClassMethods#vhost vhost}: mounts a Rack app for the given
56
+ # vhost.
57
+ # * {Routing::ClassMethods#mount mount}: mounts a Rack app at the given
58
+ # path.
59
+ #
60
+ # ## Helper Methods
61
+ #
62
+ # * {Helpers#h h}: escapes HTML entities.
63
+ # * {Helpers#file file}: sends a file.
64
+ # * {Helpers#mime_type_for mime_type_for}: returns the MIME type for the
65
+ # file.
66
+ # * {Helpers#content_type_for content_type_for}: sets the `Content-Type`
67
+ # for the file.
68
+ #
69
+ # ## Routing Conditions
70
+ #
71
+ # * {Conditions::ClassMethods#client_ip client_ip}: filters requests
72
+ # based on their client IP address.
73
+ # * {Conditions::ClassMethods#asn asn}: filters requests by the client
74
+ # IP's ASN number.
75
+ # * {Conditions::ClassMethods#country_code country_code}: filters requests
76
+ # by the client IP's ASN country code.
77
+ # * {Conditions::ClassMethods#asn_name asn_name}: filters requests by the
78
+ # client IP's ASN company/ISP name.
79
+ # * {Conditions::ClassMethods#host host}: filters requests based on the
80
+ # `Host` header.
81
+ # * {Conditions::ClassMethods#referer referer}: filters requests based on
82
+ # the `Referer` header.
83
+ # * {Conditions::ClassMethods#user_agent user_agent}: filters requests
84
+ # based on the `User-Agent` header.
85
+ # * {Conditions::ClassMethods#browser browser}: filters requests based on
86
+ # the browser name within the `User-Agent` header.
87
+ # * {Conditions::ClassMethods#browser_version browser_version}: filters
88
+ # requests based on the browser version within the `User-Agent` header.
89
+ # * {Conditions::ClassMethods#device_type device_type}: filters requests
90
+ # based on the device type within the `User-Agent` header.
91
+ # * {Conditions::ClassMethods#os os}: filters requests based on the OS
92
+ # within the `User-Agent` header.
93
+ # * {Conditions::ClassMethods#os_version os_version}: filters requests
94
+ # based on the OS version within the `User-Agent` header.
95
+ #
96
+ # ## Examples
97
+ #
98
+ # require 'ronin/web/server'
99
+ #
100
+ # class App < Ronin::Web::Server::Base
101
+ #
102
+ # # mount a file
103
+ # file '/sitemap.xml', './files/sitemap.xml'
104
+ #
105
+ # # mount a directory
106
+ # directory '/downloads/', '/tmp/downloads/'
107
+ #
108
+ # get '/' do
109
+ # # renders views/index.erb
110
+ # erb :index
111
+ # end
112
+ #
113
+ # get '/test' do
114
+ # "raw text here"
115
+ # end
116
+ #
117
+ # end
118
+ #
119
+ # App.run!
120
+ #
121
+ class Base < Sinatra::Base
122
+
123
+ include Server::Routing
124
+ include Server::Helpers
125
+ include Server::Conditions
126
+
127
+ # Default interface to run the Web Server on
128
+ DEFAULT_HOST = '0.0.0.0'
129
+
130
+ # Default port to run the Web Server on
131
+ DEFAULT_PORT = 8000
132
+
133
+ use Rack::UserAgent
134
+
135
+ set :host, DEFAULT_HOST
136
+ set :port, DEFAULT_PORT
137
+
138
+ before do
139
+ @request = Request.new(@env)
140
+ @response = Response.new
141
+ end
142
+
143
+ not_found { [404, {'Content-Type' => 'text/html'}, ['']] }
144
+
145
+ #
146
+ # Run the web server.
147
+ #
148
+ # @param [Hash] options Additional options.
149
+ #
150
+ # @option options [String] :host
151
+ # The host the server will listen on.
152
+ #
153
+ # @option options [Integer] :port
154
+ # The port the server will bind to.
155
+ #
156
+ # @option options [String] :server
157
+ # The Web Server to run on.
158
+ #
159
+ # @option options [Boolean] :background (false)
160
+ # Specifies wether the server will run in the background or run
161
+ # in the foreground.
162
+ #
163
+ # @api public
164
+ #
165
+ def self.run!(options={})
166
+ set(options)
167
+
168
+ handler = detect_rack_handler
169
+ handler_name = handler.name.gsub(/.*::/, '')
170
+
171
+ # rubocop:disable Lint/ShadowingOuterLocalVariable
172
+ runner = lambda { |handler,server|
173
+ begin
174
+ handler.run(server,Host: bind, Port: port) do |server|
175
+ trap(:INT) { quit!(server,handler_name) }
176
+ trap(:TERM) { quit!(server,handler_name) }
177
+
178
+ set :running, true
179
+ end
180
+ rescue Errno::EADDRINUSE
181
+ warn "ronin-web-server: address is already in use: #{bind}:#{port}"
182
+ end
183
+ }
184
+ # rubocop:enable Lint/ShadowingOuterLocalVariable
185
+
186
+ if options[:background]
187
+ Thread.new(handler,self,&runner)
188
+ else
189
+ runner.call(handler,self)
190
+ end
191
+
192
+ return self
193
+ end
194
+
195
+ #
196
+ # Stops the web server.
197
+ #
198
+ # @param [#call] server
199
+ # The Rack Handler server.
200
+ #
201
+ # @param [String] handler_name
202
+ # The name of the handler.
203
+ #
204
+ # @api semipublic
205
+ #
206
+ def self.quit!(server,handler_name)
207
+ # Use thins' hard #stop! if available, otherwise just #stop
208
+ server.respond_to?(:stop!) ? server.stop! : server.stop
209
+ end
210
+
211
+ end
212
+ end
213
+ end
214
+ end