paraxial 0.2.0 → 0.4.0

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: 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