wafris 2.0.0 → 2.0.1

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
  SHA256:
3
- metadata.gz: f0dfe47e533d91f974d391af755f1bd8e148808cbfe86dd6755b839201282b47
4
- data.tar.gz: bd7135922d96fa7789cc65dbd47635c4b1e84a4e7b27a6b4dde5a1a00cc15ac8
3
+ metadata.gz: 856e806ccf66f3810f2395de0062e005940bb8c06f66987b8ec3670126fb9dac
4
+ data.tar.gz: 24278b15cb5178ac90cce1cfdd35769d508cca5dd21fb655f79a23629c18ab91
5
5
  SHA512:
6
- metadata.gz: 0c1e66690ca97e6f9a9349f1960f92f5376175660bebc9a172eabe849af6806d4c5f278f1765a22b36ce75797a757bf9cb3719a58446aaa5fa8fe0356c348cf0
7
- data.tar.gz: 35a3e86f1f3c63ec38c3d67adbfb952fa89a062dad78450bfd365f45c1a1607f689e104e2c7ef6faac3a00461e07022d041e5d2f667396ad81baa3af30be8acf
6
+ metadata.gz: fa60b8e07f6960d69fd79a50661e25b8fdfd47a1d364bdfdb0e6d398117d36ebfa845f98475b8db4a9d102d317c50e5379acf249cfd10d5cba645f176d6a9e2e
7
+ data.tar.gz: 647bc36e84bf57c3f076ca83101cdf59e0d03cf3d51f3c39feb53af5be936b6e74368a9810ba6612e2149576f41dd25eb8fa92b2cc85bdda8d62afda0db8e4cd
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Wafris
4
+ class IpResolver
5
+ # List of possible IP headers in order of priority
6
+ IP_HEADERS = %w[
7
+ HTTP_X_REAL_IP
8
+ HTTP_X_TRUE_CLIENT_IP
9
+ HTTP_FLY_CLIENT_IP
10
+ HTTP_CF_CONNECTING_IP
11
+ ].freeze
12
+
13
+ def initialize(request)
14
+ @request_env = request.env
15
+ @ip = request.ip
16
+ end
17
+
18
+ def resolve
19
+ return @request_env[ip_header] if ip_header
20
+
21
+ @ip
22
+ end
23
+
24
+ private
25
+
26
+ def ip_header
27
+ IP_HEADERS.find { |header| @request_env[header] }
28
+ end
29
+ end
30
+ end
@@ -1,80 +1,43 @@
1
1
  # frozen_string_literal: true
2
2
 
3
-
4
3
  module Wafris
5
4
  class Middleware
6
5
  def initialize(app)
7
6
  @app = app
7
+ ProxyFilter.set_filter
8
8
  end
9
9
 
10
-
11
10
  def call(env)
12
-
13
- user_defined_proxies = ENV['TRUSTED_PROXY_RANGES'].split(',') if ENV['TRUSTED_PROXY_RANGES']
14
-
15
- valid_ipv4_octet = /\.(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])/
16
-
17
- trusted_proxies = Regexp.union(
18
- /\A127#{valid_ipv4_octet}{3}\z/, # localhost IPv4 range 127.x.x.x, per RFC-3330
19
- /\A::1\z/, # localhost IPv6 ::1
20
- /\Af[cd][0-9a-f]{2}(?::[0-9a-f]{0,4}){0,7}\z/i, # private IPv6 range fc00 .. fdff
21
- /\A10#{valid_ipv4_octet}{3}\z/, # private IPv4 range 10.x.x.x
22
- /\A172\.(1[6-9]|2[0-9]|3[01])#{valid_ipv4_octet}{2}\z/, # private IPv4 range 172.16.0.0 .. 172.31.255.255
23
- /\A192\.168#{valid_ipv4_octet}{2}\z/, # private IPv4 range 192.168.x.x
24
- /\Alocalhost\z|\Aunix(\z|:)/i, # localhost hostname, and unix domain sockets
25
- *user_defined_proxies
26
- )
27
-
28
- Rack::Request.ip_filter = lambda { |ip| trusted_proxies.match?(ip) }
29
-
30
11
  request = Rack::Request.new(env)
31
- # Forcing UTF-8 encoding on all strings for Sqlite3 compatibility
32
-
33
- # List of possible IP headers in order of priority
34
- ip_headers = [
35
- 'HTTP_X_REAL_IP',
36
- 'HTTP_X_TRUE_CLIENT_IP',
37
- 'HTTP_FLY_CLIENT_IP',
38
- 'HTTP_CF_CONNECTING_IP'
39
- ]
40
-
41
- # Find the first header that is present in the environment
42
- ip_header = ip_headers.find { |header| env[header] }
43
-
44
- # Use the found header or fallback to remote_ip if none of the headers are present
45
- ip = (ip_header ? env[ip_header] : request.ip).force_encoding('UTF-8')
46
-
47
- user_agent = request.user_agent ? request.user_agent.force_encoding('UTF-8') : nil
48
- path = request.path.force_encoding('UTF-8')
49
- parameters = Rack::Utils.build_query(request.params).force_encoding('UTF-8')
50
- host = request.host.to_s.force_encoding('UTF-8')
51
- request_method = String.new(request.request_method).force_encoding('UTF-8')
52
-
53
- # Submitted for evaluation
54
- headers = env.each_with_object({}) { |(k, v), h| h[k] = v.force_encoding('UTF-8') if k.start_with?('HTTP_') }
55
- body = request.body.read
56
-
57
- request_id = env.fetch('action_dispatch.request_id', SecureRandom.uuid.to_s)
58
- request_timestamp = Time.now.utc.to_i
59
-
60
- treatment = Wafris.evaluate(ip, user_agent, path, parameters, host, request_method, headers, body, request_id, request_timestamp)
12
+ wafris_request = WafrisRequest.new(request, env)
13
+
14
+ treatment = Wafris.evaluate(
15
+ wafris_request.ip,
16
+ wafris_request.user_agent,
17
+ wafris_request.path,
18
+ wafris_request.parameters,
19
+ wafris_request.host,
20
+ wafris_request.request_method,
21
+ wafris_request.headers,
22
+ wafris_request.body,
23
+ wafris_request.request_id,
24
+ wafris_request.request_timestamp
25
+ )
61
26
 
62
- # These values match what the client tests expect (200, 404, 403, 500
27
+ # These values match what the client tests expect (200, 404, 403, 500)
63
28
  if treatment == 'Allowed' || treatment == 'Passed'
64
- @app.call(env)
29
+ @app.call(env)
65
30
  elsif treatment == 'Blocked'
66
31
  [403, { 'content-type' => 'text/plain' }, ['Blocked']]
67
32
  else
68
- #ap request
33
+ #ap request
69
34
  [500, { 'content-type' => 'text/plain' }, ['Error']]
70
35
  end
71
36
 
72
37
  rescue StandardError => e
73
-
74
38
  LogSuppressor.puts_log "[Wafris] Detailed Error: #{e.class} - #{e.message}"
75
39
  LogSuppressor.puts_log "[Wafris] Backtrace: #{e.backtrace.join("\n")}"
76
40
  @app.call(env)
77
-
78
41
  end
79
42
  end
80
43
  end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Wafris
4
+ module ProxyFilter
5
+ def self.set_filter
6
+ user_defined_proxies = ENV['TRUSTED_PROXY_RANGES'].split(',') if ENV['TRUSTED_PROXY_RANGES']
7
+
8
+ valid_ipv4_octet = /\.(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])/
9
+
10
+ trusted_proxies = Regexp.union(
11
+ /\A127#{valid_ipv4_octet}{3}\z/, # localhost IPv4 range 127.x.x.x, per RFC-3330
12
+ /\A::1\z/, # localhost IPv6 ::1
13
+ /\Af[cd][0-9a-f]{2}(?::[0-9a-f]{0,4}){0,7}\z/i, # private IPv6 range fc00 .. fdff
14
+ /\A10#{valid_ipv4_octet}{3}\z/, # private IPv4 range 10.x.x.x
15
+ /\A172\.(1[6-9]|2[0-9]|3[01])#{valid_ipv4_octet}{2}\z/, # private IPv4 range 172.16.0.0 .. 172.31.255.255
16
+ /\A192\.168#{valid_ipv4_octet}{2}\z/, # private IPv4 range 192.168.x.x
17
+ /\Alocalhost\z|\Aunix(\z|:)/i, # localhost hostname, and unix domain sockets
18
+ *user_defined_proxies
19
+ )
20
+
21
+ Rack::Request.ip_filter = lambda { |ip| trusted_proxies.match?(ip) }
22
+ end
23
+ end
24
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Wafris
4
- VERSION = "2.0.0"
4
+ VERSION = "2.0.1"
5
5
  end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Wafris
4
+ class WafrisRequest
5
+ attr_reader :ip, :user_agent, :path, :parameters, :host, :request_method,
6
+ :headers, :body, :request_id, :request_timestamp
7
+
8
+ def initialize(request, env)
9
+ @ip = encode_to_utf8(IpResolver.new(request).resolve)
10
+ @user_agent = encode_to_utf8(request.user_agent)
11
+ @path = encode_to_utf8(request.path)
12
+ @parameters = encode_to_utf8(Rack::Utils.build_query(request.params))
13
+ @host = encode_to_utf8(request.host.to_s)
14
+ @request_method = encode_to_utf8(request.request_method)
15
+ @headers = extract_headers(env)
16
+ @body = request.body.read
17
+ @request_id = env.fetch('action_dispatch.request_id', SecureRandom.uuid.to_s)
18
+ @request_timestamp = Time.now.utc.to_i
19
+ end
20
+
21
+ private
22
+
23
+ def extract_headers(env)
24
+ env.each_with_object({}) do |(k, v), h|
25
+ h[k] = encode_to_utf8(v) if k.start_with?('HTTP_')
26
+ end
27
+ end
28
+
29
+ def encode_to_utf8(value)
30
+ value&.dup&.force_encoding('UTF-8')
31
+ end
32
+ end
33
+ end
data/lib/wafris.rb CHANGED
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
-
4
3
  require 'rails'
5
4
  require 'sqlite3'
6
5
  require 'ipaddr'
@@ -10,9 +9,11 @@ require 'awesome_print'
10
9
  require 'wafris/configuration'
11
10
  require 'wafris/middleware'
12
11
  require 'wafris/log_suppressor'
12
+ require 'wafris/proxy_filter'
13
+ require 'wafris/ip_resolver'
14
+ require 'wafris/wafris_request'
13
15
 
14
16
  require 'wafris/railtie' if defined?(Rails::Railtie)
15
- ActiveSupport::Deprecation.behavior = :silence
16
17
 
17
18
  module Wafris
18
19
  class << self
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wafris
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Buckbee
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2024-07-17 00:00:00.000000000 Z
12
+ date: 2024-09-16 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rack
@@ -179,10 +179,13 @@ extra_rdoc_files: []
179
179
  files:
180
180
  - lib/wafris.rb
181
181
  - lib/wafris/configuration.rb
182
+ - lib/wafris/ip_resolver.rb
182
183
  - lib/wafris/log_suppressor.rb
183
184
  - lib/wafris/middleware.rb
185
+ - lib/wafris/proxy_filter.rb
184
186
  - lib/wafris/railtie.rb
185
187
  - lib/wafris/version.rb
188
+ - lib/wafris/wafris_request.rb
186
189
  homepage:
187
190
  licenses:
188
191
  - Elastic-2.0