wafris 2.0.0 → 2.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f0dfe47e533d91f974d391af755f1bd8e148808cbfe86dd6755b839201282b47
4
- data.tar.gz: bd7135922d96fa7789cc65dbd47635c4b1e84a4e7b27a6b4dde5a1a00cc15ac8
3
+ metadata.gz: fab800ba280f295d31d26326cd24af8b30585db667f0cd26cb0b40e78e23dc34
4
+ data.tar.gz: 134f0b73d8cabfa0cd889974301d843e8c4341dc18ee76c23401af0adf313bae
5
5
  SHA512:
6
- metadata.gz: 0c1e66690ca97e6f9a9349f1960f92f5376175660bebc9a172eabe849af6806d4c5f278f1765a22b36ce75797a757bf9cb3719a58446aaa5fa8fe0356c348cf0
7
- data.tar.gz: 35a3e86f1f3c63ec38c3d67adbfb952fa89a062dad78450bfd365f45c1a1607f689e104e2c7ef6faac3a00461e07022d041e5d2f667396ad81baa3af30be8acf
6
+ metadata.gz: 617ee93c06d6b634a78a8a2f03e02d9de5df6916ace984a2efaf791b6635e2e3b4095acc9fc67d3b40200acfb0948502f22ecb1a4f55fcfbd2c26fcb2b2e7565
7
+ data.tar.gz: af26e184475c1d8fb2683cbb4f02dc1b3f08a8f7984c7ac62609cf34cc0721d1894fd82efd49df9a9dd6b3ff08f6a43035ac566d4ad0f13df776c9f1f0e6ec45
@@ -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.2"
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 = encode_to_utf8(request.body&.string)
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.2
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-21 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