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 +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 +1 -1
- data/lib/paraxial/initializers/startup.rb +2 -0
- data/lib/paraxial/version.rb +1 -1
- data/lib/paraxial.rb +73 -0
- 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
|
@@ -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
|
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
|
|
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
|