paraxial 0.8.0 → 0.9.0

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: a8acee8353bb32e2bebce880b05661b968904d02f9e0748b6041325d8f24491b
4
- data.tar.gz: 4ef0694246bc93ae69c1f88a439be89e5fdbd29bcd0ee53406de63d19a791257
3
+ metadata.gz: 0a6510720489f0277f96eef42e60e10e7f3958ab6a3763aa3941c022c497a314
4
+ data.tar.gz: 497e56a5048f7b6cbb5d2238e5d9059a66cec676dde27d9474faaaee6a5d0fb6
5
5
  SHA512:
6
- metadata.gz: 8127e330796dcea327b3b8b029831c4b851e548df33bf114a4a7b07039e34ed1f48687525747ce11ce08298771a28f95edc0d420bae07d776f08e5b812fdd566
7
- data.tar.gz: 40a7c37df1123e0f8dfc87d31e950f8fc35fbea1729f436405ae18c8af9d1f77d76217450e0e21cb44fd3a713afb6bf49d16bcfda8f5ad5ab00c87c42e492712
6
+ metadata.gz: 64182cfa8039d867bbc5e113e5f421a3e1141e833790222c52ae6191099289fbd056cef3163442c949db576d1de76402c8d5196fd05da46169e34f64de77ab71
7
+ data.tar.gz: 7fbc2ed7db3b3afb3d43a935e667d4ffc26464034c7070f8d15ba28db03c9ee5fb1fc327d56005ecefd615a39845cc8fe5f5e5aa92975186b3c9f3b615c1410b
@@ -3,19 +3,59 @@ module Paraxial
3
3
  module Checker
4
4
  @allows = { 'v4' => Patricia.new, 'v6' => Patricia.new(:AF_INET6) }
5
5
  @bans = { 'v4' => Patricia.new, 'v6' => Patricia.new(:AF_INET6) }
6
-
6
+ @buffer = Queue.new
7
+ @mutex = Mutex.new
7
8
 
8
9
  if Paraxial::Helpers.get_api_key
9
10
  @thread = Thread.new do
10
11
  loop do
11
12
  get_abr
12
13
  sleep(10)
14
+ flush_buffer
15
+ end
16
+ end
17
+ end
18
+
19
+ def self.req_to_buff(req_hash)
20
+ @buffer << req_hash
21
+ end
22
+
23
+ def self.flush_buffer
24
+ @mutex.synchronize do
25
+ requests = []
26
+ until @buffer.empty?
27
+ requests << @buffer.pop(true) rescue nil
13
28
  end
29
+
30
+ send_async_request(requests) unless requests.empty?
14
31
  end
15
32
  end
16
33
 
34
+ def self.send_async_request(requests)
35
+ body =
36
+ {
37
+ http_requests: requests,
38
+ private_api_key: Paraxial::Helpers.get_api_key
39
+ }
40
+
41
+ # Do not send HTTP events when free tier is set to true
42
+ ft = Paraxial::FreeTier.is_free_tier
43
+ if ft
44
+ puts "[Paraxial] HTTP ingest not supported on free tier"
45
+ else
46
+ Thread.new do
47
+ uri = URI.parse(Paraxial::Helpers.get_ingest_url) # Replace with your endpoint
48
+ headers = { 'Content-Type': 'application/json' }
49
+ resp = Net::HTTP.post(uri, body.to_json, headers)
50
+ puts "ingest_url resp.code: #{resp.code}"
51
+ puts resp.body
52
+ end
53
+ end
54
+ end
55
+
56
+
17
57
  def self.get_abr
18
- uri = URI.parse(Paraxial::Helpers.get_paraxial_url + '/api/abr')
58
+ uri = URI.parse(Paraxial::Helpers.get_abr_url)
19
59
  headers = { 'Content-Type': 'application/json' }
20
60
 
21
61
  body = { api_key: Paraxial::Helpers.get_api_key }
@@ -0,0 +1,34 @@
1
+ require 'net/http'
2
+ require 'json'
3
+
4
+ module Paraxial
5
+ module FreeTier
6
+ class << self
7
+ attr_reader :is_free_tier
8
+
9
+ def initialize
10
+ @is_free_tier = true
11
+ check_free_tier_status
12
+ end
13
+
14
+ private
15
+
16
+ # Kicks off an async HTTP request
17
+ def check_free_tier_status
18
+ Thread.new do
19
+ uri = URI.parse(Paraxial::Helpers.get_free_tier_url())
20
+ headers = { 'Content-Type': 'application/json' }
21
+ body = { api_key: Paraxial::Helpers.get_api_key }
22
+ r = Net::HTTP.post(uri, body.to_json, headers)
23
+ result = JSON.parse(r.body)
24
+ # Assume the API response contains a field `free_tier` (true/false)
25
+ @is_free_tier = result['free_tier']
26
+ rescue StandardError => e
27
+ # Handle any errors (network issues, parsing errors, etc.)
28
+ puts "Error fetching free tier status: #{e.message}"
29
+ @is_free_tier = true
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -12,6 +12,18 @@ module Paraxial
12
12
  get_paraxial_url + '/api/exploit'
13
13
  end
14
14
 
15
+ def self.get_free_tier_url
16
+ get_paraxial_url + '/api/free_tier'
17
+ end
18
+
19
+ def self.get_abr_url
20
+ get_paraxial_url + '/api/abr'
21
+ end
22
+
23
+ def self.get_ingest_url
24
+ get_paraxial_url + '/api/ingest'
25
+ end
26
+
15
27
  def self.get_api_key
16
28
  @paraxial_api_key ||= ENV['PARAXIAL_API_KEY']
17
29
  end
@@ -6,7 +6,7 @@ unless Rails.env.test? || File.basename($0) == 'rake' || defined?(Rails::Generat
6
6
  def load(source, proc = nil)
7
7
  exg = Paraxial.configuration&.exploit_guard || nil
8
8
  if [:monitor, :block].include?(exg)
9
- if source.is_a?(String) && source.match?(/ActionView|Net::BufferedIO|ERB|ActiveSupport/)
9
+ if source.is_a?(String) && source.match?(/ActionView|Net::BufferedIO|ERB/)
10
10
  puts "[Paraxial] Exploit Guard triggered, malicious input to Marshal.load"
11
11
  puts source
12
12
 
@@ -3,6 +3,7 @@ require 'paraxial'
3
3
  require 'rpatricia'
4
4
  require_relative '../helpers'
5
5
  require_relative '../checker'
6
+ require_relative '../free_tier'
6
7
 
7
8
  Bundler.setup
8
9
 
@@ -20,6 +21,7 @@ unless Rails.env.test? || File.basename($0) == 'rake' || defined?(Rails::Generat
20
21
  puts '[Paraxial] API key detected, agent starting'
21
22
 
22
23
  Paraxial.check_exploit_guard
24
+ Paraxial::FreeTier.initialize
23
25
 
24
26
  deps_and_licenses = []
25
27
  Bundler.load.specs.each do |spec|
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Paraxial
4
- VERSION = '0.8.0'
4
+ VERSION = '0.9.0'
5
5
  end
data/lib/paraxial.rb CHANGED
@@ -44,7 +44,66 @@ module Paraxial
44
44
  utc_time.strftime('%Y-%m-%d %H:%M:%S.%6N') + 'Z'
45
45
  end
46
46
 
47
+ def self.record(request, status)
48
+ return if Paraxial::Helpers.get_api_key.nil?
49
+
50
+ req_hash =
51
+ {
52
+ ip_address: request.remote_ip,
53
+ http_method: request.request_method,
54
+ path: request.path,
55
+ user_agent: request.user_agent,
56
+ allowed: !request.env['paraxial.deny'],
57
+ status_code: status,
58
+ inserted_at: get_timestamp,
59
+ cloud_ip: request.env['paraxial.cloud_ip'],
60
+ host: request.host
61
+ }
62
+ puts req_hash
63
+ Paraxial::Checker.req_to_buff(req_hash)
64
+ end
65
+
66
+ # routes = ['/login', '/users/:id']
67
+ def self.block_cloud_ip(request, routes)
68
+ return if Paraxial::Helpers.get_api_key.nil?
69
+
70
+ ip = request.remote_ip
71
+ cloud_provider = get_cloud_provider(ip)
72
+
73
+ if cloud_provider
74
+ request.env['paraxial.cloud_ip'] = cloud_provider
75
+ else
76
+ request.env['paraxial.cloud_ip'] = nil
77
+ end
78
+
79
+ route_patterns = routes.map do |route|
80
+ Regexp.new("^" + route.gsub(/:\w+/, '\d+') + "$")
81
+ end
82
+
83
+ match = route_patterns.any? { |pattern| pattern.match?(request.path) }
84
+
85
+ if match and cloud_provider
86
+ request.env['paraxial.deny'] = true
87
+ end
88
+ end
89
+
90
+ def self.req_allowed?(request)
91
+ return if Paraxial::Helpers.get_api_key.nil?
92
+
93
+ if request.env['paraxial.deny'] == true
94
+ false
95
+ elsif Paraxial::Checker.allow_ip?(request.remote_ip) == true
96
+ request.env['paraxial.deny'] = false
97
+ true
98
+ else
99
+ request.env['paraxial.deny'] = true
100
+ false
101
+ end
102
+ end
103
+
47
104
  def self.cloud_ip?(ip)
105
+ return if Paraxial::Helpers.get_api_key.nil?
106
+
48
107
  if ip.include?('.')
49
108
  !!PARAXIAL_IPV4.search_best(ip)
50
109
  else
@@ -52,11 +111,25 @@ module Paraxial
52
111
  end
53
112
  end
54
113
 
114
+ def self.get_cloud_provider(ip)
115
+ return if Paraxial::Helpers.get_api_key.nil?
116
+
117
+ if ip.include?('.')
118
+ PARAXIAL_IPV4.search_best(ip)&.data
119
+ else
120
+ PARAXIAL_IPV6.search_best(ip)&.data
121
+ end
122
+ end
123
+
55
124
  def self.ban_ip(ip)
125
+ return if Paraxial::Helpers.get_api_key.nil?
126
+
56
127
  Paraxial::Checker.ban_ip(ip)
57
128
  end
58
129
 
59
130
  def self.allow_ip?(ip)
131
+ return if Paraxial::Helpers.get_api_key.nil?
132
+
60
133
  Paraxial::Checker.allow_ip?(ip)
61
134
  end
62
135
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: paraxial
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Lubas
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-09-17 00:00:00.000000000 Z
11
+ date: 2024-09-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -97,6 +97,7 @@ files:
97
97
  - lib/paraxial/checker.rb
98
98
  - lib/paraxial/cli.rb
99
99
  - lib/paraxial/engine.rb
100
+ - lib/paraxial/free_tier.rb
100
101
  - lib/paraxial/helpers.rb
101
102
  - lib/paraxial/initializers/marshal_patch.rb
102
103
  - lib/paraxial/initializers/startup.rb