paraxial 0.2.0 → 0.4.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: 70c0596f1eef97562cfcb511a053227074b08349c28081f76fde5e7481085eeb
4
- data.tar.gz: a129cedace488343816f94ad89a712825b9e000de2dffa041f0ba9ab997f18d7
3
+ metadata.gz: ce7c75f780f9b356d4a15b4fb834bb6f064a8f5a39ead6e629a4f42ff2768010
4
+ data.tar.gz: 929b701d0e47c7a12b1654c3426e515b37824f591b7a65b2c9a22630c72bc8cc
5
5
  SHA512:
6
- metadata.gz: 3e67e1dc3fe51b437fc52b6ad026d155b7caea38a9d804e7676d96a2825fcd8833b320dd88f1151c313784eb7b49468c07a6f37275cdbf25bd5d66fda0d00c39
7
- data.tar.gz: 0c93c320b498c22f7feaea3483562da418fe36af99c587652ffa8a19a2da10216b8ec4b131c44096dd6a3fd46a7ded086c161ff035f8b3264868b5e64ae15f3a
6
+ metadata.gz: b1d9decea112098e9c71cf36d071fe1fbe86028ac23b34d4b9a704771d7a007a42f56abbaea51dc65825067e0ac5d029781b7c344c82a3cd339716908f6d8451
7
+ data.tar.gz: 54bff15c7c351b7f3e74eae787d2858f12e4ded57be06cb3f5872147cdccae90819396837fa60e5ddeda6fff758eddeef0868fed4d02748c3873282c6c59306e
@@ -0,0 +1,130 @@
1
+ require 'rpatricia'
2
+ module Paraxial
3
+ module Checker
4
+ @allows = { 'v4' => Patricia.new, 'v6' => Patricia.new(:AF_INET6) }
5
+ @bans = { 'v4' => Patricia.new, 'v6' => Patricia.new(:AF_INET6) }
6
+
7
+ @thread = Thread.new do
8
+ loop do
9
+ get_abr
10
+ sleep(10)
11
+ end
12
+ end
13
+
14
+ def self.get_abr
15
+ uri = URI.parse(Paraxial::Helpers.get_paraxial_url + '/api/abr')
16
+ headers = { 'Content-Type': 'application/json' }
17
+
18
+ body = { api_key: ENV['PARAXIAL_API_KEY'] }
19
+ r = Net::HTTP.post(uri, body.to_json, headers)
20
+ if r.code == '200'
21
+ put_abr(JSON.parse(r.body))
22
+ else
23
+ 'ab_failed'
24
+ end
25
+ end
26
+
27
+ def self.put_abr(abr)
28
+ # Expected input: a hash
29
+ # {"allows"=>[{"address"=>[96, 56, 162, 210], "netmask"=>32}],
30
+ # "bans"=>
31
+ # [{"address"=>[8193, 3512, 34211, 0, 0, 35374, 880, 29492], "netmask"=>128},
32
+ # {"address"=>[111, 56, 162, 210], "netmask"=>32}],
33
+ # "rules"=>[]}
34
+ ipv4_a = []
35
+ ipv4_b = []
36
+ ipv6_a = []
37
+ ipv6_b = []
38
+ abr.each do |key, value|
39
+ next if key == 'rules' # skip rules for now
40
+
41
+ value.each do |ip|
42
+ address = ip['address']
43
+ if address.length == 4
44
+ if key == 'allows'
45
+ ipv4_a << address.join('.')
46
+ elsif key == 'bans'
47
+ ipv4_b << address.join('.')
48
+ end
49
+ elsif key == 'allows'
50
+ ipv6_a << address.map { |n| n.to_s(16).rjust(4, '0') }.join(':')
51
+ elsif key == 'bans'
52
+ ipv6_b << address.map { |n| n.to_s(16).rjust(4, '0') }.join(':')
53
+ end
54
+ end
55
+ end
56
+
57
+ ab = { 'allows' => { 'v4' => ipv4_a, 'v6' => ipv6_a }, 'bans' => { 'v4' => ipv4_b, 'v6' => ipv6_b } }
58
+ Paraxial::Checker.put(ab)
59
+ end
60
+
61
+ def self.put(allow_ban)
62
+ allows = allow_ban['allows']
63
+ bans = allow_ban['bans']
64
+ @allows = { 'v4' => create_patricia(allows['v4'], 'v4'), 'v6' => create_patricia(allows['v6'], 'v6') }
65
+ @bans = { 'v4' => create_patricia(bans['v4'], 'v4'), 'v6' => create_patricia(bans['v6'], 'v6') }
66
+ :ok
67
+ end
68
+
69
+ def self.create_patricia(list, type)
70
+ if type == 'v4'
71
+ p = Patricia.new
72
+ list.each do |ip|
73
+ p.add(ip)
74
+ end
75
+ p
76
+ elsif type == 'v6'
77
+ p = Patricia.new(:AF_INET6)
78
+ list.each do |ip|
79
+ p.add(ip)
80
+ end
81
+ p
82
+ else
83
+ raise 'Wrong type in Paraxial::Checker.create_patricia'
84
+ end
85
+ end
86
+
87
+ def self.ban_ip(ip)
88
+ if ip.include?('.')
89
+ # IPv4
90
+ current_t = @bans['v4']
91
+ current_t.add(ip)
92
+ @bans['v4'] = current_t
93
+ else
94
+ # IPv6
95
+ current_t = @bans['v6']
96
+ current_t.add(ip)
97
+ @bans['v6'] = current_t
98
+ end
99
+
100
+ uri = URI.parse(Paraxial::Helpers.get_ban_url)
101
+ headers = { 'Content-Type': 'application/json' }
102
+
103
+ body = { api_key: ENV['PARAXIAL_API_KEY'], ip_address: ip }
104
+ r = Net::HTTP.post(uri, body.to_json, headers)
105
+ if r.code == '200'
106
+ :ok
107
+ else
108
+ :error
109
+ end
110
+ end
111
+
112
+ def self.allow_ip?(ip)
113
+ if ip.include?('.')
114
+ if !@allows['v4'].search_best(ip).nil? # v4 on allow list
115
+ true
116
+ elsif !@bans['v4'].search_best(ip).nil? # v4 on ban list
117
+ false
118
+ else # v4 on no list
119
+ true
120
+ end
121
+ elsif !@allows['v6'].search_best(ip).nil? # v6 on allow list
122
+ true
123
+ elsif !@bans['v6'].search_best(ip).nil? # v6 on ban list
124
+ false
125
+ else # v6 on no list
126
+ true
127
+ end
128
+ end
129
+ end
130
+ end
data/lib/paraxial/cli.rb CHANGED
@@ -4,6 +4,8 @@ require 'net/http'
4
4
  require 'uri'
5
5
  require 'json'
6
6
  require 'time'
7
+ require 'yaml'
8
+ require_relative 'helpers'
7
9
 
8
10
  module Paraxial
9
11
  class CLI < Thor
@@ -16,6 +18,13 @@ module Paraxial
16
18
 
17
19
  def scan
18
20
  puts '[Paraxial] Scan starting...'
21
+ if check_rubocop_configuration
22
+ puts '[Paraxial] .rubocop.yml contains the required paraxial configuration.'
23
+ else
24
+ puts '[Paraxial] .rubocop.yml does not contain the required paraxial configuration.'
25
+ puts '[Paraxial] How to configure: TODO_URL'
26
+ exit
27
+ end
19
28
 
20
29
  if ENV['PARAXIAL_API_KEY'].nil?
21
30
  puts '[Paraxial] Environment variable PARAXIAL_API_KEY not found'
@@ -30,21 +39,32 @@ module Paraxial
30
39
  rubocop = `rubocop --only #{cops} --format json`
31
40
  lockfile = File.read('./Gemfile.lock')
32
41
  api_key = ENV['PARAXIAL_API_KEY']
33
- uri = URI.parse(ENV['PARAXIAL_URL'] + '/api/ruby_scan')
42
+ uri = URI.parse(Paraxial::Helpers.get_paraxial_url + '/api/ruby_scan')
34
43
  headers = { 'Content-Type': 'application/json' }
35
44
 
36
- body = { rubocop:, lockfile:, api_key:, timestamp: Paraxial.get_timestamp }
45
+ body = { rubocop: rubocop, lockfile: lockfile, api_key: api_key, timestamp: Paraxial.get_timestamp }
37
46
  response = Net::HTTP.post(uri, body.to_json, headers)
38
- puts "[Paraxial] scan result: #{response.body}"
47
+ m = JSON.parse(response.body)
48
+ findings = m['ok']['findings']
49
+ puts
50
+ puts "[Paraxial] Scan count #{findings.length}"
51
+ puts
52
+ findings.each do |finding|
53
+ puts finding
54
+ puts
55
+ end
56
+ puts "[Paraxial] Scan UUID #{m['ok']['scan_uuid']}"
57
+ puts "[Paraxial] Scan URL #{m['ok']['scan_url']}"
39
58
  github_valid = (!!github_app and !!install_id and !!repo_owner and !!repo_name and !!pr_number)
40
59
 
41
60
  if github_app and github_valid == false
42
61
  puts '[Paraxial] --github_app missing arguments'
43
62
  puts '[Paraxial] Required: --github_app, --install_id, --repo_owner, --repo_name, --pr_number'
44
63
  elsif github_app and github_valid
45
- uuid_regex = /UUID\s+(\S+)/
46
- match = response.body.match(uuid_regex)
47
- uuid = match[1] if match
64
+ # uuid_regex = /UUID\s+(\S+)/
65
+ # match = response.body.match(uuid_regex)
66
+ # uuid = match[1] if match
67
+ uuid = m['ok']['scan_uuid']
48
68
  if uuid
49
69
  final_uuid = uuid.chomp('.')
50
70
  censored_backend_map = {
@@ -60,7 +80,7 @@ module Paraxial
60
80
 
61
81
  censored_backend_map['api_key'] = api_key
62
82
  backend_map = censored_backend_map
63
- parax_uri = URI.parse(ENV['PARAXIAL_URL'] + '/api/github_app')
83
+ parax_uri = URI.parse(Paraxial::Helpers.get_paraxial_url + '/api/github_app')
64
84
  github_pr_url = "https://github.com/#{repo_owner}/#{repo_name}/pull/#{pr_number}"
65
85
 
66
86
  rr = Net::HTTP.post(parax_uri, backend_map.to_json, headers)
@@ -75,5 +95,22 @@ module Paraxial
75
95
  end
76
96
  end
77
97
  end
98
+
99
+ private
100
+
101
+ def check_rubocop_configuration
102
+ rubocop_file = File.join(Dir.pwd, '.rubocop.yml')
103
+
104
+ return false unless File.exist?(rubocop_file)
105
+
106
+ config = YAML.load_file(rubocop_file)
107
+ required_key = 'require'
108
+
109
+ if config.is_a?(Hash) && config[required_key].is_a?(Array)
110
+ config[required_key].include?('paraxial')
111
+ else
112
+ false
113
+ end
114
+ end
78
115
  end
79
116
  end
@@ -0,0 +1,11 @@
1
+ module Paraxial
2
+ module Helpers
3
+ def self.get_paraxial_url
4
+ @paraxial_url ||= ENV['PARAXIAL_URL'] || 'https://app.paraxial.io/'
5
+ end
6
+
7
+ def self.get_ban_url
8
+ get_paraxial_url + '/api/ban_ip'
9
+ end
10
+ end
11
+ end
@@ -1,57 +1,73 @@
1
1
  require 'bundler'
2
2
  require 'paraxial'
3
3
  require 'rpatricia'
4
+ require_relative '../helpers'
5
+ require_relative '../checker'
4
6
 
5
7
  Bundler.setup
6
8
 
7
- Rails.application.config.to_prepare do
8
- # Your code here
9
- puts '[Paraxial] Runtime start'
10
- api_key = ENV['PARAXIAL_API_KEY']
9
+ unless Rails.env.test? || File.basename($0) == 'rake' || defined?(Rails::Generators)
10
+ Rails.application.config.to_prepare do
11
+ puts '[Paraxial] Init start'
12
+ api_key = ENV['PARAXIAL_API_KEY']
11
13
 
12
- if api_key.nil?
13
- puts '[Paraxial] PARAXIAL_API_KEY key not set, agent not started'
14
- elsif ENV['PARAXIAL_URL'].nil?
15
- puts '[Paraxial] PARAXIAL_URL key not set, agent not started'
16
- elsif Rails.env.test?
17
- puts '[Paraxial] Test environment detected, agent not started'
18
- else
19
- deps_and_licenses = []
20
- Bundler.load.specs.each do |spec|
21
- # Print the gem name and license
22
- h = { name: spec.name, version: spec.version.to_s, description: Paraxial.trim_dep(spec.description),
23
- license: spec.license || 'None' }
24
- deps_and_licenses << h
25
- end
26
- deps_and_licenses << { name: 'ruby', version: RUBY_VERSION, description: 'The Ruby Programming Language',
27
- license: 'Ruby' }
28
- uri = URI.parse(ENV['PARAXIAL_URL'] + '/api/ruby_app_lic')
29
- headers = { 'Content-Type': 'application/json' }
14
+ if api_key.nil?
15
+ puts '[Paraxial] Init PARAXIAL_API_KEY key not set, agent not started'
16
+ elsif Rails.env.test?
17
+ puts '[Paraxial] Init Test environment detected, agent not started'
18
+ else
19
+ begin
20
+ puts '[Paraxial] Init config valid, agent starting'
21
+ deps_and_licenses = []
22
+ Bundler.load.specs.each do |spec|
23
+ # Print the gem name and license
24
+ h = { name: spec.name, version: spec.version.to_s, description: Paraxial.trim_dep(spec.description),
25
+ license: spec.license || 'None' }
26
+ deps_and_licenses << h
27
+ end
28
+ deps_and_licenses << { name: 'ruby', version: RUBY_VERSION, description: 'The Ruby Programming Language',
29
+ license: 'Ruby' }
30
+ uri = URI.parse(Paraxial::Helpers.get_paraxial_url + '/api/ruby_app_lic')
31
+ headers = { 'Content-Type': 'application/json' }
30
32
 
31
- body = { app_lic: deps_and_licenses, api_key:, timestamp: Paraxial.get_timestamp }
32
- Thread.new do
33
- Net::HTTP.post(uri, body.to_json, headers)
34
- end
33
+ body = { app_lic: deps_and_licenses, api_key:, timestamp: Paraxial.get_timestamp }
34
+ cloud_uri = URI.parse(Paraxial::Helpers.get_paraxial_url + '/api/cloud_ip_list')
35
+ response = Net::HTTP.get(cloud_uri)
35
36
 
36
- cloud_uri = URI.parse(ENV['PARAXIAL_URL'] + '/api/cloud_ip_list')
37
- response = Net::HTTP.get(cloud_uri)
37
+ Thread.new do
38
+ Net::HTTP.post(uri, body.to_json, headers)
39
+ end
38
40
 
39
- # https://github.com/jkitching/rpatricia
40
- pt_v4 = Patricia.new
41
- pt_v6 = Patricia.new(:AF_INET6)
42
- cloud_list = JSON.parse(response)
43
- cloud_list.each do |k, v|
44
- if k.include?('::')
45
- pt_v6.add(k, v)
46
- else
47
- pt_v4.add(k, v)
41
+ # https://github.com/jkitching/rpatricia
42
+ pt_v4 = Patricia.new
43
+ pt_v6 = Patricia.new(:AF_INET6)
44
+ cloud_list = JSON.parse(response)
45
+ cloud_list.each do |k, v|
46
+ if k.include?('::')
47
+ pt_v6.add(k, v)
48
+ else
49
+ pt_v4.add(k, v)
50
+ end
51
+ end
52
+ puts '[Paraxial] Cloud IPs set'
53
+ # puts '[Paraxial] pt_v4.num_nodes'
54
+ # puts pt_v4.num_nodes
55
+ # puts 'pt_v6.num_nodes'
56
+ # puts pt_v6.num_nodes
57
+ PARAXIAL_IPV4 = pt_v4
58
+ PARAXIAL_IPV6 = pt_v6
59
+ # ab = Paraxial.get_abr
60
+ # puts "[Paraxial] Allows/Bans set: #{ab}"
61
+ rescue Errno::ECONNREFUSED => _e
62
+ puts '[Paraxial] Init HTTP request failed, check configuration'
63
+ PARAXIAL_IPV4 = Patricia.new unless defined?(PARAXIAL_IPV4)
64
+ PARAXIAL_IPV6 = Patricia.new(:AF_INET6) unless defined?(PARAXIAL_IPV4)
65
+ rescue StandardError => e
66
+ puts e
67
+ puts '[Paraxial] Init error, check configuration'
68
+ PARAXIAL_IPV4 = Patricia.new unless defined?(PARAXIAL_IPV4)
69
+ PARAXIAL_IPV6 = Patricia.new(:AF_INET6) unless defined?(PARAXIAL_IPV4)
48
70
  end
49
71
  end
50
- # puts '[Paraxial] pt_v4.num_nodes'
51
- # puts pt_v4.num_nodes
52
- # puts 'pt_v6.num_nodes'
53
- # puts pt_v6.num_nodes
54
- PARAXIAL_IPV4 = pt_v4
55
- PARAXIAL_IPV6 = pt_v6
56
72
  end
57
73
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Paraxial
4
- VERSION = '0.2.0'
4
+ VERSION = '0.4.0'
5
5
  end
data/lib/paraxial.rb CHANGED
@@ -9,10 +9,9 @@ require_relative 'rubocop/cop/paraxial/send'
9
9
  require_relative 'rubocop/cop/paraxial/constantize'
10
10
  require_relative 'rubocop/cop/paraxial/html_safe'
11
11
  require_relative 'rubocop/cop/paraxial/sql'
12
- require_relative "paraxial/version"
12
+ require_relative 'paraxial/version'
13
13
  require_relative 'paraxial/cli'
14
14
 
15
-
16
15
  module Paraxial
17
16
  class Error < StandardError; end
18
17
  # Your code goes here...
@@ -27,7 +26,7 @@ module Paraxial
27
26
 
28
27
  if request_path.end_with?('.php')
29
28
  # Return a 404 response if the request path ends with '.php'
30
- [404, { 'Content-Type' => 'text/plain' }, ["Not Found from Paraxial.io"]]
29
+ [404, { 'Content-Type' => 'text/plain' }, ['Not Found from Paraxial.io']]
31
30
  else
32
31
  # Pass the request to the next middleware or the application
33
32
  @app.call(env)
@@ -37,15 +36,23 @@ module Paraxial
37
36
 
38
37
  def self.get_timestamp
39
38
  utc_time = Time.now.utc
40
- utc_time.strftime("%Y-%m-%d %H:%M:%S.%6N") + "Z"
39
+ utc_time.strftime('%Y-%m-%d %H:%M:%S.%6N') + 'Z'
41
40
  end
42
41
 
43
42
  def self.cloud_ip?(ip)
44
43
  !!(PARAXIAL_IPV4.search_best(ip) or PARAXIAL_IPV6.search_best(ip))
45
44
  end
46
45
 
46
+ def self.ban_ip(ip)
47
+ Paraxial::Checker.ban_ip(ip)
48
+ end
49
+
50
+ def self.allow_ip?(ip)
51
+ Paraxial::Checker.allow_ip?(ip)
52
+ end
53
+
47
54
  def self.trim_dep(input)
48
- if input == nil
55
+ if input.nil?
49
56
  nil
50
57
  else
51
58
  cleaned_string = input.gsub(/\n/, '')
@@ -54,9 +61,7 @@ module Paraxial
54
61
  period_index = cleaned_string.index('.')
55
62
 
56
63
  # If there's a period, truncate the string up to that point
57
- if period_index
58
- cleaned_string = cleaned_string[0..period_index]
59
- end
64
+ cleaned_string = cleaned_string[0..period_index] if period_index
60
65
 
61
66
  cleaned_string
62
67
  end
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.2.0
4
+ version: 0.4.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-08-06 00:00:00.000000000 Z
11
+ date: 2024-08-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -80,8 +80,10 @@ files:
80
80
  - Rakefile
81
81
  - exe/paraxial
82
82
  - lib/paraxial.rb
83
+ - lib/paraxial/checker.rb
83
84
  - lib/paraxial/cli.rb
84
85
  - lib/paraxial/engine.rb
86
+ - lib/paraxial/helpers.rb
85
87
  - lib/paraxial/initializers/startup.rb
86
88
  - lib/paraxial/version.rb
87
89
  - lib/rubocop/cop/paraxial/constantize.rb