mirror of
https://github.com/yogeshojha/rengine.git
synced 2026-08-23 22:32:24 +02:00
210 lines
6.7 KiB
Python
210 lines
6.7 KiB
Python
# include all the celery tasks to be used in the API, do not put in tasks.py
|
|
import requests
|
|
|
|
from reNgine.common_func import create_inappnotification, get_hackerone_key_username
|
|
from reNgine.definitions import PROJECT_LEVEL_NOTIFICATION, HACKERONE_ALLOWED_ASSET_TYPES
|
|
from reNgine.celery import app
|
|
from reNgine.database_utils import bulk_import_targets
|
|
|
|
@app.task(name='import_hackerone_programs_task', bind=False, queue='api_queue')
|
|
def import_hackerone_programs_task(handles, project_slug, is_sync = False):
|
|
"""
|
|
Runs in the background to import programs from HackerOne
|
|
|
|
Args:
|
|
handles (list): List of handles to import
|
|
project_slug (str): Slug of the project
|
|
is_sync (bool): If the import is a sync operation
|
|
Returns:
|
|
None
|
|
rather creates inapp notifications
|
|
"""
|
|
def fetch_program_details_from_hackerone(program_handle):
|
|
url = f'https://api.hackerone.com/v1/hackers/programs/{program_handle}'
|
|
headers = {'Accept': 'application/json'}
|
|
creds = get_hackerone_key_username()
|
|
|
|
if not creds:
|
|
raise Exception("HackerOne API credentials not configured")
|
|
|
|
username, api_key = creds
|
|
|
|
response = requests.get(
|
|
url,
|
|
headers=headers,
|
|
auth=(username, api_key)
|
|
)
|
|
|
|
if response.status_code == 401:
|
|
raise Exception("HackerOne API credentials are invalid")
|
|
|
|
if response.status_code == 200:
|
|
return response.json()
|
|
else:
|
|
return None
|
|
|
|
for handle in handles:
|
|
program_details = fetch_program_details_from_hackerone(handle)
|
|
if program_details:
|
|
# Thanks, some parts of this logics were originally written by @null-ref-0000
|
|
# via PR https://github.com/yogeshojha/rengine/pull/1410
|
|
try:
|
|
program_name = program_details['attributes']['name']
|
|
|
|
assets = []
|
|
scopes = program_details['relationships']['structured_scopes']['data']
|
|
for scope in scopes:
|
|
asset_type = scope['attributes']['asset_type']
|
|
asset_identifier = scope['attributes']['asset_identifier']
|
|
eligible_for_submission = scope['attributes']['eligible_for_submission']
|
|
|
|
# for now we should ignore the scope that are not eligible for submission
|
|
# in future release we will add this in target out_of_scope
|
|
|
|
# we need to filter the scope that are supported by reNgine now
|
|
if asset_type in HACKERONE_ALLOWED_ASSET_TYPES and eligible_for_submission:
|
|
assets.append(asset_identifier)
|
|
|
|
# in some cases asset_type is OTHER and may contain the asset
|
|
elif asset_type == 'OTHER' and ('.' in asset_identifier or asset_identifier.startswith('http')):
|
|
assets.append(asset_identifier)
|
|
|
|
# cleanup assets
|
|
assets = list(set(assets))
|
|
|
|
# convert assets to list of dict with name and description
|
|
assets = [{'name': asset, 'description': None} for asset in assets]
|
|
new_targets_added = bulk_import_targets(
|
|
targets=assets,
|
|
project_slug=project_slug,
|
|
organization_name=program_name,
|
|
org_description='Imported from Hackerone',
|
|
h1_team_handle=handle
|
|
)
|
|
|
|
if new_targets_added:
|
|
create_inappnotification(
|
|
title=f"HackerOne Program Imported: {handle}",
|
|
description=f"The program '{program_name}' from hackerone has been successfully imported.",
|
|
notification_type=PROJECT_LEVEL_NOTIFICATION,
|
|
project_slug=project_slug,
|
|
icon="mdi-check-circle",
|
|
status='success'
|
|
)
|
|
|
|
except Exception as e:
|
|
create_inappnotification(
|
|
title=f"HackerOne Program Import Failed: {handle}",
|
|
description=f"Failed to import program from hackerone with handle '{handle}'. {str(e)}",
|
|
notification_type=PROJECT_LEVEL_NOTIFICATION,
|
|
project_slug=project_slug,
|
|
icon="mdi-alert-circle",
|
|
status='error'
|
|
)
|
|
else:
|
|
create_inappnotification(
|
|
title=f"HackerOne Program Import Failed: {handle}",
|
|
description=f"Failed to import program from hackerone with handle '{handle}'. Program details could not be fetched.",
|
|
notification_type=PROJECT_LEVEL_NOTIFICATION,
|
|
project_slug=project_slug,
|
|
icon="mdi-alert-circle",
|
|
status='error'
|
|
)
|
|
|
|
if is_sync:
|
|
title = "HackerOne Program Sync Completed"
|
|
description = f"Sync process for {len(handles)} program(s) has completed."
|
|
else:
|
|
title = "HackerOne Program Import Completed"
|
|
description = f"Import process for {len(handles)} program(s) has completed."
|
|
|
|
create_inappnotification(
|
|
title=title,
|
|
description=description,
|
|
notification_type=PROJECT_LEVEL_NOTIFICATION,
|
|
project_slug=project_slug,
|
|
icon="mdi-check-all",
|
|
status='success'
|
|
)
|
|
|
|
|
|
@app.task(name='sync_bookmarked_programs_task', bind=False, queue='api_queue')
|
|
def sync_bookmarked_programs_task(project_slug):
|
|
"""
|
|
Runs in the background to sync bookmarked programs from HackerOne
|
|
|
|
Args:
|
|
project_slug (str): Slug of the project
|
|
Returns:
|
|
None
|
|
Creates in-app notifications for progress and results
|
|
"""
|
|
|
|
def fetch_bookmarked_programs():
|
|
url = f'https://api.hackerone.com/v1/hackers/programs?&page[size]=100'
|
|
headers = {'Accept': 'application/json'}
|
|
bookmarked_programs = []
|
|
|
|
credentials = get_hackerone_key_username()
|
|
if not credentials:
|
|
raise Exception("HackerOne API credentials not configured")
|
|
|
|
username, api_key = credentials
|
|
|
|
while url:
|
|
response = requests.get(
|
|
url,
|
|
headers=headers,
|
|
auth=(username, api_key)
|
|
)
|
|
|
|
if response.status_code == 401:
|
|
raise Exception("HackerOne API credentials are invalid")
|
|
elif response.status_code != 200:
|
|
raise Exception(f"HackerOne API request failed with status code {response.status_code}")
|
|
|
|
data = response.json()
|
|
programs = data['data']
|
|
bookmarked = [p for p in programs if p['attributes']['bookmarked']]
|
|
bookmarked_programs.extend(bookmarked)
|
|
|
|
url = data['links'].get('next')
|
|
|
|
return bookmarked_programs
|
|
|
|
try:
|
|
bookmarked_programs = fetch_bookmarked_programs()
|
|
handles = [program['attributes']['handle'] for program in bookmarked_programs]
|
|
|
|
if not handles:
|
|
create_inappnotification(
|
|
title="HackerOne Bookmarked Programs Sync Completed",
|
|
description="No bookmarked programs found.",
|
|
notification_type=PROJECT_LEVEL_NOTIFICATION,
|
|
project_slug=project_slug,
|
|
icon="mdi-information",
|
|
status='info'
|
|
)
|
|
return
|
|
|
|
import_hackerone_programs_task.delay(handles, project_slug, is_sync=True)
|
|
|
|
create_inappnotification(
|
|
title="HackerOne Bookmarked Programs Sync Progress",
|
|
description=f"Found {len(handles)} bookmarked program(s). Starting import process.",
|
|
notification_type=PROJECT_LEVEL_NOTIFICATION,
|
|
project_slug=project_slug,
|
|
icon="mdi-progress-check",
|
|
status='info'
|
|
)
|
|
|
|
except Exception as e:
|
|
create_inappnotification(
|
|
title="HackerOne Bookmarked Programs Sync Failed",
|
|
description=f"Failed to sync bookmarked programs: {str(e)}",
|
|
notification_type=PROJECT_LEVEL_NOTIFICATION,
|
|
project_slug=project_slug,
|
|
icon="mdi-alert-circle",
|
|
status='error'
|
|
)
|