Projects STRLCPY Hunt3r Commits 0dc2fd70
🤬
  • ■ ■ ■ ■
    README.md
    skipped 5 lines
    6 6  <p align="center">
    7 7   <a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/license-MIT-_red.svg"></a>
    8 8   <a href="https://github.com/EasyRecon/Hunt3r/issues"><img src="https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat"></a>
    9  - <a href="https://github.com/EasyRecon/Hunt3r"><img src="https://img.shields.io/badge/release-v1.4.0-informational"></a>
     9 + <a href="https://github.com/EasyRecon/Hunt3r"><img src="https://img.shields.io/badge/release-v1.5.0-informational"></a>
    10 10   <a href="https://github.com/easyrecon/hunt3r/issues" target="_blank"><img src="https://img.shields.io/github/issues/easyrecon/hunt3r?color=blue" /></a>
    11 11  </p>
    12 12   
    skipped 41 lines
  • ■ ■ ■ ■ ■ ■
    backend/Dockerfile
    skipped 11 lines
    12 12  RUN mv scaleway-cli_2.5.1_linux_amd64 /usr/local/bin/scw
    13 13  RUN chmod +x /usr/local/bin/scw
    14 14   
     15 +## Install AWS CLI
     16 +RUN cd /tmp && curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" && unzip awscliv2.zip && ./aws/install
     17 + 
    15 18  WORKDIR /hunt3r
    16 19  COPY Gemfile /hunt3r/Gemfile
    17 20  COPY Gemfile.lock /hunt3r/Gemfile.lock
    skipped 1 lines
  • ■ ■ ■ ■ ■
    backend/app/controllers/admin/providers_controller.rb
    skipped 79 lines
    80 80  end
    81 81   
    82 82  def provider_is_valid?(providers_params)
    83  - valid = false
    84  - 
    85  - if providers_params[:name] == 'scaleway'
     83 + case providers_params[:name]
     84 + when 'scaleway'
    86 85   path = '/root/.config/scw/config.yaml'
    87 86   dir = File.dirname(path)
    88 87   FileUtils.mkdir_p(dir) unless Dir.exist?(dir)
    skipped 10 lines
    99 98   File.write(path, scw_config)
    100 99   
    101 100   check_config = `scw instance server list -o json`
    102  - check_config.empty? ? nil : valid = true
     101 + valid = !check_config.empty?
     102 + when 'aws'
     103 + path = '/root/.aws/config'
     104 + dir = File.dirname(path)
     105 + FileUtils.mkdir_p(dir) unless Dir.exist?(dir)
     106 + 
     107 + aws_config = <<~HEREDOC
     108 + [default]
     109 + region = #{providers_params[:infos][:region]}
     110 + output = json
     111 + HEREDOC
     112 + 
     113 + File.write(path, aws_config)
     114 + 
     115 + path = File.join(`echo $HOME`.strip, '/.aws/credentials')
     116 + dir = File.dirname(path)
     117 + FileUtils.mkdir_p(dir) unless Dir.exist?(dir)
     118 + 
     119 + aws_credentials = <<~HEREDOC
     120 + [default]
     121 + aws_access_key_id = #{providers_params[:infos][:access_key]}
     122 + aws_secret_access_key = #{providers_params[:infos][:secret_key]}
     123 + HEREDOC
     124 + 
     125 + File.write(path, aws_credentials)
     126 + 
     127 + check_config = `aws ec2 describe-instances`
     128 + valid = !check_config.empty?
     129 + else
     130 + valid = false
    103 131   end
    104 132   
    105 133   valid
    skipped 7 lines
    113 141   FileUtils.mkdir_p(dir) unless Dir.exist?(dir)
    114 142   
    115 143   ssh_key = Base64.decode64(provider.infos['ssh_key'])
    116  - return false unless ssh_key.match?(/-----BEGIN OPENSSH PRIVATE KEY-----.*-----END OPENSSH PRIVATE KEY-----/m)
     144 + return false unless ssh_key.match?(/-----BEGIN (OPENSSH|RSA) PRIVATE KEY-----.*-----END (OPENSSH|RSA) PRIVATE KEY-----/m)
    117 145   
    118 146   ssh_key += "\n" unless ssh_key.end_with?("\n")
    119 147   
    skipped 6 lines
  • ■ ■ ■ ■ ■ ■
    backend/app/controllers/application_controller.rb
    skipped 15 lines
    16 16   def server_delete(server, state)
    17 17   server.destroy
    18 18   server.scan.update(state: state)
    19  - return unless server.name.downcase.start_with?('scw-')
    20 19   
    21  - Thread.start { `scw instance server terminate #{server.uid} with-ip=true` }
     20 + if server.name.downcase.start_with?('scw-')
     21 + Thread.start { `scw instance server terminate #{server.uid} with-ip=true` }
     22 + elsif server.name.downcase.start_with?('aws-')
     23 + Thread.start { `aws ec2 terminate-instances --instance-ids #{server.uid}` }
     24 + end
    22 25   end
    23 26   
    24 27   def base64?(value)
    skipped 11 lines
  • ■ ■ ■ ■ ■ ■
    backend/app/controllers/scans_controller.rb
    skipped 82 lines
    83 83   
    84 84   scan_cmd[:cmd] += " --scan-id #{scan.id} --type-scan #{scan.type_scan} -d #{scan.domain}"
    85 85   
    86  - slack_webhook = Tool.find_by(name: 'slack')
     86 + slack_webhook = Tool.find_by(name: 'slack')&.infos
     87 + scan_cmd[:cmd] += " --slack #{slack_webhook['webhook']}"
    87 88   scan_cmd[:errors] = 'missing_webhook' if scan.notifs && slack_webhook.nil?
    88 89   
    89 90   scan_cmd = build_recon_scan_cmd(scan, scan_cmd) if scan.type_scan == 'recon'
    skipped 52 lines
    142 143   end
    143 144   
    144 145   def build_nuclei_scan_cmd(scan, scan_cmd)
    145  - scan_cmd[:errors] = 'missing_nuclei' unless File.exist?(File.join(scan_config_files, 'nuclei/config.yaml'))
    146  - 
    147 146   scan_cmd[:cmd] += " --nuclei #{scan.nuclei}"
    148 147   
    149 148   unless (scan.custom_templates && !scan.custom_templates.empty?) || scan.all_templates
    skipped 55 lines
    205 204   def launch_server(scan)
    206 205   server_infos = {}
    207 206   
    208  - unless scan.provider == 'scaleway'
     207 + unless scan.provider == 'scaleway' || scan.provider == 'aws'
    209 208   server_infos[:error] = 'unknown_provider'
    210 209   return server_infos
    211 210   end
    212 211   
    213  - # Force default value to DEV1-S
    214  - scan.update(instance_type: 'DEV1-S') unless scan[:instance_type]
    215  - cmd_output = launch_scaleway_server(scan)
     212 + cmd_output = if scan.provider == 'scaleway'
     213 + # Force default value to DEV1-S
     214 + scan.update(instance_type: 'DEV1-S') unless scan[:instance_type]
     215 + launch_scaleway_server(scan)
     216 + else
     217 + # Force default value to t2.small
     218 + scan.update(instance_type: 't2.small') unless scan[:instance_type]
     219 + launch_aws_server(scan)
     220 + end
    216 221   
    217 222   begin
    218 223   cmd_output_json = JSON.parse(cmd_output)
    skipped 4 lines
    223 228   
    224 229   scan.update(state: 'Deploy In Progress')
    225 230   
    226  - server_infos[:infos] = {
    227  - uid: cmd_output_json['id'],
    228  - name: cmd_output_json['name'],
    229  - ip: cmd_output_json['public_ip']['address'],
    230  - state: 'Launched',
    231  - scan_id: scan.id
    232  - }
     231 + case scan.provider
     232 + when 'scaleway'
     233 + server_infos[:infos] = {
     234 + uid: cmd_output_json['id'],
     235 + name: cmd_output_json['name'],
     236 + ip: cmd_output_json['public_ip']['address'],
     237 + state: 'Launched',
     238 + scan_id: scan.id
     239 + }
     240 + when 'aws'
     241 + server_infos[:infos] = {
     242 + uid: cmd_output_json['Instances'][0]['InstanceId'],
     243 + name: cmd_output_json['Instances'][0]['Tags'][0]['Value'],
     244 + state: 'Launched',
     245 + scan_id: scan.id
     246 + }
     247 + 
     248 + sleep 1
     249 + 
     250 + cmd_output = `aws ec2 describe-instances --instance-ids #{server_infos[:infos][:uid]}`
     251 + json_data = JSON.parse(cmd_output)
     252 + server_infos[:infos][:ip] = json_data['Reservations'][0]['Instances'][0]['PublicIpAddress']
     253 + end
    233 254   
    234 255   server_infos
    235 256   end
    skipped 7 lines
    243 264   Scope.find_by(scope: base_domain)&.update(last_scan: Time.now) unless scan.type_scan == 'nuclei'
    244 265   Thread.start do
    245 266   # Sleep until the server starts and install the necessary tools
    246  - sleep(360)
     267 + sleep(420)
    247 268   
    248 269   begin
    249 270   Net::SCP.start(server.ip, 'root', keys: "/root/.ssh/#{scan.provider}_id_rsa") do |scp|
    skipped 49 lines
    299 320   
    300 321   `scw instance server create type=#{scan.instance_type} image=ubuntu_jammy name=scw-hunt3r-#{random_name} cloud-init=@#{cloud_init_file} -o json`.strip
    301 322   end
     323 + 
     324 + def launch_aws_server(scan)
     325 + return unless scan.instance_type_valid?
     326 + 
     327 + `aws ec2 run-instances --image-id ami-0d75513e7706cf2d9 --count 1 --instance-type #{scan.instance_type} --key-name hunt3r --user-data file://#{cloud_init_file} --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=aws-#{random_name}}]'`
     328 + end
     329 + 
    302 330  end
    303 331   
  • ■ ■ ■ ■ ■
    backend/app/models/scan.rb
    skipped 22 lines
    23 23   "#{((running_time / 3600) * 0.0432).round(2)}€"
    24 24   when 'DEV1-XL'
    25 25   "#{((running_time / 3600) * 0.0648).round(2)}€"
     26 + when 't2.small'
     27 + "#{((running_time / 3600) * 0.022).round(2)}€"
     28 + when 't2.medium'
     29 + "#{((running_time / 3600) * 0.045).round(2)}€"
     30 + when 't2.large'
     31 + "#{((running_time / 3600) * 0.09).round(2)}€"
     32 + when 't2.xlarge'
     33 + "#{((running_time / 3600) * 0.18).round(2)}€"
    26 34   else
    27 35   0
    28 36   end
    skipped 4 lines
    33 41   'DEV1-S' => 1,
    34 42   'DEV1-M' => 2,
    35 43   'DEV1-L' => 3,
    36  - 'DEV1-XL' => 4
     44 + 'DEV1-XL' => 4,
     45 + 't2.small' => 1,
     46 + 't2.medium' => 2,
     47 + 't2.large' => 3,
     48 + 't2.xlarge' => 4
    37 49   }
    38 50   multiplicator[instance_type]
    39 51   end
    40 52   
    41 53   def instance_type_valid?
    42  - %w[DEV1-S DEV1-M DEV1-M DEV1-XL].include?(instance_type)
     54 + %w[DEV1-S DEV1-M DEV1-M DEV1-XL t2.small t2.medium t2.large t2.xlarge].include?(instance_type)
    43 55   end
    44 56  end
    45 57   
  • ■ ■ ■ ■ ■ ■
    backend/lib/platforms/hackerone.rb
    skipped 38 lines
    39 39   
    40 40   def self.parse_programs(programs, platform)
    41 41   programs.each do |program|
     42 + next unless program['attributes']['submission_state'] == 'open'
     43 + 
    42 44   slug = program['attributes']['handle']
    43 45   
    44 46   # In case it is not yet present in the database we add the program
    skipped 31 lines
    76 78   def self.parse_scopes(scopes, slug, platform)
    77 79   program = Program.find_by(slug: slug)
    78 80   scopes.each do |scope|
     81 + next unless scope['attributes']['eligible_for_submission']
     82 + 
    79 83   endpoint = scope['attributes']['asset_identifier']
    80 84   type = scope['attributes']['asset_type']
    81 85   next unless type == 'URL'
    skipped 68 lines
  • ■ ■ ■ ■ ■ ■
    backend/lib/platforms/intigriti.rb
    skipped 72 lines
    73 73   
    74 74   def self.parse_programs(programs, platform)
    75 75   programs.each do |program|
     76 + next if program['status'] == 4
     77 +
    76 78   # In case it is not yet present in the database we add the program
    77 79   if Program.find_by(slug: program['handle']).nil?
    78 80   vdp = !(program['maxBounty']['value']).positive?
    skipped 116 lines
  • ■ ■ ■ ■ ■ ■
    backend/storage/configs/cloud-init.yml
    skipped 8 lines
    9 9   - ruby-dev
    10 10   - make
    11 11   - gcc
     12 + - whois
    12 13   
    13 14  runcmd:
     15 + # Allow root connection on AWS
     16 + - sed -i 's/.*ssh-rsa/ssh-rsa/' /root/.ssh/authorized_keys
    14 17   # Amass
    15  - - wget https://github.com/OWASP/Amass/releases/download/v3.19.2/amass_linux_amd64.zip
     18 + - wget https://github.com/OWASP/Amass/releases/download/v3.19.3/amass_linux_amd64.zip
    16 19   - unzip amass_linux_amd64.zip
    17 20   - mv amass_linux_amd64/amass /usr/local/bin/
    18 21   - rm -r amass_linux_amd64 amass_linux_amd64.zip
    skipped 7 lines
    26 29   - mv findomain-linux /usr/local/bin/findomain
    27 30   - chmod +x /usr/local/bin/findomain
    28 31   # Nuclei
    29  - - wget https://github.com/projectdiscovery/nuclei/releases/download/v2.6.9/nuclei_2.6.9_linux_amd64.zip
    30  - - unzip nuclei_2.6.9_linux_amd64.zip
     32 + - wget https://github.com/projectdiscovery/nuclei/releases/download/v2.7.5/nuclei_2.7.5_linux_amd64.zip
     33 + - unzip nuclei_2.7.5_linux_amd64.zip
    31 34   - mv nuclei /usr/local/bin
    32  - - rm nuclei_2.6.9_linux_amd64.zip
     35 + - rm nuclei_2.7.5_linux_amd64.zip
    33 36   # Naabu
    34  - - wget https://github.com/projectdiscovery/naabu/releases/download/v2.0.7/naabu_2.0.7_linux_amd64.zip
    35  - - unzip naabu_2.0.7_linux_amd64.zip
     37 + - wget https://github.com/projectdiscovery/naabu/releases/download/v2.0.9/naabu_2.0.9_linux_amd64.zip
     38 + - unzip naabu_2.0.9_linux_amd64.zip
    36 39   - mv naabu /usr/local/bin/
    37  - - rm naabu_2.0.7_linux_amd64.zip
     40 + - rm naabu_2.0.9_linux_amd64.zip
    38 41   # HTTPX
    39  - - wget https://github.com/projectdiscovery/httpx/releases/download/v1.2.1/httpx_1.2.1_linux_amd64.zip
    40  - - unzip httpx_1.2.1_linux_amd64.zip
     42 + - wget https://github.com/projectdiscovery/httpx/releases/download/v1.2.2/httpx_1.2.2_linux_amd64.zip
     43 + - unzip httpx_1.2.2_linux_amd64.zip
    41 44   - mv httpx /usr/local/bin/
    42  - - rm LICENSE.md README.md httpx_1.2.1_linux_amd64.zip
     45 + - rm LICENSE.md README.md httpx_1.2.2_linux_amd64.zip
    43 46   # Subfinder
    44  - - wget https://github.com/projectdiscovery/subfinder/releases/download/v2.5.1/subfinder_2.5.1_linux_amd64.zip
    45  - - unzip subfinder_2.5.1_linux_amd64.zip
     47 + - wget https://github.com/projectdiscovery/subfinder/releases/download/v2.5.2/subfinder_2.5.2_linux_amd64.zip
     48 + - unzip subfinder_2.5.2_linux_amd64.zip
    46 49   - mv subfinder /usr/local/bin
    47  - - rm subfinder_2.5.1_linux_amd64.zip
     50 + - rm subfinder_2.5.2_linux_amd64.zip
    48 51   # GAU
    49  - - wget https://github.com/lc/gau/releases/download/v2.1.1/gau_2.1.1_linux_amd64.tar.gz
    50  - - tar -xzvf gau_2.1.1_linux_amd64.tar.gz
     52 + - wget https://github.com/lc/gau/releases/download/v2.1.2/gau_2.1.2_linux_amd64.tar.gz
     53 + - tar -xzvf gau_2.1.2_linux_amd64.tar.gz
    51 54   - mv gau /usr/local/bin/
    52  - - rm LICENSE README.md gau_2.1.1_linux_amd64.tar.gz
     55 + - rm LICENSE README.md gau_2.1.2_linux_amd64.tar.gz
    53 56   # GoWitness
    54  - - wget https://github.com/sensepost/gowitness/releases/download/2.3.6/gowitness-2.3.6-linux-amd64
    55  - - mv gowitness-2.3.6-linux-amd64 /usr/local/bin/gowitness
     57 + - wget https://github.com/sensepost/gowitness/releases/download/2.4.0/gowitness-2.4.0-linux-amd64
     58 + - mv gowitness-2.4.0-linux-amd64 /usr/local/bin/gowitness
    56 59   - chmod +x /usr/local/bin/gowitness
    57 60   - wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
    58 61   - apt install ./google-chrome-stable_current_amd64.deb -y
    skipped 2 lines
    61 64   - gem install typhoeus
    62 65   # Concurrent Ruby
    63 66   - gem install concurrent-ruby
     67 + # PublicSuffix
     68 + - gem install public_suffix
    64 69   # Wappalyzer
    65 70   - curl -sL https://deb.nodesource.com/setup_14.x | bash -
    66 71   - apt -y install nodejs
    skipped 10 lines
  • ■ ■ ■ ■ ■
    backend/storage/tools/libs/hunt3r_dashboard.rb
    skipped 27 lines
    28 28   end
    29 29   
    30 30   def self.delete_server
     31 + InteractDashboard.update_scan_status('Stopped')
    31 32   request = Typhoeus::Request.new(
    32 33   File.join(OPTIONS[:url], "/servers/#{OPTIONS[:srv_uid]}/outside?token=#{OPTIONS[:hunt3r_token]}"),
    33 34   method: :delete,
    skipped 76 lines
  • ■ ■ ■ ■ ■ ■
    backend/storage/tools/libs/nuclei_scan.rb
    1 1  class NucleiScan
    2 2   def self.start
    3 3   InteractDashboard.update_scan_status('Nuclei - Start')
     4 + Slack.notify(":new: Nuclei scan started for #{OPTIONS[:domain]}")
    4 5   FileUtils.mkdir_p(OPTIONS[:output])
    5 6   
    6 7   FileUtils.cp('/tmp/domains.txt', "#{OPTIONS[:output]}/domains.txt")
    7 8   
    8 9   Nuclei.check_domains('domains')
     10 + Slack.notify(":stopwatch: Nuclei scan finished for #{OPTIONS[:domain]}")
    9 11   end
    10 12  end
    11 13   
  • ■ ■ ■ ■ ■
    backend/storage/tools/libs/recon_scan.rb
    1 1  class ReconScan
    2 2   def self.start
    3 3   InteractDashboard.update_scan_status('Recon - Start')
     4 + Slack.notify(":new: Recon scan started for #{OPTIONS[:domain]}")
    4 5   
    5 6   if OPTIONS[:leak]
    6 7   InteractDashboard.update_scan_status('Recon - Get Leaks')
    skipped 9 lines
    16 17   
    17 18   if OPTIONS[:intel]
    18 19   InteractDashboard.update_scan_status('Recon - Intel')
    19  - Whoxy.get_domains
     20 + Amass.intel
     21 + Assetfinder.intel
     22 + Whoxy.intel
     23 + 
     24 + system("cat #{OPTIONS[:output]}/*_intel_valid.txt | sort -u > #{OPTIONS[:output]}/intel_domains.txt")
     25 + 
    20 26   C99.check_domains
    21 27   end
    22 28   
    skipped 18 lines
    41 47   Nuclei.check_domains
    42 48   end
    43 49   
    44  - return unless OPTIONS[:gau]
    45  - 
    46  - InteractDashboard.update_scan_status('Recon - GAU')
    47  - Gau.get_urls
     50 + if OPTIONS[:gau]
     51 + InteractDashboard.update_scan_status('Recon - GAU')
     52 + Gau.get_urls
     53 + end
    48 54   # **-- END OF THE ACTIVE CHECK PHASE
     55 + 
     56 + Slack.notify(build_end_message)
    49 57   end
    50 58  end
    51 59   
    52 60  private
     61 + 
     62 +def build_end_message
     63 + nb_domains = `wc -l #{OPTIONS[:output]}/all_domains.txt`.strip.split(' ')[0]
     64 + nb_domains_alive = `wc -l #{OPTIONS[:output]}/httpx.txt`.strip.split(' ')[0]
     65 + 
     66 + output = ":stopwatch: Recon scan finished for #{OPTIONS[:domain]} :"
     67 + output += "\n - Number of detected domains : #{nb_domains}"
     68 + output += "\n - Number of detected and accessible domains : #{nb_domains_alive}"
     69 + 
     70 + if OPTIONS[:nuclei]
     71 + nb_vulns = `wc -l #{OPTIONS[:output]}/nuclei.json`.strip.split(' ')[0]
     72 + output += "\n - Number of detected vulnerabilities : #{nb_vulns}"
     73 + end
     74 + 
     75 + output
     76 +end
    53 77   
    54 78  def clean_domains
    55 79   regex_string = OPTIONS[:excludes].split(',')
    skipped 22 lines
  • ■ ■ ■ ■ ■ ■
    backend/storage/tools/libs/tools/amass.rb
    skipped 18 lines
    19 19   
    20 20   system(cmd)
    21 21   end
     22 + 
     23 + def self.intel
     24 + cmd = "amass intel -whois -d #{OPTIONS[:domain]} -config #{config_path}"
     25 + cmd += " -o #{OPTIONS[:output]}/amass_intel.txt"
     26 + 
     27 + system(cmd)
     28 + 
     29 + Whois.check('amass')
     30 + end
    22 31  end
    23 32   
    24 33  private
    skipped 25 lines
  • ■ ■ ■ ■ ■ ■
    backend/storage/tools/libs/tools/assetfinder.rb
     1 +class Assetfinder
     2 + def self.intel
     3 + system("assetfinder #{OPTIONS[:domain]} | sort -u > #{OPTIONS[:output]}/assetfinder_intel.txt")
     4 + 
     5 + Whois.check('assetfinder')
     6 + end
     7 +end
     8 + 
  • ■ ■ ■ ■ ■ ■
    backend/storage/tools/libs/tools/c99.rb
    1 1  class C99
    2 2   def self.check_domains
    3  - return unless File.exist?("#{OPTIONS[:output]}/whoxy_domains.txt")
     3 + return unless File.exist?("#{OPTIONS[:output]}/intel_domains.txt")
    4 4   
    5  - domains = File.open("#{OPTIONS[:output]}/whoxy_domains.txt").read
     5 + domains = File.open("#{OPTIONS[:output]}/intel_domains.txt").read
    6 6   domains.each_line do |domain|
    7 7   domain.chomp!
    8 8   next if domain == OPTIONS[:domain]
    skipped 17 lines
  • ■ ■ ■ ■
    backend/storage/tools/libs/tools/gau.rb
    skipped 6 lines
    7 7   valid_urls = Set[]
    8 8   
    9 9   random = (0...8).map { rand(65..90).chr }.join
    10  - `gau --blacklist png,jpg,jpeg,gif,svg,js,css,ttf,woff,woff2 --o #{OPTIONS[:output]}/gau_#{random}.txt #{url}`
     10 + `gau --blacklist png,jpg,jpeg,gif,svg,js,css,ttf,woff,woff2,icon,tiff --o #{OPTIONS[:output]}/gau_#{random}.txt #{url}`
    11 11   
    12 12   gau_results = File.open("#{OPTIONS[:output]}/gau_#{random}.txt").read
    13 13   gau_results.each_line do |line|
    skipped 20 lines
  • ■ ■ ■ ■ ■ ■
    backend/storage/tools/libs/tools/httpx.rb
    skipped 4 lines
    5 5   file = File.read("#{OPTIONS[:output]}/naabu.json")
    6 6   data = JSON.parse(file)
    7 7   
    8  - pool = Concurrent::FixedThreadPool.new(8 * OPTIONS[:concurrency])
     8 + pool = Concurrent::FixedThreadPool.new(6 * OPTIONS[:concurrency])
    9 9   
    10 10   urls = []
    11 11   data.each do |host, infos|
    skipped 25 lines
    37 37   
    38 38   # Allows not to pollute the recon with useless domains
    39 39   # Ex http://www.domain.tld 302 to https://www.domain.tld
    40  - next if url.start_with?('http://') && result_json['location'].match?(%r{https://(www\.)?#{host}(:443)?/?})
     40 + next if url.start_with?('http://') && result_json['location']&.match?(%r{https://(www\.)?#{host}(:443)?/?})
    41 41   next if url.start_with?('https://') && url.end_with?(':80')
    42 42   next if url.start_with?('http://') && url.end_with?(':443')
    43 43   
    skipped 3 lines
    47 47   technologies = []
    48 48   
    49 49   begin
    50  - wappalyzer = JSON.load(`node /root/Tools/wappalyzer/src/drivers/npm/cli.js #{url}`)
    51  - wappalyzer['technologies'].each do |technology|
     50 + wappalyzer = JSON.load(`node /root/Tools/wappalyzer/src/drivers/npm/cli.js #{url} -w 10000`)
     51 + wappalyzer['technologies']&.each do |technology|
    52 52   technologies << technology['name']
    53 53   end
    54 54   rescue
    skipped 40 lines
  • ■ ■ ■ ■ ■
    backend/storage/tools/libs/tools/nuclei.rb
    skipped 11 lines
    12 12   
    13 13   cmd = "nuclei -l #{OPTIONS[:output]}/#{file}.txt -silent -t #{templates_path}"
    14 14   cmd += " -severity #{OPTIONS[:nuclei_severity]}" if OPTIONS[:nuclei_severity]
    15  - cmd += " -config /tmp/tools/nuclei/config.yaml"
     15 + cmd += ' -config /tmp/tools/nuclei/config.yaml' if File.file?('/tmp/tools/nuclei/config.yaml')
    16 16   
    17 17   if OPTIONS[:interactsh_url]
    18 18   cmd += " -iserver #{OPTIONS[:interactsh_url]}"
    skipped 21 lines
    40 40   
    41 41   next unless name && severity && matched_at
    42 42   
     43 + Slack.notify(":bug: New vuln : #{name} | #{severity} | #{matched_at}")
    43 44   InteractDashboard.send_vulnerability(name, severity, matched_at)
    44 45   end
    45 46  end
    skipped 25 lines
  • ■ ■ ■ ■ ■ ■
    backend/storage/tools/libs/tools/whois.rb
     1 +class Whois
     2 + def self.check(tool)
     3 + 
     4 + domains = File.read("#{OPTIONS[:output]}/#{tool}_intel.txt")
     5 + match = OPTIONS[:domain].split('.')[0]
     6 + 
     7 + valid_domains = []
     8 + domains.each_line do |domain|
     9 + domain.chomp!
     10 + 
     11 + root_domain = PublicSuffix.domain(domain)
     12 + next if root_domain.nil? || root_domain == OPTIONS[:domain]
     13 + 
     14 + if tool == 'whoxy' && root_domain.match?(/^#{match}\./)
     15 + valid_domains << domain
     16 + next
     17 + elsif root_domain.match?(/^#{match}\./)
     18 + # We can't keep this type of domain if the source is not reliable because it generates too much FP
     19 + next
     20 + end
     21 + next if valid_domains.include?(root_domain)
     22 + 
     23 + sleep 1.5 # Avoid WHOIS connection blocked | TODO : Use the Whois API to avoid sleep
     24 + whois = `whois #{root_domain} | grep -iF "#{match}"`
     25 + next if whois.nil? || whois.empty?
     26 + 
     27 + valid_domains << root_domain
     28 + end
     29 + 
     30 + File.write("/tmp/scan/results/#{tool}_intel_valid.txt", valid_domains.join("\n"), mode: 'a')
     31 + end
     32 +end
     33 + 
  • ■ ■ ■ ■ ■ ■
    backend/storage/tools/libs/tools/whoxy.rb
    1 1  class Whoxy
    2  - def self.get_domains
     2 + def self.intel
    3 3   response = Typhoeus::Request.get(
    4  - "http://api.whoxy.com/?key=#{OPTIONS[:whoxy_token]}&history=#{OPTIONS[:domain]}"
     4 + "https://api.whoxy.com/?key=#{OPTIONS[:whoxy_token]}&history=#{OPTIONS[:domain]}"
    5 5   )
    6 6   return unless response&.code == 200
    7 7   
    skipped 4 lines
    12 12   email = Set[]
    13 13   
    14 14   response_json['whois_records'].each do |result|
    15  - if result['registrant_contact']['company_name']&.match?(/#{OPTIONS[:domain].sub(/\..*/, '')}/i)
     15 + registrant_company = result['registrant_contact']['company_name']
     16 + if registrant_company&.match?(/#{OPTIONS[:domain].split('.')[0]}/i)
    16 17   company << result['registrant_contact']['company_name'].gsub(' ', '+')
    17 18   end
    18 19   
    19  - if result['registrant_contact']['email_address']&.match?(OPTIONS[:domain])
     20 + registrant_email = result['registrant_contact']['email_address']
     21 + if registrant_email&.include?('@') && !registrant_email&.include?('anonymised') && registrant_email&.match?(OPTIONS[:domain].split('.')[0])
    20 22   email << result['registrant_contact']['email_address']
    21 23   end
    22 24   end
    skipped 7 lines
    30 32  private
    31 33   
    32 34  def reverse(data, type)
    33  - subdomains = []
     35 + whois_domains = []
    34 36   
    35 37   data.each do |value|
    36  - next if value.end_with?(".#{OPTIONS[:domain]}")
     38 + get_whoxy_results(type, value, whois_domains)
     39 + end
     40 + 
     41 + File.open('whoxy_intel.txt', 'w+') do |f|
     42 + f.puts(whois_domains)
     43 + end
     44 + 
     45 + Whois.check('whoxy')
     46 +end
     47 + 
     48 +def get_whoxy_results(type, value, whois_domains, page=1)
     49 + response = Typhoeus::Request.get(
     50 + "https://api.whoxy.com/?key=#{OPTIONS[:whoxy_token]}&reverse=whois&#{type}=#{value}&page=#{page}"
     51 + )
     52 + return unless response&.code == 200
    37 53   
    38  - response = Typhoeus::Request.get(
    39  - "http://api.whoxy.com/?key=#{OPTIONS[:whoxy_token]}&reverse=whois&#{type}=#{value}"
    40  - )
    41  - next unless response&.code == 200
     54 + response_json = JSON.parse(response.body)
     55 + return unless response_json.key?('search_result')
    42 56   
    43  - response_json = JSON.parse(response.body)
    44  - next unless response_json.key?('search_result')
     57 + total_pages = response_json['total_pages']
    45 58   
    46  - response_json['search_result'].each do |result|
    47  - subdomains << result['domain_name']
    48  - end
    49  - end
     59 + response_json['search_result'].each do |result|
     60 + next if result['domain_name'] == OPTIONS[:domain]
     61 + next if whois_domains.include?(result['domain_name'])
    50 62   
    51  - File.open("#{OPTIONS[:output]}/whoxy_domains.txt", 'w+') do |f|
    52  - f.puts(subdomains)
     63 + whois_domains << result['domain_name']
    53 64   end
     65 + 
     66 + get_whoxy_results(type, value, whois_domains, page + 1) unless page == total_pages
    54 67  end
    55 68   
  • ■ ■ ■ ■ ■ ■
    backend/storage/tools/scan.rb
    skipped 3 lines
    4 4  require 'json'
    5 5  require 'base64'
    6 6  require 'concurrent'
     7 +require 'public_suffix'
    7 8   
    8 9  require_relative 'libs/hunt3r_dashboard'
    9 10  require_relative 'libs/slack'
    skipped 1 lines
    11 12  require_relative 'libs/nuclei_scan'
    12 13   
    13 14  require_relative 'libs/tools/amass'
     15 +require_relative 'libs/tools/assetfinder'
    14 16  require_relative 'libs/tools/c99'
    15 17  require_relative 'libs/tools/dehashed'
    16 18  require_relative 'libs/tools/gau'
    skipped 2 lines
    19 21  require_relative 'libs/tools/mesh'
    20 22  require_relative 'libs/tools/naabu'
    21 23  require_relative 'libs/tools/nuclei'
     24 +require_relative 'libs/tools/whois'
    22 25  require_relative 'libs/tools/whoxy'
    23 26   
    24 27  OPTIONS = {}
    skipped 134 lines
  • ■ ■ ■ ■ ■ ■
    docs/assets/files/nuclei_config.yml
     1 +# nuclei config file
     2 +# generated by https://github.com/projectdiscovery/goflags
     3 + 
     4 +# target urls/hosts to scan
     5 +#target: []
     6 + 
     7 +# path to file containing a list of target urls/hosts to scan (one per line)
     8 +#list:
     9 + 
     10 +# resume scan using resume.cfg (clustering will be disabled)
     11 +#resume: false
     12 + 
     13 +# template or template directory paths to include in the scan
     14 +#templates: []
     15 + 
     16 +# url containing list of templates to run
     17 +#template-url: []
     18 + 
     19 +# run only new templates added in latest nuclei-templates release
     20 +#new-templates: false
     21 + 
     22 +# workflow or workflow directory paths to include in the scan
     23 +#workflows: []
     24 + 
     25 +# url containing list of workflows to run
     26 +#workflow-url: []
     27 + 
     28 +# validate the passed templates to nuclei
     29 +#validate: false
     30 + 
     31 +# list all available templates
     32 +#tl: false
     33 + 
     34 +# allowed domain list to load remote templates from
     35 +#remote-template-domain: ["api.nuclei.sh"]
     36 + 
     37 +# execute a subset of templates that contain the provided tags
     38 +#tags: []
     39 + 
     40 +# tags from the default deny list that permit executing more intrusive templates
     41 +#include-tags: []
     42 + 
     43 +# exclude templates with the provided tags
     44 +exclude-tags: ['dos', 'dns', 'ssl', 'tech', 'token-spray', 'iot', 'token', 'network', 'android', 'metadata', 'wordpress', 'wp-plugin', 'misc']
     45 + 
     46 +# templates to be executed even if they are excluded either by default or configuration
     47 +#include-templates: []
     48 + 
     49 +# template or template directory paths to exclude
     50 +exclude-templates: [
     51 + misconfiguration/http-missing-security-headers.yaml,
     52 + misconfiguration/xss-deprecated-header.yaml,
     53 + misconfiguration/iis-internal-ip-disclosure.yaml,
     54 + misconfiguration/aspx-debug-mode.yaml,
     55 + misconfiguration/front-page-misconfig.yaml,
     56 + misconfiguration/unauthenticated-varnish-cache-purge.yaml,
     57 + miscellaneous/robots-txt-endpoint.yaml,
     58 + exposures/configs/keycloak-openid-config.yaml,
     59 + exposures/files/readme-md.yaml,
     60 + exposures/configs/azure-domain-tenant.yaml,
     61 + exposures/apis/drupal-jsonapi-user-listing.yaml,
     62 + exposed-panels/drupal-login.yaml,
     63 + vulnerabilities/generic/cors-misconfig.yaml,
     64 + vulnerabilities/generic/request-based-interaction.yaml,
     65 + vulnerabilities/generic/oob-header-based-interaction.yaml,
     66 + vulnerabilities/other/openvpn-hhi.yaml,
     67 + cves/2000/CVE-2000-0114.yaml,
     68 + exposed-panels/key-cloak-admin-panel.yaml
     69 +]
     70 + 
     71 +# templates to run based on severity. possible values: info, low, medium, high, critical
     72 +#severity: info,low,medium,high,critical
     73 + 
     74 +# templates to exclude based on severity. possible values: info, low, medium, high, critical
     75 +#exclude-severity:
     76 + 
     77 +# protocol types to be executed. possible values: dns, file, http, headless, network, workflow, ssl, websocket, whois
     78 +#type:
     79 + 
     80 +# protocol types to not be executed. possible values: dns, file, http, headless, network, workflow, ssl, websocket, whois
     81 +#exclude-type:
     82 + 
     83 +# execute templates that are (co-)created by the specified authors
     84 +#author: []
     85 + 
     86 +# list of template ids to run (comma-separated, file)
     87 +#template-id: []
     88 + 
     89 +# list of template ids to exclude (comma-separated, file)
     90 +#exclude-id: []
     91 + 
     92 +# output file to write found issues/vulnerabilities
     93 +#output:
     94 + 
     95 +# display findings only
     96 +# silent: true
     97 + 
     98 +# disable output content coloring (ansi escape codes)
     99 +#no-color: false
     100 + 
     101 +# write output in jsonl(ines) format
     102 +# json: true
     103 + 
     104 +# include request/response pairs in the jsonl output (for findings only)
     105 +#include-rr: false
     106 + 
     107 +# don't display match metadata
     108 +#no-meta: false
     109 + 
     110 +# don't display timestamp metadata in cli output
     111 +#no-timestamp: false
     112 + 
     113 +# local nuclei reporting database (always use this to persist report data)
     114 +#report-db:
     115 + 
     116 +# show optional match failure status
     117 +#matcher-status: false
     118 + 
     119 +# directory to export results in markdown format
     120 +#markdown-export:
     121 + 
     122 +# file to export results in sarif format
     123 +#sarif-export:
     124 + 
     125 +# path to the nuclei configuration file
     126 +#config:
     127 + 
     128 +# nuclei reporting module configuration file
     129 +#report-config:
     130 + 
     131 +# custom headers in header:value format
     132 +#header: []
     133 + 
     134 +# custom vars in var=value format
     135 +#var:
     136 + 
     137 +# file containing resolver list for nuclei
     138 +#resolvers:
     139 + 
     140 +# use system dns resolving as error fallback
     141 +#system-resolvers: false
     142 + 
     143 +# enable passive http response processing mode
     144 +#passive: false
     145 + 
     146 +# enable environment variables to be used in template
     147 +#env-vars: false
     148 + 
     149 +# client certificate file (pem-encoded) used for authenticating against scanned hosts
     150 +#client-cert:
     151 + 
     152 +# client key file (pem-encoded) used for authenticating against scanned hosts
     153 +#client-key:
     154 + 
     155 +# client certificate authority file (pem-encoded) used for authenticating against scanned hosts
     156 +#client-ca:
     157 + 
     158 +# use ztls library with autofallback to standard one for tls13
     159 +#ztls: false
     160 + 
     161 +# interactsh server url for self-hosted instance (default: oast.pro,oast.live,oast.site,oast.online,oast.fun,oast.me)
     162 +#interactsh-server:
     163 + 
     164 +# authentication token for self-hosted interactsh server
     165 +#interactsh-token:
     166 + 
     167 +# number of requests to keep in the interactions cache
     168 +#interactions-cache-size: 5000
     169 + 
     170 +# number of seconds to wait before evicting requests from cache
     171 +#interactions-eviction: 60
     172 + 
     173 +# number of seconds to wait before each interaction poll request
     174 +#interactions-poll-duration: 5
     175 + 
     176 +# extra time for interaction polling before exiting
     177 +#interactions-cooldown-period: 5
     178 + 
     179 +# disable interactsh server for oast testing, exclude oast based templates
     180 +#no-interactsh: false
     181 + 
     182 +# maximum number of requests to send per second
     183 +# rate-limit: 250
     184 + 
     185 +# maximum number of requests to send per minute
     186 +#rate-limit-minute: 0
     187 + 
     188 +# maximum number of hosts to be analyzed in parallel per template
     189 +#bulk-size: 25
     190 + 
     191 +# maximum number of templates to be executed in parallel
     192 +#concurrency: 20
     193 + 
     194 +# maximum number of headless hosts to be analyzed in parallel per template
     195 +#headless-bulk-size: 10
     196 + 
     197 +# maximum number of headless templates to be executed in parallel
     198 +#headless-concurrency: 10
     199 + 
     200 +# time to wait in seconds before timeout
     201 +#timeout: 5
     202 + 
     203 +# number of times to retry a failed request
     204 +#retries: 1
     205 + 
     206 +# leave default http/https ports (eg. host:80,host:443
     207 +#leave-default-ports: false
     208 + 
     209 +# max errors for a host before skipping from scan
     210 +#max-host-error: 30
     211 + 
     212 +# use a project folder to avoid sending same request multiple times
     213 +#project: false
     214 + 
     215 +# set a specific project path
     216 +#project-path: /tmp
     217 + 
     218 +# stop processing http requests after the first match (may break template/workflow logic)
     219 +#stop-at-first-path: false
     220 + 
     221 +# stream mode - start elaborating without sorting the input
     222 +#stream: false
     223 + 
     224 +# enable templates that require headless browser support (root user on linux will disable sandbox)
     225 +#headless: false
     226 + 
     227 +# seconds to wait for each page in headless mode
     228 +#page-timeout: 20
     229 + 
     230 +# show the browser on the screen when running templates with headless mode
     231 +#show-browser: false
     232 + 
     233 +# use local installed chrome browser instead of nuclei installed
     234 +#system-chrome: false
     235 + 
     236 +# show all requests and responses
     237 +#debug: false
     238 + 
     239 +# show all sent requests
     240 +#debug-req: false
     241 + 
     242 +# show all received responses
     243 +#debug-resp: false
     244 + 
     245 +# list of http(s)/socks5 proxy to use (comma separated or file input)
     246 +#proxy: []
     247 + 
     248 +# file to write sent requests trace log
     249 +#trace-log:
     250 + 
     251 +# file to write sent requests error log
     252 +#error-log:
     253 + 
     254 +# show nuclei version
     255 +#version: false
     256 + 
     257 +# show verbose output
     258 +#verbose: false
     259 + 
     260 +# display templates loaded for scan
     261 +#vv: false
     262 + 
     263 +# shows the version of the installed nuclei-templates
     264 +#templates-version: false
     265 + 
     266 +# update nuclei engine to the latest released version
     267 +#update: false
     268 + 
     269 +# update nuclei-templates to latest released version
     270 +#update-templates: false
     271 + 
     272 +# overwrite the default directory to install nuclei-templates
     273 +#update-directory: /root/nuclei-templates
     274 + 
     275 +# disable automatic nuclei/templates update check
     276 +#disable-update-check: false
     277 + 
     278 +# display statistics about the running scan
     279 +#stats: false
     280 + 
     281 +# write statistics data to an output file in jsonl(ines) format
     282 +#stats-json: false
     283 + 
     284 +# number of seconds to wait between showing a statistics update
     285 +#stats-interval: 5
     286 + 
     287 +# expose nuclei metrics on a port
     288 +#metrics: false
     289 + 
     290 +# port to expose nuclei metrics on
  • docs/assets/images/aws_inbound_rules.png
  • docs/assets/images/aws_new_user.png
  • docs/assets/images/aws_ssh_key.png
  • ■ ■ ■ ■ ■ ■
    docs/changelog.md
    1 1  # Changelog
    2 2   
     3 +## Version 1.5.0
     4 + 
     5 +**Frontend Improvements :**
     6 + 
     7 +- Improve Mobile Version
     8 +- Redirect to login when unauthorized
     9 +- Fix notifications box size
     10 +- Remove referer when clicking on a subdomain link
     11 +- Improve pagination
     12 +- Add multiples vulnerabilities deletion
     13 + 
     14 +**Backend Improvements :**
     15 + 
     16 +- Add AWS as cloud provider
     17 +- Improve Nuclei configuration managements
     18 +- Improve platforms sync
     19 + 
     20 +**Scan Improvements :**
     21 + 
     22 +- Tools update
     23 +- Add Slack notifications
     24 +- Add more exclusions to GAU
     25 +- Intel recon improvements
     26 + 
    3 27  ## Version 1.4.0
    4 28   
    5 29  **Scan Improvements :**
    skipped 48 lines
  • ■ ■ ■ ■ ■
    docs/getting_started/first_setup.md
    skipped 7 lines
    8 8   
    9 9  ## Configure a Cloud Provider
    10 10   
    11  -!!! warning "Cloud Provider Support"
    12  - 
    13  - Version 1.0 comes with Scaleway support only at the moment, other cloud providers will be added in the following versions with AWS first
    14  - 
    15 11  !!! info "SSH Key"
    16 12   
    17 13   An SSH key will be required by Hunt3r to deploy and manage your servers, however it is possible to configure a specific SSH key for Hunt3r and by provider
    skipped 9 lines
    27 23  As well as a Keys API for Hunt3r, still on the same page
    28 24   
    29 25  ![](../assets/images/Scaleway_API_Keys_Configuration.png)
     26 + 
     27 +### AWS configuration
     28 + 
     29 +You need to add a user [here](https://console.aws.amazon.com/iamv2/home#/users) with EC2 rights
     30 + 
     31 +![](../assets/images/aws_new_user.png)
     32 + 
     33 +You have to register your SSH key (without passphrase) [here](https://eu-west-1.console.aws.amazon.com/ec2/v2/home?region=eu-west-1#KeyPairs:) with the name 'hunt3r' (required), the key must be registered in the same region as the region used on the dashboard.
     34 + 
     35 +![](../assets/images/aws_ssh_key.png)
     36 + 
     37 +The default group security must be modified to allow SSH connections (Inbound rules) at least [here](https://eu-west-1.console.aws.amazon.com/ec2/v2/home?region=eu-west-1#SecurityGroups:)
     38 + 
     39 +![](../assets/images/aws_inbound_rules.png)
     40 + 
     41 +### Nuclei configuration
     42 + 
     43 +If you want to use Nuclei, we advise you to use a custom configuration file to add template exclusions on [/admin/tools/settings](http://0.0.0.0/admin/tools/). In case no file is filled in, all templates will be used
     44 + 
     45 +If necessary, you can use our [suggested configuration](https://docs.hunt3r.ovh/assets/files/nuclei_config.yml)
    30 46   
    31 47  ### Amass configuration
    32 48   
    skipped 8 lines
  • ■ ■ ■ ■
    frontend/src/app/UI/components/nb-sidebar-toggle/nb-sidebar-toggle.component.html
    skipped 16 lines
    17 17   <nb-actions size="small" >
    18 18   <nb-action class="user-action" >
    19 19   <nb-action icon="bell-outline" badgeDot="{{notif.length>1}}" disbled="true" nbContextMenuTag="notif-context-menu" [nbContextMenu]="notif" nbContextMenuTrigger="click" badgePosition="top right" badgeText="{{notif.length>1 ? (notif.length-1) : '' }}" badgeStatus="danger" size="large"></nb-action>
    20  - <nb-user [nbContextMenu]="userMenu" nbContextMenuTag="user-context-menu" name="{{user.user_email}}" >
     20 + <nb-user [nbContextMenu]="userMenu" id="sidebarre_username" nbContextMenuTag="user-context-menu" name="{{user.user_email}}" onlyPicture="{{this.screen > 960 ? false : true}}" >
    21 21   </nb-user>
    22 22   </nb-action>
    23 23   </nb-actions>
    skipped 12 lines
  • ■ ■ ■ ■ ■ ■
    frontend/src/app/UI/components/nb-sidebar-toggle/nb-sidebar-toggle.component.scss
    skipped 6 lines
    7 7  }
    8 8   
    9 9   
     10 +::ng-deep .menu-title{
     11 + flex: 1 0!important;
     12 +}
     13 + 
     14 + 
     15 + 
    10 16  @include nb-install-component() {
    11 17   display: flex;
    12 18   justify-content: space-between;
    skipped 55 lines
    68 74   text-decoration: none;
    69 75   }
    70 76   }
     77 + 
    71 78   
    72 79   
    73 80   @include media-breakpoint-down(sm) {
    skipped 16 lines
  • ■ ■ ■ ■ ■ ■
    frontend/src/app/UI/components/nb-sidebar-toggle/nb-sidebar-toggle.component.ts
    skipped 36 lines
    37 37   name: 'Dark',
    38 38   },
    39 39   ];
    40  - 
     40 + screen = 0
    41 41   currentTheme:any = 'default';
    42 42   backgroundColor ='black'
    43 43   
    skipped 24 lines
    68 68   this.router.navigateByUrl('/auth/login');
    69 69   }
    70 70   });
     71 + 
     72 + 
    71 73   }
    72 74   
    73 75   async getNotification(){
    skipped 1 lines
    75 77   
    76 78   if(result.data.length>0)this.notif=[{ "title": 'Delete all notifications',"icon":"trash-outline"}]
    77 79   result.data.forEach((element)=> {
    78  - let icon=''
    79  - if(element.message_type=='success') icon='checkmark-circle-outline'
    80  - if(element.message_type=='warning') icon='alert-circle-outline'
    81  - if(element.message_type=='danger') icon='close-circle-outline'
    82  - this.notif.push({"title":element.message,"icon":icon})
     80 + this.notif.push({"title":element.message,"badge":{dotMode: true, status: element.message_type}})
    83 81   })
    84 82   })
    85 83   }
    skipped 18 lines
    104 102  }
    105 103   
    106 104   async ngOnInit() {
     105 + this.screen = window.screen.width
     106 + if(this.screen < 960){
     107 + this.toggleLeft()
     108 + }
    107 109   await this.getNotification()
    108 110   this.nbMenuService.onItemClick()
    109 111   .pipe(
    skipped 28 lines
    138 140   .subscribe(themeName => this.currentTheme = themeName);
    139 141   }
    140 142   
    141  - toggleLeft(event:any) {
    142  - event.preventDefault()
     143 + toggleLeft(event:any="") {
     144 + if(event !=""){
     145 + event.preventDefault()
     146 + }
    143 147   this.sidebarService.toggle(true, 'left');
    144 148   return false
    145 149   }
    skipped 6 lines
  • ■ ■ ■ ■
    frontend/src/app/admin/bugbountySettings/bugbountySettings.component.html
    skipped 91 lines
    92 92   </div>
    93 93   </div>
    94 94   <div class="form-group row">
    95  - <label for="inputEmail1" class="label col-sm-3 col-form-label">Password</label>
     95 + <label for="inputEmail1" class="label col-sm-3 col-form-label">Api token</label>
    96 96   <div class="col-sm-9">
    97 97   <input class="col" nbInput type="password" name="password"formControlName="password" [value]="hackerone.password">
    98 98   </div>
    skipped 22 lines
  • ■ ■ ■ ■ ■
    frontend/src/app/admin/bugbountySettings/bugbountySettings.component.ts
    skipped 55 lines
    56 56   this.hackeroneForm = this.fbuilder.group({
    57 57   email:'',
    58 58   password:'',
     59 + otp:''
    59 60   });
    60 61   }
    61 62   
    skipped 36 lines
    98 99   event.preventDefault()
    99 100   let formName:'yeswehackForm'|'hackeroneForm'|'intigritiForm'=`${platform}Form`
    100 101   let data = this[formName].value
     102 + data.name=platform
     103 + console.log(data)
    101 104   if(data.otp == "" ) delete data.otp
    102  - data.name=platform
    103 105   let finalData = {"platform": data}
    104 106   if(this[platform].email!='' ){
    105 107   this.updatePlatform(finalData)
    skipped 38 lines
  • ■ ■ ■ ■ ■ ■
    frontend/src/app/admin/cloudSettings/cloudSettings.component.html
    skipped 54 lines
    55 55   <nb-tabset>
    56 56   <nb-tab tabTitle="Scaleway">
    57 57   <nb-form-field>
    58  - <form [formGroup]="scalewayForm" (ngSubmit)="updatescaleway($event)">
     58 + <form [formGroup]="scalewayForm" (ngSubmit)="updatecloud($event,'scaleway')">
    59 59   <div class="form-group row">
    60 60   <label for="inputEmail1" class="label col-sm-3 col-form-label">Access key</label>
    61 61   <div class="col-sm-9">
    skipped 43 lines
    105 105   <button type="submit" class="col" nbButton status="success">Update</button>
    106 106   </div>
    107 107   <div class="col end">
    108  - <button type="button" class="col " (click)="deletescaleway()" nbButton status="danger">Delete</button>
     108 + <button type="button" class="col " (click)="deletecloud('scaleway')" nbButton status="danger">Delete</button>
    109 109   </div>
    110 110   </div>
    111 111  
    skipped 2 lines
    114 114   </nb-tab>
    115 115   <nb-tab tabTitle="AWS">
    116 116   <nb-form-field>
    117  - <form [formGroup]="awsForm" (ngSubmit)="updateaws($event)">
     117 + <form [formGroup]="awsForm" (ngSubmit)="updatecloud($event,'aws')">
    118 118   <div class="form-group row">
    119 119   <label for="inputEmail1" class="label col-sm-3 col-form-label">Access key</label>
    120 120   <div class="col-sm-9">
    121  - <input class="col" nbInput type="text" name="access_key" [value]="aws.access_key" id="access_key">
     121 + <input class="col" nbInput type="text" name="access_key" [value]="aws.access_key" formControlName="access_key" id="access_key">
    122 122   </div>
    123 123   </div>
    124 124   <div class="form-group row">
    skipped 3 lines
    128 128   </div>
    129 129   </div>
    130 130   <div class="form-group row">
    131  - <label for="inputEmail1" class="label col-sm-3 col-form-label">Role</label>
    132  - <div class="col-sm-9">
    133  - <input class="col" nbInput type="text" name="organisation_id" id="organisation_id" [value]="aws.organization_id">
    134  - </div>
    135  - </div>
    136  - <div class="form-group row">
    137  - <label for="inputEmail1" class="label col-sm-3 col-form-label">Project ID</label>
     131 + <label for="inputEmail1" class="label col-sm-3 col-form-label">Region</label>
    138 132   <div class="col-sm-9">
    139  - <input class="col" nbInput type="text" name="created_at" id="created_at" [value]="aws.project_id">
    140  - </div>
    141  - </div>
    142  - <div class="form-group row">
    143  - <label for="inputEmail1" class="label col-sm-3 col-form-label">Creation date</label>
    144  - <div class="col-sm-9">
    145  - <input class="col" nbInput type="text" name="region" id="region" [value]="aws.region">
    146  - </div>
    147  - </div>
    148  - <div class="form-group row">
    149  - <label for="inputEmail1" class="label col-sm-3 col-form-label">Creation date</label>
    150  - <div class="col-sm-9">
    151  - <input class="col" nbInput type="text" name="zone" id="zone" [value]="aws.zone">
     133 + <input class="col" nbInput type="text" name="region" id="region" formControlName="region" [value]="aws.region">
    152 134   </div>
    153 135   </div>
    154 136   <div class="form-group row">
    155 137   <label for="inputEmail1" class="label col-sm-3 col-form-label">SSH key (private)</label>
    156 138   <div class="col-sm-9">
    157  - <textarea nbInput fullWidth formControlName="ssh_key" >{{scaleway.ssh_key}}</textarea>
     139 + <textarea nbInput fullWidth formControlName="ssh_key" >{{aws.ssh_key}}</textarea>
    158 140   </div>
    159 141   </div>
    160 142   <div class="form-group row">
    161 143   <div class="offset-sm-3 col-sm-9">
    162 144   <button type="submit" nbButton status="success">Update</button>
     145 + </div>
     146 + <div class="col end">
     147 + <button type="button" class="col " (click)="deletecloud('scaleway')" nbButton status="danger">Delete</button>
    163 148   </div>
    164 149   </div>
    165 150   </form>
    skipped 16 lines
  • ■ ■ ■ ■ ■ ■
    frontend/src/app/admin/cloudSettings/cloudSettings.component.ts
    skipped 28 lines
    29 29   awsExist = false;
    30 30   aws = {
    31 31   "access_key":"",
    32  - "secret_key":"",
    33  - "organization_id":"",
    34  - "project_id":"",
    35  - "region":"",
    36  - "zone":"",
    37  - "ssh_key": ""
     32 + "secret_key":"",
     33 + "region":"",
     34 + "ssh_key": ""
    38 35   }
    39 36   
    40 37   loading = true;
    skipped 42 lines
    83 80   })
    84 81   }
    85 82   
    86  - updatescaleway(event:any) {
     83 + updatecloud(event:any,type:'scaleway'|'aws') {
    87 84   event.preventDefault()
    88 85   this.loading = true;
    89  - let data = this.scalewayForm.value
     86 + let data = this[`${type}Form`].value
    90 87   data.ssh_key=btoa(data.ssh_key)
    91  - let finalData = {"provider": {"name":"scaleway","infos":data}}
     88 + let finalData = {"provider": {"name":type,"infos":data}}
    92 89   if(finalData.provider.infos.secret_key.charAt(1) == '*') delete finalData.provider.infos.secret_key
    93 90   let action:'create'|'update'='create'
    94  - if(this.scalewayExist) action='update'
     91 + if(this[`${type}Exist`]) action='update'
    95 92   Object.keys(finalData.provider.infos).forEach(key => {
    96 93   if (finalData.provider.infos[key] === '') {
    97 94   delete finalData.provider.infos[key];
    98 95   }
    99 96   });
    100  - this.cloudService[`${action}Scaleway`](finalData).subscribe( (result) => {
     97 + this.cloudService[`${action}Cloud`](finalData).subscribe( (result) => {
    101 98   this.loading = false;
    102 99   this.messageService.showToast(result.message,'success')
    103 100   this.getCloudProvider()
    skipped 3 lines
    107 104   })
    108 105   }
    109 106   
    110  - deletescaleway() {
     107 + deletecloud(type:'aws'|'scaleway') {
    111 108   this.loading = true;
    112  - this.cloudService.deleteScaleway().subscribe( (result) => {
    113  - this.messageService.showToast('Cloud provider scaleway has been deleted','success')
    114  - this.scalewayExist=false
     109 + this.cloudService.deleteCloud(type).subscribe( (result) => {
     110 + this.messageService.showToast(`Cloud provider ${type} has been deleted`,'success')
     111 + this[`${type}Exist`]=false
    115 112   this.loading = false;
    116 113   this.getCloudProvider()
    117 114   },(err) =>{
    skipped 11 lines
  • ■ ■ ■ ■ ■
    frontend/src/app/app.component.scss
    skipped 2 lines
    3 3  nb-sidebar-toggle {
    4 4   width: 100vw!important;
    5 5  }
     6 +html {
     7 + width: 100vw!important;
     8 +}
     9 + 
     10 + 
    6 11   
  • ■ ■ ■ ■ ■ ■
    frontend/src/app/core/cloudProvider/cloudProvider.service.ts
    skipped 7 lines
    8 8   
    9 9   constructor(private httpService:HttpService) {
    10 10   }
    11  - createScaleway(data:UpdateCloudProvider): Observable<UpdateProviderResponse> {
     11 + createCloud(data:UpdateCloudProvider): Observable<UpdateProviderResponse> {
    12 12   return this.httpService.post<UpdateProviderResponse>('/admin/providers',data)
    13 13   }
    14  - deleteScaleway(): Observable<DeleteProviderResponse> {
    15  - return this.httpService.delete<DeleteProviderResponse>('/admin/providers/scaleway')
     14 + deleteCloud(platform:string): Observable<DeleteProviderResponse> {
     15 + return this.httpService.delete<DeleteProviderResponse>('/admin/providers/'+platform)
    16 16   }
    17  - updateScaleway(data:UpdateCloudProvider): Observable<UpdateProviderResponse> {
     17 + updateCloud(data:UpdateCloudProvider): Observable<UpdateProviderResponse> {
    18 18   return this.httpService.patch<UpdateProviderResponse>('/admin/providers',data)
    19 19   }
     20 + 
    20 21   getCloudProvider(): Observable<DataCloudProvider> {
    21 22   return this.httpService.get<DataCloudProvider>('/admin/providers')
    22 23   }
    skipped 1 lines
  • ■ ■ ■ ■
    frontend/src/app/pages/dashboard/dashboard.component.html
    skipped 3 lines
    4 4   <nb-sidebar-toggle style="width:100vw"></nb-sidebar-toggle>
    5 5   </nb-layout-header>
    6 6   
    7  - <nb-sidebar left tag="left" state="expanded">
     7 + <nb-sidebar left tag="left" state="expanded" responsive>
    8 8   <nb-menu-services></nb-menu-services>
    9 9   </nb-sidebar>
    10 10   
    skipped 31 lines
  • ■ ■ ■ ■ ■ ■
    frontend/src/app/pages/domains/domains.component.html
    skipped 3 lines
    4 4   <nb-sidebar-toggle style="width:100vw"></nb-sidebar-toggle>
    5 5   </nb-layout-header>
    6 6   
    7  - <nb-sidebar left tag="left" state="expanded">
     7 + <nb-sidebar left tag="left" state="expanded" responsive>
    8 8   <nb-menu-services></nb-menu-services>
    9 9   </nb-sidebar>
    10 10   
    skipped 13 lines
    24 24   <div class="form-group col">
    25 25   <label for="inputEmail1" class="label col-sm-6 col-form-label">Technologie used</label>
    26 26   <div class="col-sm-9">
    27  - <input class="col" nbInput type="text" #technologieSearch>
     27 + <input class="col" nbInput type="text" #technologieSearch name="technologieSearch">
    28 28   </div>
    29 29   </div>
    30 30   <div class="form-group col">
    31 31   <label for="inputEmail1" class="label col-sm-6 col-form-label">URL</label>
    32 32   <div class="col-sm-9">
    33  - <input class="col" nbInput type="text" #urlSearch >
     33 + <input class="col" nbInput type="text" #urlSearch name="urlSearch">
    34 34   </div>
    35 35   </div>
    36 36   <div class="form-group col">
    37 37   <label for="inputEmail1" class="label col-sm-6 col-form-label">Status code</label>
    38 38   <div class="col-sm-9">
    39  - <input class="col" nbInput type="text" #statusCodeSearch>
     39 + <input class="col" nbInput type="text" #statusCodeSearch name="statusCodeSearch">
    40 40   </div>
    41 41   </div>
    42 42   <div class="form-group col">
    skipped 4 lines
    47 47   </div>
    48 48   </div>
    49 49   <div class="searchButton">
     50 + <button type="button" nbButton status="basic" (click)="technologieSearch.value='';urlSearch.value='';statusCodeSearch.value='';domainSearchInput.value='';searchDomainInit(technologieSearch.value,urlSearch.value,statusCodeSearch.value,domainSearchInput.value)">reset</button>
    50 51   <button type="button" nbButton status="success" (click)="searchDomainInit(technologieSearch.value,urlSearch.value,statusCodeSearch.value,domainSearchInput.value)"><nb-icon icon="search-outline" ></nb-icon></button>
    51 52   </div>
    52 53   </nb-card-body>
    53 54   </nb-card>
    54 55   
    55  - <div class="pagination col-md-4 offset-md-8">
     56 + <div class="col-md-4 offset-md-8">
    56 57   <nb-select placeholder="Select limit" [(selected)]="this.limit" (selectedChange)="changeLimit($event)">
    57 58   <nb-option value="10">10</nb-option>
    58 59   <nb-option value="50">50</nb-option>
    skipped 3 lines
    62 63   <button [disabled]="page==1" (click)="goToPage(page-1)" nbButton ghost status="basic">
    63 64   <nb-icon icon="arrow-left-outline"></nb-icon>
    64 65   </button>
     66 + <nb-select placeholder="Select page" (selectedChange)="goToPage($event)">
     67 + <nb-option *ngFor="let item of [].constructor(total_pages); let i = index" value="{{i+1}}">{{i+1}}</nb-option>
     68 + </nb-select>
    65 69   <button [disabled]="page==total_pages" nbButton ghost status="basic" (click)="goToPage(page+1)">
    66 70   <nb-icon icon="arrow-right-outline"></nb-icon>
    67 71   </button>
    68  - <div class="page">
    69  - page {{page}} of {{total_pages}} pages
    70  - </div>
    71 72   </div>
    72 73   <table >
    73 74   <tr>
    skipped 18 lines
    92 93   </td>
    93 94   </tr>
    94 95   </table>
    95  - <div class="pagination col-md-4 offset-md-8">
    96  - <nb-select placeholder="Select limit" [(selected)]="this.limit" (selectedChange)="changeLimit($event)">
    97  - <nb-option value="10">10</nb-option>
    98  - <nb-option value="50">50</nb-option>
    99  - <nb-option value="100">100</nb-option>
    100  - <nb-option value="-1">All</nb-option>
    101  - </nb-select>
     96 + <div class="pagination col-md-1 offset-md-11">
    102 97   <button [disabled]="page==1" (click)="goToPage(page-1)" nbButton ghost status="basic">
    103 98   <nb-icon icon="arrow-left-outline"></nb-icon>
    104 99   </button>
    105 100   <button [disabled]="page==total_pages" nbButton ghost status="basic" (click)="goToPage(page+1)">
    106 101   <nb-icon icon="arrow-right-outline"></nb-icon>
    107 102   </button>
    108  - <div class="page">
    109  - page {{page}} of {{total_pages}} pages
    110  - </div>
    111  - </div>
    112  - 
     103 + </div>
     104 + <br>
     105 + <div class="page">
     106 + page {{page}} of {{total_pages}} pages
     107 + </div>
    113 108   </nb-card-body>
    114 109   
    115 110   <ng-template #dialogConfirm let-data let-ref="dialogRef">
    skipped 23 lines
  • ■ ■ ■ ■ ■ ■
    frontend/src/app/pages/domains/domains.component.scss
    skipped 69 lines
    70 70   border-top-right-radius: 0px;
    71 71   border-bottom-left-radius: 0px;
    72 72  }
     73 +.searchButton button:first-child {
     74 + border-bottom-right-radius: 0px;
     75 +}
     76 +.searchButton button:last-child {
     77 + border-top-left-radius: 0px;
     78 +}
    73 79   
    74 80  .page{
    75 81   text-align: end;
    skipped 5 lines
  • ■ ■ ■ ■ ■
    frontend/src/app/pages/domains/domains.component.ts
    skipped 74 lines
    75 75   this.getDomains()
    76 76   }
    77 77   
    78  - 
    79 78   deleteDomain(id:string){
    80 79   this.confirmDialogModal.close()
    81 80   this.loadingDomain=true
    skipped 18 lines
  • ■ ■ ■ ■ ■ ■
    frontend/src/app/pages/engines/engines.component.html
    skipped 3 lines
    4 4   <nb-sidebar-toggle style="width:100vw"></nb-sidebar-toggle>
    5 5   </nb-layout-header>
    6 6   
    7  - <nb-sidebar left tag="left" state="expanded">
     7 + <nb-sidebar left tag="left" state="expanded" responsive>
    8 8   <nb-menu-services></nb-menu-services>
    9 9   </nb-sidebar>
    10 10   
    skipped 84 lines
    95 95   <div class="col-sm-8">
    96 96   <nb-select placeholder="Select provider" [selected]="modelEngine.infos.provider" (selectedChange)="toggle($event,'provider')">
    97 97   <nb-option value="scaleway">Scaleway</nb-option>
     98 + <nb-option value="aws">Aws</nb-option>
    98 99   </nb-select>
    99 100   </div>
    100 101   </div>
    101 102   <div class="form-group ">
    102 103   <label for="inputEmail1" class="label col-sm-4 col-form-label">Instance type</label>
    103 104   <div class="col-sm-8">
    104  - <nb-select placeholder="Select server type" [selected]="modelEngine.infos.instance_type" (selectedChange)="toggle($event,'instance_type')">
    105  - <nb-option value="DEV1-S">DEV1_S: 2vCPUs 2GB RAM 0.01/hour</nb-option>
    106  - <nb-option value="DEV1-M">DEV1_M: 3vCPUs 4GB RAM 0.02/hour</nb-option>
    107  - <nb-option value="DEV1-L">DEV1_L: 4vCPUs 8GB RAM 0.04/hour</nb-option>
    108  - <nb-option value="DEV1-XL">DEV1_XL: 4vCPUs 12GB RAM 0.06/hour</nb-option>
     105 + <nb-select placeholder="Select server type" [selected]="modelEngine.infos.instance_type" (selectedChange)="toggle($event,'instance_type')" >
     106 + <nb-option *ngFor="let intance of this.currentInstance | keyvalue" value="{{intance.key}}">{{intance.value}}</nb-option>
    109 107   </nb-select>
    110 108   </div>
    111 109   </div>
    skipped 99 lines
  • ■ ■ ■ ■ ■
    frontend/src/app/pages/engines/engines.component.ts
    skipped 26 lines
    27 27   templatList:string[]=<any>[]
    28 28   modelEngine:Engine=<Engine>{}
    29 29   
     30 + scalewayInstance:any={
     31 + "DEV1-S":"DEV1_S: 2vCPUs 2GB RAM 0.01/hour",
     32 + "DEV1-M":"DEV1_M: 3vCPUs 4GB RAM 0.02/hour",
     33 + "DEV1-L":"DEV1_L: 4vCPUs 8GB RAM 0.04/hour",
     34 + "DEV1-XL":"DEV1_XL: 4vCPUs 12GB RAM 0.06/hour"
     35 + }
    30 36   
     37 + awsInstance:any={
     38 + "t2.small" :"t2.small: 1CPU 2GB/RAM 12 Credit/H",
     39 + "t2.medium" :"t2.medium: 2CPU 4GB/RAM 24 Credit/H",
     40 + "t2.large" :"t2.large: 2CPU 8GB/RAM 36 Credit/H",
     41 + "t2.xlarge" :"t2.xlarge: 4CPU 16GB/RAM 6 Credit/H"
     42 + }
     43 + 
     44 + 
     45 + currentInstance:any={"":""}
    31 46   constructor(private enginesService : EnginesService,
    32 47   private messageService: MessageService,
    33 48   private fbuilder: FormBuilder,
    skipped 91 lines
    125 140   this.engineModal.close()
    126 141   }
    127 142   toggle(checked: any,name:string) {
    128  - 
    129 143   this.addEngineForm.get(name)!.setValue(checked)
    130  - console.log(this.addEngineForm.value)
     144 + if(name=='provider'){
     145 + let cloudProvider:'aws'|'scaleway'= this.addEngineForm.get(name)!.value
     146 + this.addEngineForm.get('instance_type')!.setValue('')
     147 + this.currentInstance=this[`${cloudProvider}Instance`]
     148 + }
    131 149   }
    132 150   
    133 151   addEngine(event:any,name:string){
    skipped 50 lines
  • ■ ■ ■ ■ ■ ■
    frontend/src/app/pages/leaks/leaks.component.html
    skipped 3 lines
    4 4   <nb-sidebar-toggle style="width:100vw"></nb-sidebar-toggle>
    5 5   </nb-layout-header>
    6 6   
    7  - <nb-sidebar left tag="left" state="expanded">
     7 + <nb-sidebar left tag="left" state="expanded" responsive>
    8 8   <nb-menu-services></nb-menu-services>
    9 9   </nb-sidebar>
    10 10   
    skipped 18 lines
    29 29   </div>
    30 30   </div>
    31 31   <div class="searchButton">
     32 + <button type="button" nbButton status="basic" (click)="searchText.value='';getLeaks(searchText.value)">reset</button>
    32 33   <button type="button" nbButton status="success" (click)="getLeaks(searchText.value)" ><nb-icon icon="search-outline" ></nb-icon></button>
    33 34   </div>
    34 35   </nb-card-body>
    35 36   </nb-card>
    36  -
    37  - 
    38  - <div class="pagination col-md-4 offset-md-8">
     37 + <div class="col-md-4 offset-md-8">
    39 38   <nb-select placeholder="Select limit" [(selected)]="this.limit" (selectedChange)="changeLimit($event)">
    40 39   <nb-option value="10">10</nb-option>
    41 40   <nb-option value="50">50</nb-option>
    skipped 3 lines
    45 44   <button [disabled]="page==1" (click)="goToPage(page-1)" nbButton ghost status="basic">
    46 45   <nb-icon icon="arrow-left-outline"></nb-icon>
    47 46   </button>
     47 + <nb-select placeholder="Select page" (selectedChange)="goToPage($event)">
     48 + <nb-option *ngFor="let item of [].constructor(total_pages); let i = index" value="{{i+1}}">{{i+1}}</nb-option>
     49 + </nb-select>
    48 50   <button [disabled]="page==total_pages" nbButton ghost status="basic" (click)="goToPage(page+1)">
    49 51   <nb-icon icon="arrow-right-outline"></nb-icon>
    50 52   </button>
    51  - <div class="page">
    52  - page {{page}} of {{total_pages}} pages
    53  - </div>
    54 53   </div>
    55 54   
    56 55   <table >
    skipped 10 lines
    67 66   </tr>
    68 67  
    69 68   </table>
    70  - <div class="pagination col-md-4 offset-md-8">
    71  - <nb-select placeholder="Select limit" [(selected)]="this.limit" (selectedChange)="changeLimit($event)">
    72  - <nb-option value="10">10</nb-option>
    73  - <nb-option value="50">50</nb-option>
    74  - <nb-option value="100">100</nb-option>
    75  - <nb-option value="-1">All</nb-option>
    76  - </nb-select>
     69 + <div class="pagination col-md-1 offset-md-11">
    77 70   <button [disabled]="page==1" (click)="goToPage(page-1)" nbButton ghost status="basic">
    78 71   <nb-icon icon="arrow-left-outline"></nb-icon>
    79 72   </button>
    80 73   <button [disabled]="page==total_pages" nbButton ghost status="basic" (click)="goToPage(page+1)">
    81 74   <nb-icon icon="arrow-right-outline"></nb-icon>
    82 75   </button>
    83  - <div class="page">
    84  - page {{page}} of {{total_pages}} pages
    85  - </div>
    86  - </div>
     76 + </div>
     77 + <br>
     78 + <div class="page">
     79 + page {{page}} of {{total_pages}} pages
     80 + </div>
    87 81   </nb-card-body>
    88 82   </nb-card>
    89 83   </nb-layout-column>
    skipped 4 lines
  • ■ ■ ■ ■ ■ ■
    frontend/src/app/pages/leaks/leaks.component.scss
    skipped 63 lines
    64 64   border-top-right-radius: 0px;
    65 65   border-bottom-left-radius: 0px;
    66 66  }
     67 +.searchButton button:first-child {
     68 + border-bottom-right-radius: 0px;
     69 +}
     70 +.searchButton button:last-child {
     71 + border-top-left-radius: 0px;
     72 +}
    67 73  .page{
    68 74   text-align: end;
    69 75   padding:10px
    skipped 4 lines
  • ■ ■ ■ ■
    frontend/src/app/pages/nuclei/nuclei.component.html
    skipped 3 lines
    4 4   <nb-sidebar-toggle style="width:100vw"></nb-sidebar-toggle>
    5 5   </nb-layout-header>
    6 6   
    7  - <nb-sidebar left tag="left" state="expanded">
     7 + <nb-sidebar left tag="left" state="expanded" responsive>
    8 8   <nb-menu-services></nb-menu-services>
    9 9   </nb-sidebar>
    10 10   
    skipped 76 lines
  • ■ ■ ■ ■ ■ ■
    frontend/src/app/pages/programs/programs.component.html
    skipped 3 lines
    4 4   <nb-sidebar-toggle style="width:100vw"></nb-sidebar-toggle>
    5 5   </nb-layout-header>
    6 6   
    7  - <nb-sidebar left tag="left" state="expanded">
     7 + <nb-sidebar left tag="left" state="expanded" responsive>
    8 8   <nb-menu-services></nb-menu-services>
    9 9   </nb-sidebar>
    10 10   
    skipped 11 lines
    22 22   <nb-card-body>
    23 23  
    24 24   <br><br>
    25  - <input nbInput type="text" #searchText>
    26  - <nb-select placeholder="Select platform" [(selected)]="selectedPlateform">
    27  - <nb-option selected value="all">All</nb-option>
    28  - <nb-option value="intigriti">Intigriti</nb-option>
    29  - <nb-option value="yeswehack">YesWeHack</nb-option>
    30  - <nb-option value="hackerone">HackerOne</nb-option>
    31  - </nb-select>
    32  - <button type="button" class="col" (click)="getProgram(searchText.value,selectedPlateform)" nbButton status="success"><nb-icon icon="search-outline"></nb-icon></button>
    33  - 
     25 + <div class="btnGrp">
     26 + <input nbInput type="text" #searchText>
     27 + <nb-select placeholder="Select platform" [(selected)]="selectedPlateform">
     28 + <nb-option selected value="all">All</nb-option>
     29 + <nb-option value="intigriti">Intigriti</nb-option>
     30 + <nb-option value="yeswehack">YesWeHack</nb-option>
     31 + <nb-option value="hackerone">HackerOne</nb-option>
     32 + </nb-select>
     33 + <button type="button" class="col" (click)="getProgram(searchText.value,selectedPlateform)" nbButton status="success"><nb-icon icon="search-outline"></nb-icon></button>
     34 + </div>
    34 35   <table >
    35 36   <tr>
    36 37   <th>Id</th>
    skipped 147 lines
  • ■ ■ ■ ■ ■ ■
    frontend/src/app/pages/programs/programs.component.scss
    skipped 54 lines
    55 55  
    56 56   }
    57 57  }
     58 +::ng-deep .btnGrp .select-button {
     59 + border-radius: 0px!important;
     60 +}
     61 +::ng-deep .btnGrp input:first-child{
     62 + border-bottom-right-radius: 0px;
     63 + border-top-right-radius: 0px;
     64 +}
     65 +.btnGrp button:last-child{
     66 + border-bottom-left-radius: 0px!important;
     67 + border-top-left-radius: 0px!important;
     68 + padding-bottom: calc( (100% - 20px) /2);
     69 + padding-top: calc( (100% - 20px) /2);
     70 + margin-top:-3px
     71 +}
  • ■ ■ ■ ■
    frontend/src/app/pages/scans/scans.component.html
    skipped 3 lines
    4 4   <nb-sidebar-toggle style="width:100vw"></nb-sidebar-toggle>
    5 5   </nb-layout-header>
    6 6   
    7  - <nb-sidebar left tag="left" state="expanded">
     7 + <nb-sidebar left tag="left" state="expanded" responsive>
    8 8   <nb-menu-services></nb-menu-services>
    9 9   </nb-sidebar>
    10 10   
    skipped 78 lines
  • ■ ■ ■ ■
    frontend/src/app/pages/servers/servers.component.html
    skipped 3 lines
    4 4   <nb-sidebar-toggle style="width:100vw"></nb-sidebar-toggle>
    5 5   </nb-layout-header>
    6 6   
    7  - <nb-sidebar left tag="left" state="expanded">
     7 + <nb-sidebar left tag="left" state="expanded" responsive>
    8 8   <nb-menu-services></nb-menu-services>
    9 9   </nb-sidebar>
    10 10   
    skipped 51 lines
  • ■ ■ ■ ■ ■ ■
    frontend/src/app/pages/subdomains/subdomains.component.html
    skipped 3 lines
    4 4   <nb-sidebar-toggle style="width:100vw"></nb-sidebar-toggle>
    5 5   </nb-layout-header>
    6 6   
    7  - <nb-sidebar left tag="left" state="expanded">
     7 + <nb-sidebar left tag="left" state="expanded" responsive>
    8 8   <nb-menu-services></nb-menu-services>
    9 9   </nb-sidebar>
    10 10   
    skipped 34 lines
    45 45   </div>
    46 46   </nb-card-body>
    47 47   </nb-card>
    48  - 
    49  -
    50  - <div class="pagination col-md-4 offset-md-8">
    51  - <nb-select placeholder="Select limit" [(selected)]="this.limit" (selectedChange)="changeLimit($event)">
    52  - <nb-option value="10">10</nb-option>
    53  - <nb-option value="50">50</nb-option>
    54  - <nb-option value="100">100</nb-option>
    55  - <nb-option value="-1">All</nb-option>
    56  - </nb-select>
    57  - <button [disabled]="page==1" (click)="goToPage(page-1)" nbButton ghost status="basic">
    58  - <nb-icon icon="arrow-left-outline"></nb-icon>
    59  - </button>
    60  - <button [disabled]="page==total_pages" nbButton ghost status="basic" (click)="goToPage(page+1)">
    61  - <nb-icon icon="arrow-right-outline"></nb-icon>
    62  - </button>
    63  - <div class="page">
    64  - page {{page}} of {{total_pages}} pages
    65  - </div>
    66  - </div>
    67  -
    68  -
    69  - 
     48 + <div class="col-md-4 offset-md-8">
     49 + <nb-select placeholder="Select limit" [(selected)]="this.limit" (selectedChange)="changeLimit($event)">
     50 + <nb-option value="10">10</nb-option>
     51 + <nb-option value="50">50</nb-option>
     52 + <nb-option value="100">100</nb-option>
     53 + <nb-option value="-1">All</nb-option>
     54 + </nb-select>
     55 + <button [disabled]="page==1" (click)="goToPage(page-1)" nbButton ghost status="basic">
     56 + <nb-icon icon="arrow-left-outline"></nb-icon>
     57 + </button>
     58 + <nb-select placeholder="Select page" (selectedChange)="goToPage($event)">
     59 + <nb-option *ngFor="let item of [].constructor(total_pages); let i = index" value="{{i+1}}">{{i+1}}</nb-option>
     60 + </nb-select>
     61 + <button [disabled]="page==total_pages" nbButton ghost status="basic" (click)="goToPage(page+1)">
     62 + <nb-icon icon="arrow-right-outline"></nb-icon>
     63 + </button>
     64 + </div>
    70 65   <table class="subdomainTable">
    71 66   <tr>
    72  - <th>ID</th>
     67 + <!--<th>ID</th>-->
    73 68   <th>URL</th>
    74 69   <th>IP</th>
    75 70   <th>Ports</th>
    skipped 5 lines
    81 76  
    82 77   </tr>
    83 78   <tr *ngFor="let item of this.subdomainsList">
    84  - <td>{{ item.id }}</td>
     79 + <!-- <td>{{ item.id }}</td>-->
    85 80   <td>
    86  - <a href="{{ item.url }}" target="_blank">{{ item.url }}</a>
     81 + <a href="{{ item.url }}" rel="noreferrer" target="_blank">{{ item.url }}</a>
    87 82   <br *ngIf="item.infos.title">
    88 83   <div class="badgeSubDiv">
    89 84   <nb-badge *ngIf="item.infos.title" class="badgeSub breakSentance" text="Title: {{item.infos.title}}" status="info" ></nb-badge>
    skipped 46 lines
    136 131   <td><img (click)="screenModal(apiUrl+'/screenshots/'+item.id)" class="screenpreview" id='screen{{item.id}}' appLazyLoad [src]="item.id.toString()" loading="lazy"></td>
    137 132   </tr>
    138 133   </table>
    139  - <div class="pagination col-md-4 offset-md-8">
    140  - <nb-select placeholder="Select limit" [(selected)]="this.limit" (selectedChange)="changeLimit($event)">
    141  - <nb-option value="10">10</nb-option>
    142  - <nb-option value="50">50</nb-option>
    143  - <nb-option value="100">100</nb-option>
    144  - <nb-option value="-1">All</nb-option>
    145  - </nb-select>
     134 + <div class="pagination col-md-1 offset-md-11">
    146 135   <button [disabled]="page==1" (click)="goToPage(page-1)" nbButton ghost status="basic">
    147 136   <nb-icon icon="arrow-left-outline"></nb-icon>
    148 137   </button>
    149 138   <button [disabled]="page==total_pages" nbButton ghost status="basic" (click)="goToPage(page+1)">
    150 139   <nb-icon icon="arrow-right-outline"></nb-icon>
    151  - </button><br>
    152  - <div class="page">
    153  - page {{page}} of {{total_pages}} pages
    154  - </div>
    155  - </div>
     140 + </button>
     141 + </div>
     142 + <br>
     143 + <div class="page">
     144 + page {{page}} of {{total_pages}} pages
     145 + </div>
    156 146   
    157 147   </nb-card-body>
    158 148   
    skipped 20 lines
  • ■ ■ ■ ■
    frontend/src/app/pages/urls/urls.component.html
    skipped 3 lines
    4 4   <nb-sidebar-toggle style="width:100vw"></nb-sidebar-toggle>
    5 5   </nb-layout-header>
    6 6   
    7  - <nb-sidebar left tag="left" state="expanded">
     7 + <nb-sidebar left tag="left" state="expanded" responsive>
    8 8   <nb-menu-services></nb-menu-services>
    9 9   </nb-sidebar>
    10 10   
    skipped 88 lines
  • ■ ■ ■ ■
    frontend/src/app/pages/user/user.component.html
    skipped 3 lines
    4 4   <nb-sidebar-toggle style="width:100vw"></nb-sidebar-toggle>
    5 5   </nb-layout-header>
    6 6   
    7  - <nb-sidebar left tag="left" state="expanded">
     7 + <nb-sidebar left tag="left" state="expanded" responsive>
    8 8   <nb-menu-services></nb-menu-services>
    9 9   </nb-sidebar>
    10 10   
    skipped 42 lines
  • ■ ■ ■ ■ ■ ■
    frontend/src/app/pages/vulnerabilities/vulnerabilities.component.html
    skipped 3 lines
    4 4   <nb-sidebar-toggle style="width:100vw"></nb-sidebar-toggle>
    5 5   </nb-layout-header>
    6 6   
    7  - <nb-sidebar left tag="left" state="expanded">
     7 + <nb-sidebar left tag="left" state="expanded" responsive>
    8 8   <nb-menu-services></nb-menu-services>
    9 9   </nb-sidebar>
    10 10   
    skipped 26 lines
    37 37   </div>
    38 38   </div>
    39 39   <div class="searchButton">
     40 + <button type="button" nbButton status="basic" (click)="this.criticity='';getVulnerabilities()">reset</button>
    40 41   <button type="button" nbButton status="success" (click)="getVulnerabilities()"><nb-icon icon="search-outline" ></nb-icon></button>
    41 42   </div>
    42 43   </nb-card-body>
    43 44   </nb-card>
    44 45   <br>
    45 46   
    46  - <div class="pagination col-md-4 offset-md-8">
     47 + <div class="col-md-4 offset-md-8">
    47 48   <nb-select placeholder="Select limit" [(selected)]="this.limit" (selectedChange)="changeLimit($event)">
    48 49   <nb-option value="10">10</nb-option>
    49 50   <nb-option value="50">50</nb-option>
    skipped 3 lines
    53 54   <button [disabled]="page==1" (click)="goToPage(page-1)" nbButton ghost status="basic">
    54 55   <nb-icon icon="arrow-left-outline"></nb-icon>
    55 56   </button>
     57 + <nb-select placeholder="Select page" (selectedChange)="goToPage($event)">
     58 + <nb-option *ngFor="let item of [].constructor(total_pages); let i = index" value="{{i+1}}">{{i+1}}</nb-option>
     59 + </nb-select>
    56 60   <button [disabled]="page==total_pages" nbButton ghost status="basic" (click)="goToPage(page+1)">
    57 61   <nb-icon icon="arrow-right-outline"></nb-icon>
    58 62   </button>
    59  - <div class="page">
    60  - page {{page}} of {{total_pages}} pages
    61  - </div>
    62 63   </div>
    63 64   
    64 65   <table >
    65 66   <tr>
     67 + <th><nb-checkbox checked="{{checkedAll}}" (checkedChange)="selectAll($event)"></nb-checkbox></th>
    66 68   <th>Name</th>
    67 69   <th>Severity</th>
    68 70   <th>Domain</th>
    69 71   <th>Creation date</th>
    70  - <th>Actions</th>
    71 72   </tr>
    72 73   <tr *ngFor="let item of this.vulnerabilitiesList">
     74 + <td><nb-checkbox class="vulnSelect" checked="{{checkedAll}}" (checkedChange)="selectOne($event,item.id)"></nb-checkbox></td>
    73 75   <td>{{ item.name }}</td>
    74 76   <td><nb-badge class="badgeSub" text="{{item.severity}}" status="{{item.severity=='critical'? 'danger' : item.severity=='high'? 'warning':item.severity=='medium'? 'primary':item.severity=='low'? 'info':'basic' }}" ></nb-badge></td>
    75 77   <td>{{ item.matched_at }}</td>
    76 78   <td>{{ item.created_at }}</td>
    77  - <td>
    78  - <div class="row actionGrp" >
    79  - <div class="col">
    80  - <button type="button" (click)="deleteVulnerabilities(item.id)" nbButton status="danger"><nb-icon icon="trash-outline" ></nb-icon></button>
    81  - </div>
    82  - </div>
    83  - </td>
    84 79   
    85 80   </tr>
    86 81  
    87 82   </table>
    88 83   
    89  - <div class="pagination col-md-4 offset-md-8">
    90  - <nb-select placeholder="Select limit" [(selected)]="this.limit" (selectedChange)="changeLimit($event)">
    91  - <nb-option value="10">10</nb-option>
    92  - <nb-option value="50">50</nb-option>
    93  - <nb-option value="100">100</nb-option>
    94  - <nb-option value="-1">All</nb-option>
    95  - </nb-select>
    96  - <button [disabled]="page==1" (click)="goToPage(page-1)" nbButton ghost status="basic">
    97  - <nb-icon icon="arrow-left-outline"></nb-icon>
    98  - </button>
    99  - <button [disabled]="page==total_pages" nbButton ghost status="basic" (click)="goToPage(page+1)">
    100  - <nb-icon icon="arrow-right-outline"></nb-icon>
    101  - </button>
    102  - <div class="page">
    103  - page {{page}} of {{total_pages}} pages
     84 + <div class="pagination col-md-1 offset-md-11">
     85 + <button [disabled]="page==1" (click)="goToPage(page-1)" nbButton ghost status="basic">
     86 + <nb-icon icon="arrow-left-outline"></nb-icon>
     87 + </button>
     88 + <button [disabled]="page==total_pages" nbButton ghost status="basic" (click)="goToPage(page+1)">
     89 + <nb-icon icon="arrow-right-outline"></nb-icon>
     90 + </button>
     91 + </div>
     92 + <br>
     93 + <div class="page">
     94 + page {{page}} of {{total_pages}} pages
     95 + </div>
     96 + 
     97 + <div class="actionDelete" style="{{selectedVuln.length>0?'right:-10px':''}}" >
     98 + <div class="col">
     99 + <button type="button" (click)="deleteSelectedVulnerabilities()" nbButton status="danger"><nb-icon icon="trash-outline" ></nb-icon></button>
    104 100   </div>
    105 101   </div>
    106  - 
    107 102   
    108 103   </nb-card-body>
    109 104   </nb-card>
    skipped 5 lines
  • ■ ■ ■ ■ ■ ■
    frontend/src/app/pages/vulnerabilities/vulnerabilities.component.scss
    skipped 63 lines
    64 64   border-top-right-radius: 0px;
    65 65   border-bottom-left-radius: 0px;
    66 66  }
     67 +.searchButton button:first-child {
     68 + border-bottom-right-radius: 0px;
     69 +}
     70 +.searchButton button:last-child {
     71 + border-top-left-radius: 0px;
     72 +}
    67 73  .badgeSub {
    68 74   position: relative;
    69 75   border-radius: 10px;
    skipped 9 lines
    79 85  .pagination{
    80 86   margin-top: 20px;
    81 87  }
     88 + 
     89 +.actionDelete {
     90 + position: fixed;
     91 + top:250px;
     92 + right:-200px;
     93 + border:black;
     94 + border-radius: 10px;
     95 + background-color: var(--card-background-color);
     96 + transition: right 0.4s ease-in-out;
     97 + border: var(--card-border-width) var(--card-border-style) var(--card-border-color);
     98 + div{
     99 + padding:10px 25px 10px 10px;
     100 + button{
     101 + 
     102 + }
     103 + }
     104 +}
  • ■ ■ ■ ■ ■
    frontend/src/app/pages/vulnerabilities/vulnerabilities.component.ts
    skipped 19 lines
    20 20   page=1
    21 21   total_pages=1
    22 22   criticity=''
     23 + checkedAll=false
     24 + selectedVuln:Vulnerabilities[]=<any>[]
     25 + 
    23 26  
    24 27   
    25 28   constructor(private vulnerabilitiesService : VulnerabilitiesService,private messageService: MessageService) {
    skipped 11 lines
    37 40   this.loading=false
    38 41   this.messageService.showToast(err.message, 'danger');
    39 42   })
     43 + }
     44 + log(a:any){
     45 + console.log(a)
     46 + }
     47 + selectAll(checked: boolean){
     48 + this.checkedAll = checked;
     49 + if(checked)this.selectedVuln=this.vulnerabilitiesList
     50 + else this.selectedVuln=<any>[]
     51 + }
     52 + selectOne(checked: boolean,id:number){
     53 + if(checked) this.addVuln(id)
     54 + else this.removeVuln(id)
     55 + console.log(this.selectedVuln)
    40 56   }
    41 57   
    42  - deleteVulnerabilities(id:number){
    43  - this.loading=true
    44  - this.vulnerabilitiesService.deleteVulnerabilities(id).subscribe((result)=> {
    45  - this.loading=false
    46  - this.messageService.showToast(result.message, 'success');
    47  - this.getVulnerabilities()
    48  - },(err)=> {
    49  - this.loading=false
    50  - this.messageService.showToast(err.message, 'danger');
     58 + addVuln(id:number){
     59 + this.vulnerabilitiesList.forEach(item=>{
     60 + if(id==item.id){
     61 + this.selectedVuln.push(item)
     62 + }
    51 63   })
    52 64   }
     65 + removeVuln(id:number){
     66 + this.selectedVuln= this.selectedVuln.filter((item)=> {
     67 + return id!=item.id
     68 + })
     69 + }
     70 + async deleteVulnerabilities(id:number){
     71 + new Promise((resolve, reject) =>{
     72 + this.loading=true
     73 + this.vulnerabilitiesService.deleteVulnerabilities(id).subscribe((result)=> {
     74 + this.loading=false
     75 + this.messageService.showToast(result.message, 'success');
     76 + resolve(true)
     77 + },(err)=> {
     78 + this.loading=false
     79 + this.messageService.showToast(err.message, 'danger');
     80 + reject(false)
     81 + })
     82 + })
     83 + }
     84 + deleteSelectedVulnerabilities(){
     85 + let last = this.selectedVuln[this.selectedVuln.length-1]
     86 + this.selectedVuln.forEach(async item => {
     87 + await this.deleteVulnerabilities(item.id).then(async x => {
     88 + if(item.id==last.id){
     89 + await new Promise(f => setTimeout(f, 1000));
     90 + this.selectAll(false)
     91 + this.getVulnerabilities()
     92 + }
     93 + })
    53 94   
     95 + })
     96 + }
    54 97   ngOnInit(): void {
    55 98   
    56 99  
    57 100   }
     101 + delay(ms: number) {
     102 + return new Promise( resolve => setTimeout(resolve, ms) );
     103 +}
    58 104   changeCriticity(event:any){
    59 105   this.criticity=event
    60 106   }
    skipped 11 lines
  • ■ ■ ■ ■ ■ ■
    frontend/src/app/shared/auth-guard.service.ts
    1 1  import {Injectable} from '@angular/core';
    2 2  import {CanActivate, Router} from "@angular/router";
    3  -import {NbAuthService} from "@nebular/auth";
     3 +import {NbAuthService,NbAuthToken} from "@nebular/auth";
    4 4  import { NbToastrService, NbComponentStatus } from '@nebular/theme';
    5 5  import {tap} from "rxjs";
    6 6   
    7 7  @Injectable({
    8 8   providedIn: 'root'
    9 9  })
     10 + 
    10 11  export class AuthGuardService implements CanActivate {
    11 12   
     13 + 
     14 + user = {user_id:0,user_email:'',exp:0};
     15 + 
     16 + 
    12 17   constructor(private authService: NbAuthService,
    13 18   private router: Router,
    14 19   private toastrService: NbToastrService) {
    15 20   //this.authService.isAuthenticated().subscribe( (x) => {console.log(x)})
     21 + this.authService.onTokenChange()
     22 + .subscribe( (token: NbAuthToken) => {
     23 + if (token.isValid()) {
     24 + this.user = token.getPayload(); // receive payload from token and assign it to our `user` variable
     25 + console.log('check token')
     26 + if(Math.floor(Date.now() / 1000) > this.user.exp){
     27 + localStorage.clear();
     28 + this.router.navigateByUrl('/auth/login');
     29 + }
     30 + } else {
     31 + localStorage.clear();
     32 + this.router.navigateByUrl('/auth/login');
     33 + }
     34 + });
    16 35   }
    17 36   
    18 37   canActivate() {
    skipped 17 lines
Please wait...
Page is in error, reload to recover