scopes_extractor 0.1.0 → 0.2.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: 694da3bb3d2fd3ed580db8d5afa0da7bac2c2326037ed4218b57d87eca7ca174
4
- data.tar.gz: 100836692c414cd682653231a65a5937dc8b201560bbf10fa95e96e38d9b39a8
3
+ metadata.gz: 2720124a1d479958f99a1e40d303f5a8fa1fb45727b7c575197561522245cd3f
4
+ data.tar.gz: bc579dc76168344ac983876d54db4b55977099e6488fbe26a0971bf85488af35
5
5
  SHA512:
6
- metadata.gz: 1a3f2040079e8e05cfd2157b259f95b8912813f8f7ec2e867fd0ce9f7802a05a3b46c63027b5493a0d79a2b28f536b67686b9fb3b5d71926e70de31b846764ca
7
- data.tar.gz: 53e92c8b6bcf0608c6c14d6e4f4733e29a8c86a930b7a25de1b6d5242c45d8e7eb38df8d0ebbf50a4c4d49d50e2c5c6286d0609d0140fc44d2d72ba21132466a
6
+ metadata.gz: 9b5387a228e502be7cd36c5ea4e67151ece0a046406931619c159c17d4345069b0885b5de27683a63190b5ac0a108023dc7524e406e836179eb12cf820c6be41
7
+ data.tar.gz: 784560b6ed8def4699d7c3e03a34ee02ef5db707183acc7d702e3c058cf0bb0df0c38ceca648609f24cb79941d10dd78bc1f64b8dd4583098bef70dcb19c6f78
@@ -8,14 +8,13 @@ class HttpClient
8
8
  }
9
9
 
10
10
  def self.headers(url, authentication)
11
- case
12
- when url.include?('yeswehack')
11
+ if url.include?('yeswehack')
13
12
  { 'Content-Type' => 'application/json', Authorization: "Bearer #{authentication}" }
14
- when url.include?('intigriti')
13
+ elsif url.include?('intigriti')
15
14
  { Authorization: "Bearer #{authentication}" }
16
- when url.include?('bugcrowd')
15
+ elsif url.include?('bugcrowd')
17
16
  { 'Cookie' => authentication }
18
- when url.include?('hackerone')
17
+ elsif url.include?('hackerone')
19
18
  @request_options[:userpwd] = "#{ENV.fetch('H1_USERNAME', nil)}:#{ENV.fetch('H1_API_KEY', nil)}"
20
19
  { 'Accept' => 'application/json' }
21
20
  else
@@ -35,4 +34,4 @@ class HttpClient
35
34
 
36
35
  Typhoeus.post(url, @request_options)
37
36
  end
38
- end
37
+ 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
@@ -31,8 +31,8 @@ class ScopesExtractor
31
31
 
32
32
  if options[:yeswehack]
33
33
  jwt = YesWeHack::Auth.jwt
34
-
35
34
  results['YesWeHack'] = {}
35
+
36
36
  YesWeHack::Programs.sync(results['YesWeHack'], options, jwt)
37
37
  end
38
38
 
@@ -52,9 +52,10 @@ class ScopesExtractor
52
52
 
53
53
  if options[:hackerone]
54
54
  results['Hackerone'] = {}
55
+
55
56
  Hackerone::Programs.sync(results['Hackerone'], options)
56
57
  end
57
58
 
58
- p results
59
+ results
59
60
  end
60
- end
61
+ 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.2.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-16 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