paraxial 0.7.0 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/paraxial/checker.rb +42 -2
- data/lib/paraxial/free_tier.rb +34 -0
- data/lib/paraxial/helpers.rb +12 -0
- data/lib/paraxial/initializers/marshal_patch.rb +2 -2
- data/lib/paraxial/initializers/startup.rb +2 -0
- data/lib/paraxial/version.rb +1 -1
- data/lib/paraxial.rb +75 -2
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0a6510720489f0277f96eef42e60e10e7f3958ab6a3763aa3941c022c497a314
|
4
|
+
data.tar.gz: 497e56a5048f7b6cbb5d2238e5d9059a66cec676dde27d9474faaaee6a5d0fb6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 64182cfa8039d867bbc5e113e5f421a3e1141e833790222c52ae6191099289fbd056cef3163442c949db576d1de76402c8d5196fd05da46169e34f64de77ab71
|
7
|
+
data.tar.gz: 7fbc2ed7db3b3afb3d43a935e667d4ffc26464034c7070f8d15ba28db03c9ee5fb1fc327d56005ecefd615a39845cc8fe5f5e5aa92975186b3c9f3b615c1410b
|
data/lib/paraxial/checker.rb
CHANGED
@@ -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.
|
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
|
data/lib/paraxial/helpers.rb
CHANGED
@@ -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
|
@@ -4,9 +4,9 @@ unless Rails.env.test? || File.basename($0) == 'rake' || defined?(Rails::Generat
|
|
4
4
|
alias_method :original_load, :load
|
5
5
|
|
6
6
|
def load(source, proc = nil)
|
7
|
-
exg = Paraxial.configuration
|
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
|
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|
|
data/lib/paraxial/version.rb
CHANGED
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
|
|
@@ -83,7 +156,7 @@ module Paraxial
|
|
83
156
|
|
84
157
|
def self.check_exploit_guard
|
85
158
|
if configuration.nil?
|
86
|
-
puts "[Paraxial] Exploit Guard, no
|
159
|
+
puts "[Paraxial] Exploit Guard, no configuration exists, will not run"
|
87
160
|
return
|
88
161
|
end
|
89
162
|
|
@@ -95,7 +168,7 @@ module Paraxial
|
|
95
168
|
when nil
|
96
169
|
puts "[Paraxial] Exploit Guard, not configured, will not run"
|
97
170
|
else
|
98
|
-
puts "[Paraxial] Exploit Guard, bad value"
|
171
|
+
puts "[Paraxial] Exploit Guard, bad configuration value: #{configuration.exploit_guard}, will not run"
|
99
172
|
end
|
100
173
|
end
|
101
174
|
|
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.
|
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-
|
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
|