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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2f1109dfaeac6ea30bcc246368fbfa4588fd2dd2
4
- data.tar.gz: 22cabc4371ed6a45093b03e094bc2aa433a4362c
3
+ metadata.gz: e057b05ae3168ee5ff218a8c6ce01c46184e523c
4
+ data.tar.gz: 91438a6194dce60e5dc4827d76c5a5056e8db1c5
5
5
  SHA512:
6
- metadata.gz: a898d03940990af84ec7cab9cb172ebc28580179e86965f7be9b0ba806f9a5e51e6ded0e2c6863b91c678907403f00fd4ec442e6bce97faaded946b0a5b888e4
7
- data.tar.gz: d4b1462c4e80f8e8d14acc30e0452bbbf446d43df1899e6f9e1a61cb9dc607132717240abad80ddbd4b82ff19bcf566fd720d807cf70ff1a866d180d4dd337e7
6
+ metadata.gz: 71cc70b613e2d72c8914d8ce896f7baea3f11c85623490a915a7c88160303572df4a4a429b2651ec803c8138c2b586ac0cf998a71c0ce4bddd659c0d5b56e749
7
+ data.tar.gz: b2bcb23777a6c8cbaab3672c2f2954818d4d602cdfc6e08f45c289a118832ae735a6743727e9eba3e79d4240e249d6a89ba4d0abff8aa585dff20d3d62a5eb8f
@@ -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(ssl: { verify: false }) do |conn|
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 do |name, value|
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
- webrick_response[name] = value
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, request_interceptor, response_interceptor, conf)
6
+ def initialize(server, forwarder)
8
7
  super server
9
- @forwarder = HTTPForwarder.new(request_interceptor, response_interceptor, conf)
8
+ @forwarder = forwarder
10
9
  end
11
10
 
12
11
  def service(request, response)
@@ -1,6 +1,5 @@
1
1
  require 'ritm/session'
2
2
 
3
- # Main module
4
3
  module Ritm
5
4
  GLOBAL_SESSION = Session.new
6
5
 
@@ -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 we can create self-signed certificates on the fly
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)
@@ -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
- @request_interceptor = default_request_handler(session)
36
- @response_interceptor = default_response_handler(session)
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
- request_interceptor: @request_interceptor,
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
- @conf,
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 request_interceptor [Proc]: If given, it will be invoked before proxying the request
15
- # @param response_interceptor [Proc]: If give, it will be invoked before sending back the response
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
@@ -1,4 +1,3 @@
1
- # Ritm version
2
1
  module Ritm
3
- VERSION = '1.0.2'.freeze
2
+ VERSION = '1.0.3'.freeze
4
3
  end
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.2
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-25 00:00:00.000000000 Z
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: '1.4'
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: '1.4'
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