ritm 1.0.2 → 1.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/ritm/configuration.rb +0 -3
- data/lib/ritm/helpers/encodings.rb +0 -2
- data/lib/ritm/interception/http_forwarder.rb +28 -7
- data/lib/ritm/interception/request_interceptor_servlet.rb +2 -3
- data/lib/ritm/main.rb +0 -1
- data/lib/ritm/proxy/cert_signing_https_server.rb +1 -1
- data/lib/ritm/proxy/launcher.rb +7 -9
- data/lib/ritm/proxy/proxy_server.rb +1 -17
- data/lib/ritm/proxy/ssl_reverse_proxy.rb +3 -5
- data/lib/ritm/version.rb +1 -2
- metadata +18 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e057b05ae3168ee5ff218a8c6ce01c46184e523c
|
4
|
+
data.tar.gz: 91438a6194dce60e5dc4827d76c5a5056e8db1c5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 71cc70b613e2d72c8914d8ce896f7baea3f11c85623490a915a7c88160303572df4a4a429b2651ec803c8138c2b586ac0cf998a71c0ce4bddd659c0d5b56e749
|
7
|
+
data.tar.gz: b2bcb23777a6c8cbaab3672c2f2954818d4d602cdfc6e08f45c289a118832ae735a6743727e9eba3e79d4240e249d6a89ba4d0abff8aa585dff20d3d62a5eb8f
|
data/lib/ritm/configuration.rb
CHANGED
@@ -2,7 +2,6 @@ require 'dot_hash'
|
|
2
2
|
require 'set'
|
3
3
|
|
4
4
|
module Ritm
|
5
|
-
# Global Ritm settings
|
6
5
|
class Configuration
|
7
6
|
def default_settings # rubocop:disable Metrics/MethodLength
|
8
7
|
{
|
@@ -60,12 +59,10 @@ module Ritm
|
|
60
59
|
end
|
61
60
|
end
|
62
61
|
|
63
|
-
# Re-enable interception
|
64
62
|
def enable
|
65
63
|
@settings.intercept[:enabled] = true
|
66
64
|
end
|
67
65
|
|
68
|
-
# Disable interception
|
69
66
|
def disable
|
70
67
|
@settings.intercept[:enabled] = false
|
71
68
|
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
require 'zlib'
|
2
2
|
|
3
3
|
module Ritm
|
4
|
-
# ENCODER/DECODER of HTTP content
|
5
4
|
module Encodings
|
6
5
|
ENCODINGS = %i[identity gzip deflate].freeze
|
7
6
|
|
@@ -34,7 +33,6 @@ module Ritm
|
|
34
33
|
class << self
|
35
34
|
private
|
36
35
|
|
37
|
-
# Returns data unchanged. Identity is the default value of Accept-Encoding headers.
|
38
36
|
def identity(data)
|
39
37
|
data
|
40
38
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'faraday'
|
2
|
-
|
3
2
|
require 'ritm/interception/intercept_utils'
|
3
|
+
require 'webrick/cookie'
|
4
4
|
|
5
5
|
module Ritm
|
6
6
|
# Forwarder that acts as a WEBrick <-> Faraday adaptor: Works this way:
|
@@ -13,6 +13,21 @@ module Ritm
|
|
13
13
|
#
|
14
14
|
# Besides the possible modifications to be done by interceptors there might be automated globally configured
|
15
15
|
# transformations like header stripping/adding.
|
16
|
+
|
17
|
+
class ParamEncoder
|
18
|
+
def encode(params)
|
19
|
+
pairs = params.map { |k, v| "#{k}=#{v}" }
|
20
|
+
pairs.join('&')
|
21
|
+
end
|
22
|
+
|
23
|
+
def decode(query)
|
24
|
+
query.split('&').each_with_object({}) do |param, params|
|
25
|
+
k, v = param.split('=')
|
26
|
+
params[k] = v
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
16
31
|
class HTTPForwarder
|
17
32
|
include InterceptUtils
|
18
33
|
|
@@ -21,9 +36,11 @@ module Ritm
|
|
21
36
|
@response_interceptor = response_interceptor
|
22
37
|
@config = context_config
|
23
38
|
# TODO: make SSL verification a configuration setting
|
24
|
-
@client = Faraday.new(
|
39
|
+
@client = Faraday.new(
|
40
|
+
ssl: { verify: false },
|
41
|
+
request: { params_encoder: ParamEncoder.new }
|
42
|
+
) do |conn|
|
25
43
|
conn.adapter :net_http
|
26
|
-
conn.proxy = @config.misc.upstream_proxy unless @config.misc.upstream_proxy.nil?
|
27
44
|
end
|
28
45
|
end
|
29
46
|
|
@@ -39,11 +56,10 @@ module Ritm
|
|
39
56
|
def faraday_forward(request)
|
40
57
|
req_method = request.request_method.downcase
|
41
58
|
@client.send req_method do |req|
|
59
|
+
req.options[:proxy] = @config.misc.upstream_proxy
|
42
60
|
req.url request.request_uri
|
43
61
|
req.body = request.body
|
44
|
-
request.header.each
|
45
|
-
req.headers[name] = value
|
46
|
-
end
|
62
|
+
request.header.each { |name, value| req.headers[name] = value }
|
47
63
|
end
|
48
64
|
end
|
49
65
|
|
@@ -51,7 +67,12 @@ module Ritm
|
|
51
67
|
webrick_response.status = faraday_response.status
|
52
68
|
webrick_response.body = faraday_response.body
|
53
69
|
faraday_response.headers.each do |name, value|
|
54
|
-
|
70
|
+
case name
|
71
|
+
when 'set-cookie'
|
72
|
+
WEBrick::Cookie.parse_set_cookies(value).each { |cookie| webrick_response.cookies << cookie }
|
73
|
+
else
|
74
|
+
webrick_response[name] = value
|
75
|
+
end
|
55
76
|
end
|
56
77
|
webrick_response
|
57
78
|
end
|
@@ -1,12 +1,11 @@
|
|
1
1
|
require 'webrick'
|
2
|
-
require 'ritm/interception/http_forwarder'
|
3
2
|
|
4
3
|
module Ritm
|
5
4
|
# Actual implementation of the SSL Reverse Proxy service (decoupled from the certificate handling)
|
6
5
|
class RequestInterceptorServlet < WEBrick::HTTPServlet::AbstractServlet
|
7
|
-
def initialize(server,
|
6
|
+
def initialize(server, forwarder)
|
8
7
|
super server
|
9
|
-
@forwarder =
|
8
|
+
@forwarder = forwarder
|
10
9
|
end
|
11
10
|
|
12
11
|
def service(request, response)
|
data/lib/ritm/main.rb
CHANGED
@@ -9,7 +9,7 @@ module Ritm
|
|
9
9
|
module Proxy
|
10
10
|
# Patches WEBrick::HTTPServer SSL context creation to get
|
11
11
|
# a callback on the 'Client Helo' step of the SSL-Handshake if SNI is specified
|
12
|
-
# So
|
12
|
+
# So RitM can create self-signed certificates on the fly
|
13
13
|
class CertSigningHTTPSServer < WEBrick::HTTPServer
|
14
14
|
# Override
|
15
15
|
def setup_ssl_context(config)
|
data/lib/ritm/proxy/launcher.rb
CHANGED
@@ -2,6 +2,7 @@ require 'ritm/proxy/ssl_reverse_proxy'
|
|
2
2
|
require 'ritm/proxy/proxy_server'
|
3
3
|
require 'ritm/certs/ca'
|
4
4
|
require 'ritm/interception/handlers'
|
5
|
+
require 'ritm/interception/http_forwarder'
|
5
6
|
|
6
7
|
module Ritm
|
7
8
|
module Proxy
|
@@ -13,13 +14,11 @@ module Ritm
|
|
13
14
|
build_proxy
|
14
15
|
end
|
15
16
|
|
16
|
-
# Starts the service (non blocking)
|
17
17
|
def start
|
18
18
|
@https.start_async
|
19
19
|
@http.start_async
|
20
20
|
end
|
21
21
|
|
22
|
-
# Stops the service
|
23
22
|
def shutdown
|
24
23
|
@https.shutdown
|
25
24
|
@http.shutdown
|
@@ -32,8 +31,10 @@ module Ritm
|
|
32
31
|
ssl_proxy_host = @conf.ssl_reverse_proxy.bind_address
|
33
32
|
ssl_proxy_port = @conf.ssl_reverse_proxy.bind_port
|
34
33
|
@https_forward = "#{ssl_proxy_host}:#{ssl_proxy_port}"
|
35
|
-
|
36
|
-
|
34
|
+
|
35
|
+
request_interceptor = default_request_handler(session)
|
36
|
+
response_interceptor = default_response_handler(session)
|
37
|
+
@forwarder = HTTPForwarder.new(request_interceptor, response_interceptor, @conf)
|
37
38
|
|
38
39
|
crt_path = @conf.ssl_reverse_proxy.ca.pem
|
39
40
|
key_path = @conf.ssl_reverse_proxy.ca.key
|
@@ -47,17 +48,14 @@ module Ritm
|
|
47
48
|
Logger: WEBrick::Log.new(File.open(File::NULL, 'w')),
|
48
49
|
https_forward: @https_forward,
|
49
50
|
ProxyVia: nil,
|
50
|
-
|
51
|
-
response_interceptor: @response_interceptor,
|
51
|
+
forwarder: @forwarder,
|
52
52
|
ritm_conf: @conf)
|
53
53
|
end
|
54
54
|
|
55
55
|
def build_reverse_proxy
|
56
56
|
@https = Ritm::Proxy::SSLReverseProxy.new(@conf.ssl_reverse_proxy.bind_port,
|
57
57
|
@certificate,
|
58
|
-
@
|
59
|
-
request_interceptor: @request_interceptor,
|
60
|
-
response_interceptor: @response_interceptor)
|
58
|
+
@forwarder)
|
61
59
|
end
|
62
60
|
|
63
61
|
def ca_certificate(pem, key)
|
@@ -1,15 +1,12 @@
|
|
1
1
|
require 'webrick'
|
2
2
|
require 'webrick/httpproxy'
|
3
3
|
require 'ritm/helpers/patches'
|
4
|
-
require 'ritm/interception/intercept_utils'
|
5
4
|
|
6
5
|
module Ritm
|
7
6
|
module Proxy
|
8
7
|
# Proxy server that accepts request and response intercept handlers for HTTP traffic
|
9
8
|
# HTTPS traffic is redirected to the SSLReverseProxy for interception
|
10
9
|
class ProxyServer < WEBrick::HTTPProxyServer
|
11
|
-
include InterceptUtils
|
12
|
-
|
13
10
|
def start_async
|
14
11
|
trap(:TERM) { shutdown }
|
15
12
|
trap(:INT) { shutdown }
|
@@ -28,20 +25,7 @@ module Ritm
|
|
28
25
|
def proxy_service(req, res)
|
29
26
|
# Proxy Authentication
|
30
27
|
proxy_auth(req, res)
|
31
|
-
|
32
|
-
# Request modifier handler
|
33
|
-
intercept_request(@config[:request_interceptor], req, @config[:ritm_conf].intercept.request)
|
34
|
-
|
35
|
-
begin
|
36
|
-
send("do_#{req.request_method}", req, res)
|
37
|
-
rescue NoMethodError
|
38
|
-
raise WEBrick::HTTPStatus::MethodNotAllowed, "unsupported method `#{req.request_method}'."
|
39
|
-
rescue StandardError => err
|
40
|
-
raise WEBrick::HTTPStatus::ServiceUnavailable, err.message
|
41
|
-
end
|
42
|
-
|
43
|
-
# Response modifier handler
|
44
|
-
intercept_response(@config[:response_interceptor], req, res, @config[:ritm_conf].intercept.response)
|
28
|
+
@config[:forwarder].forward(req, res)
|
45
29
|
end
|
46
30
|
|
47
31
|
# Override
|
@@ -11,9 +11,8 @@ module Ritm
|
|
11
11
|
# Creates a HTTPS server with the given settings
|
12
12
|
# @param port [Fixnum]: TCP port to bind the service
|
13
13
|
# @param ca [Ritm::CA]: The certificate authority used to sign fake server certificates
|
14
|
-
# @param
|
15
|
-
|
16
|
-
def initialize(port, ca, conf, request_interceptor: nil, response_interceptor: nil)
|
14
|
+
# @param forwarder [Ritm::HTTPForwarder]: Forwards http traffic with interception
|
15
|
+
def initialize(port, ca, forwarder)
|
17
16
|
@ca = ca
|
18
17
|
default_vhost = 'localhost'
|
19
18
|
@server = CertSigningHTTPSServer.new(Port: port,
|
@@ -21,8 +20,7 @@ module Ritm
|
|
21
20
|
Logger: WEBrick::Log.new(File.open(File::NULL, 'w')),
|
22
21
|
ca: ca,
|
23
22
|
**vhost_settings(default_vhost))
|
24
|
-
|
25
|
-
@server.mount '/', RequestInterceptorServlet, request_interceptor, response_interceptor, conf
|
23
|
+
@server.mount '/', RequestInterceptorServlet, forwarder
|
26
24
|
end
|
27
25
|
|
28
26
|
def start_async
|
data/lib/ritm/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ritm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sebastián Tello
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-12-
|
11
|
+
date: 2017-12-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: certificate_authority
|
@@ -142,14 +142,28 @@ dependencies:
|
|
142
142
|
requirements:
|
143
143
|
- - "~>"
|
144
144
|
- !ruby/object:Gem::Version
|
145
|
-
version: '
|
145
|
+
version: '2.0'
|
146
146
|
type: :development
|
147
147
|
prerelease: false
|
148
148
|
version_requirements: !ruby/object:Gem::Requirement
|
149
149
|
requirements:
|
150
150
|
- - "~>"
|
151
151
|
- !ruby/object:Gem::Version
|
152
|
-
version: '
|
152
|
+
version: '2.0'
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: sinatra-contrib
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - "~>"
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '2.0'
|
160
|
+
type: :development
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - "~>"
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '2.0'
|
153
167
|
- !ruby/object:Gem::Dependency
|
154
168
|
name: thin
|
155
169
|
requirement: !ruby/object:Gem::Requirement
|