ritm 1.0.2 → 1.0.3
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.
- 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
|