scopes_extractor 0.1.0 → 0.3.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: 694da3bb3d2fd3ed580db8d5afa0da7bac2c2326037ed4218b57d87eca7ca174
4
- data.tar.gz: 100836692c414cd682653231a65a5937dc8b201560bbf10fa95e96e38d9b39a8
3
+ metadata.gz: 9213285da286cb2ad488374dc8e5971d34bb06987b710c2bbd4dcac12f3d1384
4
+ data.tar.gz: af84cd2c4e8e8a43ccb40f126bc1996e812bf66b828e2a3b4aea6bd5dcba9531
5
5
  SHA512:
6
- metadata.gz: 1a3f2040079e8e05cfd2157b259f95b8912813f8f7ec2e867fd0ce9f7802a05a3b46c63027b5493a0d79a2b28f536b67686b9fb3b5d71926e70de31b846764ca
7
- data.tar.gz: 53e92c8b6bcf0608c6c14d6e4f4733e29a8c86a930b7a25de1b6d5242c45d8e7eb38df8d0ebbf50a4c4d49d50e2c5c6286d0609d0140fc44d2d72ba21132466a
6
+ metadata.gz: 20bbb233618c27774be21ab80ac56e8e9ac2b6e749922bdb1768c634b30f7b7b04f23e622f0a958ddc257e6ed5ef1239fb94aec973eafbfe0c20c3300c831d60
7
+ data.tar.gz: 5612a5f74b44fd9904e0f7b3ba22218104ee68e36ca27b15dbcaf8f437e22e74f680f997a832d64ddf0580f4f0d8421baac3532aee8537a8c587f48c45bf7369
@@ -2,37 +2,40 @@
2
2
 
3
3
  # HttpClient Class
4
4
  class HttpClient
5
- @request_options = {
6
- ssl_verifypeer: false,
7
- ssl_verifyhost: 0
8
- }
5
+ def self.request_options
6
+ {
7
+ ssl_verifypeer: false,
8
+ ssl_verifyhost: 0
9
+ }
10
+ end
9
11
 
10
12
  def self.headers(url, authentication)
11
- case
12
- when url.include?('yeswehack')
13
+ if url.include?('yeswehack')
13
14
  { 'Content-Type' => 'application/json', Authorization: "Bearer #{authentication}" }
14
- when url.include?('intigriti')
15
+ elsif url.include?('intigriti')
15
16
  { Authorization: "Bearer #{authentication}" }
16
- when url.include?('bugcrowd')
17
+ elsif url.include?('bugcrowd')
17
18
  { 'Cookie' => authentication }
18
- when url.include?('hackerone')
19
- @request_options[:userpwd] = "#{ENV.fetch('H1_USERNAME', nil)}:#{ENV.fetch('H1_API_KEY', nil)}"
20
- { 'Accept' => 'application/json' }
19
+ elsif url.include?('hackerone')
20
+ h1_credz = Base64.urlsafe_encode64("#{ENV.fetch('H1_USERNAME', nil)}:#{ENV.fetch('H1_API_KEY', nil)}")
21
+ { 'Accept' => 'application/json', 'Authorization' => "Basic #{h1_credz}" }
21
22
  else
22
23
  { 'Content-Type' => 'application/json' }
23
24
  end
24
25
  end
25
26
 
26
27
  def self.get(url, authentication = nil)
27
- @request_options[:headers] = headers(url, authentication)
28
+ options = request_options
29
+ options[:headers] = headers(url, authentication)
28
30
 
29
- Typhoeus.get(url, @request_options)
31
+ Typhoeus.get(url, options)
30
32
  end
31
33
 
32
34
  def self.post(url, data)
33
- @request_options[:headers] = { 'Content-Type' => 'application/json' }
34
- @request_options[:body] = data
35
+ options = request_options
36
+ options[:headers] = { 'Content-Type' => 'application/json' }
37
+ options[:body] = data
35
38
 
36
- Typhoeus.post(url, @request_options)
39
+ Typhoeus.post(url, options)
37
40
  end
38
- end
41
+ end
@@ -39,4 +39,4 @@ class Bugcrowd
39
39
  match[0]
40
40
  end
41
41
  end
42
- end
42
+ end
@@ -6,7 +6,9 @@ class Bugcrowd
6
6
  # Bugcrowd Sync Programs
7
7
  class Programs
8
8
  def self.sync(results, options, cookie, page_id = 1)
9
- response = HttpClient.get("https://bugcrowd.com/programs.json?page[]=#{page_id}&waitlistable[]=false&joinable[]=false", cookie)
9
+ response = HttpClient.get(
10
+ "https://bugcrowd.com/programs.json?page[]=#{page_id}&waitlistable[]=false&joinable[]=false", cookie
11
+ )
10
12
  return unless response&.code == 200
11
13
 
12
14
  body = JSON.parse(response.body)
@@ -33,4 +35,4 @@ class Bugcrowd
33
35
  }
34
36
  end
35
37
  end
36
- end
38
+ end
@@ -21,7 +21,7 @@ class Bugcrowd
21
21
  in_scopes = JSON.parse(response.body)['targets']
22
22
  scopes['in'] = parse_scopes(in_scopes)
23
23
 
24
- scopes['out'] = { } # TODO
24
+ scopes['out'] = {} # TODO
25
25
 
26
26
  scopes
27
27
  end
@@ -40,4 +40,4 @@ class Hackerone
40
40
  { next_page: json_body['links']['next'], programs: json_body['data'] }
41
41
  end
42
42
  end
43
- end
43
+ end
@@ -5,13 +5,13 @@ class Hackerone
5
5
  class Scopes
6
6
  def self.sync(program)
7
7
  scopes = {}
8
- response = HttpClient.get( "https://api.hackerone.com/v1/hackers/programs/#{program[:slug]}")
8
+ response = HttpClient.get("https://api.hackerone.com/v1/hackers/programs/#{program[:slug]}")
9
9
  return scopes unless response&.code == 200
10
10
 
11
11
  in_scopes = JSON.parse(response.body)['relationships']['structured_scopes']['data']
12
12
  scopes['in'] = parse_scopes(in_scopes)
13
13
 
14
- scopes['out'] = { } # TODO
14
+ scopes['out'] = {} # TODO
15
15
 
16
16
  scopes
17
17
  end
@@ -47,4 +47,4 @@ class Hackerone
47
47
  normalized
48
48
  end
49
49
  end
50
- end
50
+ end
@@ -19,7 +19,8 @@ class Intigriti
19
19
  next if program['status'] == 4 # Suspended
20
20
 
21
21
  results[program['name']] = program_info(program)
22
- results[program['name']]['scopes'] = Scopes.sync({ handle: program['handle'], company: program['companyHandle'] }, token)
22
+ results[program['name']]['scopes'] =
23
+ Scopes.sync({ handle: program['handle'], company: program['companyHandle'] }, token)
23
24
  end
24
25
  end
25
26
 
@@ -30,7 +30,7 @@ class Intigriti
30
30
  end
31
31
 
32
32
  def self.submit_otp(mechanize)
33
- return if ENV['INTIGRITI_OTP']&.empty?
33
+ return if ENV['INTIGRITI_OTP'] && ENV['INTIGRITI_OTP'].empty?
34
34
 
35
35
  totp_page = mechanize.get('https://login.intigriti.com/account/loginwith2fa')
36
36
  totp_code = ROTP::TOTP.new(ENV.fetch('INTI_OTP', nil))
@@ -51,4 +51,4 @@ class Intigriti
51
51
  token_page.body&.undump
52
52
  end
53
53
  end
54
- end
54
+ end
@@ -4,7 +4,7 @@ class YesWeHack
4
4
  # YesWeHack Auth Class
5
5
  class Auth
6
6
  def self.jwt
7
- totp_token = get_totp_token
7
+ totp_token = extract_totp_token
8
8
  return unless totp_token
9
9
 
10
10
  response = send_totp(totp_token)
@@ -16,7 +16,7 @@ class YesWeHack
16
16
  jwt
17
17
  end
18
18
 
19
- def self.get_totp_token
19
+ def self.extract_totp_token
20
20
  data = { email: ENV.fetch('YWH_EMAIL', nil), password: ENV.fetch('YWH_PASSWORD', nil) }.to_json
21
21
  response = HttpClient.post('https://api.yeswehack.com/login', data)
22
22
  return unless response&.code == 200
@@ -32,4 +32,4 @@ class YesWeHack
32
32
  response
33
33
  end
34
34
  end
35
- end
35
+ end
@@ -39,4 +39,4 @@ class YesWeHack
39
39
  }
40
40
  end
41
41
  end
42
- end
42
+ end
@@ -25,6 +25,8 @@ class YesWeHack
25
25
 
26
26
  normalized = normalize(infos['scope'])
27
27
  normalized.each do |asset|
28
+ next unless asset.include?('.')
29
+
28
30
  scopes_normalized << asset
29
31
  end
30
32
  end
@@ -32,25 +34,25 @@ class YesWeHack
32
34
  scopes_normalized
33
35
  end
34
36
 
35
- # rubocop:disable Metrics/AbcSize
36
- # rubocop:disable Metrics/MethodLength
37
- # rubocop:disable Metrics/PerceivedComplexity
38
- # rubocop:disable Metrics/CyclomaticComplexity
39
37
  def self.normalize(scope)
40
38
  # Remove (+++) & When end with '*'
41
39
  scope = scope.gsub(/\(?\+\)?/, '').sub(/\*$/, '').strip
42
40
  return [] if scope.include?('<') # <yourdomain>-yeswehack.domain.tld
43
41
 
42
+ scope = scope.split[0] # When spaces
43
+
44
44
  normalized = []
45
45
 
46
- match = scope.match(/^(.*)\((.*)\)$/) # Ex: *.lazada.(sg|vn|co.id|co.th|com|com.ph|com.my)
47
- if match && match[1] && match[2]
48
- tlds = match[2].split('|')
49
- tlds.each { |tld| normalized << "#{match[1]}#{tld}" }
50
- elsif scope.include?(' ')
51
- normalized << scope.split(' ')[0]
46
+ multi_subs = scope.match(/^\((.*)\)(.*)/) # Ex: (online|portal|agents|agentuat|surinameuat|surinameopsuat|suriname|thailandevoa).vfsevisa.com
47
+ multi_tld = scope.match(/^(.*)\((.*)\)$/) # Ex: *.lazada.(sg|vn|co.id|co.th|com|com.ph|com.my)
48
+ if multi_tld && multi_tld[1] && multi_tld[2]
49
+ tlds = multi_tld[2].split('|')
50
+ tlds.each { |tld| normalized << "#{multi_tld[1]}#{tld}" }
52
51
  elsif scope.match?(%r{https?://\*})
53
52
  normalized << scope.sub(%r{https?://}, '')
53
+ elsif multi_subs && multi_subs[1] && multi_subs[2]
54
+ subs = multi_subs[1].split('|')
55
+ subs.each { |sub| normalized << "#{sub}#{multi_subs[2]}"}
54
56
  else
55
57
  normalized << scope
56
58
  end
@@ -58,4 +60,4 @@ class YesWeHack
58
60
  normalized
59
61
  end
60
62
  end
61
- end
63
+ end
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'base64'
3
4
  require 'dotenv'
4
5
  require 'json'
5
6
  require 'rotp'
@@ -31,8 +32,8 @@ class ScopesExtractor
31
32
 
32
33
  if options[:yeswehack]
33
34
  jwt = YesWeHack::Auth.jwt
34
-
35
35
  results['YesWeHack'] = {}
36
+
36
37
  YesWeHack::Programs.sync(results['YesWeHack'], options, jwt)
37
38
  end
38
39
 
@@ -52,9 +53,12 @@ class ScopesExtractor
52
53
 
53
54
  if options[:hackerone]
54
55
  results['Hackerone'] = {}
56
+
55
57
  Hackerone::Programs.sync(results['Hackerone'], options)
56
58
  end
57
59
 
58
- p results
60
+ File.open('extract.json', 'w') { |f| f.write(JSON.pretty_generate(results)) } if options[:save]
61
+
62
+ results
59
63
  end
60
- end
64
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: scopes_extractor
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joshua MARTINELLE
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-05-13 00:00:00.000000000 Z
11
+ date: 2023-05-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: colorize
@@ -85,45 +85,45 @@ dependencies:
85
85
  - !ruby/object:Gem::Version
86
86
  version: 2.9.1
87
87
  - !ruby/object:Gem::Dependency
88
- name: typhoeus
88
+ name: rotp
89
89
  requirement: !ruby/object:Gem::Requirement
90
90
  requirements:
91
91
  - - "~>"
92
92
  - !ruby/object:Gem::Version
93
- version: '1.4'
93
+ version: '6.2'
94
94
  - - ">="
95
95
  - !ruby/object:Gem::Version
96
- version: 1.4.0
96
+ version: 6.2.2
97
97
  type: :runtime
98
98
  prerelease: false
99
99
  version_requirements: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: '1.4'
103
+ version: '6.2'
104
104
  - - ">="
105
105
  - !ruby/object:Gem::Version
106
- version: 1.4.0
106
+ version: 6.2.2
107
107
  - !ruby/object:Gem::Dependency
108
- name: rotp
108
+ name: typhoeus
109
109
  requirement: !ruby/object:Gem::Requirement
110
110
  requirements:
111
111
  - - "~>"
112
112
  - !ruby/object:Gem::Version
113
- version: '6.2'
113
+ version: '1.4'
114
114
  - - ">="
115
115
  - !ruby/object:Gem::Version
116
- version: 6.2.2
116
+ version: 1.4.0
117
117
  type: :runtime
118
118
  prerelease: false
119
119
  version_requirements: !ruby/object:Gem::Requirement
120
120
  requirements:
121
121
  - - "~>"
122
122
  - !ruby/object:Gem::Version
123
- version: '6.2'
123
+ version: '1.4'
124
124
  - - ">="
125
125
  - !ruby/object:Gem::Version
126
- version: 6.2.2
126
+ version: 1.4.0
127
127
  description:
128
128
  email:
129
129
  - contact@jomar.fr