def set_treatment_manager(treatment: str, treatment_manager: str, finding: Dict[str, FindingType], is_customer_admin: bool, user_mail: str) -> str: if treatment == 'IN PROGRESS': if not is_customer_admin: treatment_manager = user_mail if treatment_manager: project_users = project_dal.get_users( str(finding.get('project_name'))) customer_roles = ['customer', 'customeradmin'] customer_users = \ [user for user in project_users if user_domain.get_data(user, 'role') in customer_roles] if treatment_manager not in customer_users: raise GraphQLError('Invalid treatment manager') else: raise GraphQLError('Invalid treatment manager') elif treatment == 'ACCEPTED': treatment_manager = user_mail elif treatment == 'ACCEPTED_UNDEFINED': last_state = cast(List[Dict[str, str]], finding.get('historic_treatment'))[-1] if last_state['acceptance_status'] == 'SUBMITTED': treatment_manager = user_mail else: treatment_manager = last_state['user'] return treatment_manager
def send_updated_vuln_email(finding_id: str, user_email: str, data_vuln: Dict[str, str], updated_vuln_description: str): """Send email when vulnerabilities were updated""" if len(updated_vuln_description) == 1: number_vuln = 'vulnerability' else: number_vuln = 'vulnerabilities' project_name = \ str(finding_dal.get_attributes(finding_id, ['project_name']).get('project_name')).lower() recipients = project_dal.get_users(project_name, True) finding_name = finding_dal.get_attributes(finding_id, ['finding']).get('finding') email_send_thread = threading.Thread( name='Updated vulnerabilities email thread', target=send_mail_updated_vulns, args=(recipients, { 'user_email': user_email, 'finding_name': finding_name, 'number_vuln': number_vuln, 'project': project_name.capitalize(), 'treatment': str(data_vuln['treatment']).lower(), 'updated_vuln_description': updated_vuln_description, 'justification': data_vuln.get('treatment_justification', ''), 'treatment_manager': data_vuln.get('treatment_manager', ''), })) email_send_thread.start()
def request_verification(finding_id: str, user_email: str, user_fullname: str, justification: str, vuln_ids: List[str]) -> bool: finding = finding_dal.get_finding(finding_id) vulnerabilities = get_by_ids(finding_id, vuln_ids) vulnerabilities = [ validate_requested_verification(vuln) for vuln in vulnerabilities ] vulnerabilities = [validate_closed(vuln) for vuln in vulnerabilities] if not vulnerabilities: raise VulnNotFound() comment_id = int(round(time() * 1000)) tzn = pytz.timezone(settings.TIME_ZONE) # type: ignore today = datetime.now(tz=tzn).today().strftime('%Y-%m-%d %H:%M:%S') historic_verification = cast(List[Dict[str, Union[str, int, List[str]]]], finding.get('historic_verification', [])) historic_verification.append({ 'date': today, 'user': user_email, 'status': 'REQUESTED', 'comment': comment_id, 'vulns': vuln_ids }) update_finding = finding_dal.update( finding_id, {'historic_verification': historic_verification}) comment_data = { 'comment_type': 'verification', 'content': justification, 'created': today, 'email': user_email, 'finding_id': int(finding_id), 'fullname': user_fullname, 'modified': today, 'parent': 0, } comment_dal.create(comment_id, comment_data) update_vulns = [ vuln_dal.request_verification(vuln) for vuln in vulnerabilities ] if all(update_vulns) and update_finding: finding_utils.send_remediation_email( user_email, finding_id, str(finding.get('finding', '')), str(finding.get('project_name', '')), justification) project_users = project_dal.get_users( str(finding.get('project_name', ''))) notifications.notify_mobile( project_users, t('notifications.remediated.title'), t('notifications.remediated.content', finding=finding.get('finding'), project=str(finding.get('project_name', '')).upper())) else: rollbar.report_message('Error: An error occurred remediating', 'error') return all(update_vulns)
def verify_finding(finding_id: str, user_email: str, justification: str, user_fullname: str) -> bool: success = False finding = get_finding(finding_id) project_name = str(finding.get('projectName', '')) finding_name = str(finding.get('finding', '')) historic_verification = cast(List[Dict[str, Union[str, int, datetime]]], finding.get('historicVerification', [{}])) if historic_verification[-1].get('status') == 'REQUESTED' and\ not historic_verification[-1].get('vulns', []): tzn = pytz.timezone(settings.TIME_ZONE) # type: ignore today = datetime.now(tz=tzn).today().strftime('%Y-%m-%d %H:%M:%S') comment_id = int(round(time() * 1000)) new_state: Dict[str, Union[str, int, datetime]] = { 'date': today, 'user': user_email, 'status': 'VERIFIED', 'comment': comment_id, } comment_data = { 'user_id': comment_id, 'comment_type': 'verification', 'content': justification, 'fullname': user_fullname, 'parent': historic_verification[-1].get('comment', 0), } historic_verification.append(new_state) add_comment(user_email, comment_data, finding_id, is_remediation_comment=True) success = finding_dal.update( finding_id, {'historic_verification': historic_verification}) if success: vuln_domain.update_vulnerabilities_date(user_email, finding_id) finding_utils.send_finding_verified_email(finding_id, finding_name, project_name) project_users = project_dal.get_users(project_name) notifications.notify_mobile( project_users, t('notifications.verified.title'), t('notifications.verified.content', finding=finding_name, project=project_name.upper())) else: rollbar.report_message( 'Error: An error occurred verifying the finding', 'error') else: raise NotVerificationRequested() return success
def send_finding_verified_email(finding_id: str, finding_name: str, project_name: str): recipients = project_dal.get_users(project_name) base_url = 'https://fluidattacks.com/integrates/dashboard#!' email_send_thread = threading.Thread( name='Verified finding email thread', target=send_mail_verified_finding, args=(recipients, { 'project': project_name, 'finding_name': finding_name, 'finding_url': base_url + '/project/{project!s}/{finding!s}/tracking' .format(project=project_name, finding=finding_id), 'finding_id': finding_id })) email_send_thread.start()
def get_email_recipients(project_name: str, comment_type: Union[str, bool]) -> List[str]: project_users = project_dal.get_users(project_name) recipients: List[str] = [] approvers = FI_MAIL_REVIEWERS.split(',') recipients += approvers if comment_type == 'observation': analysts = [ user for user in project_users if user_domain.get_data(user, 'role') == 'analyst' ] recipients += analysts else: recipients += project_users return recipients
def verify(info, finding_id: str, vulnerabilities: List[Dict[str, str]], closed_vulns: List[str], date) -> List[bool]: finding = finding_dal.get_finding(finding_id) success = [ update_vuln_state(info, [vuln], {'state': 'closed'}, finding_id, date) for vuln in vulnerabilities if vuln.get('UUID') in closed_vulns ] finding_utils.send_finding_verified_email( finding_id, str(finding.get('finding', '')), str(finding.get('project_name', ''))) project_users = project_dal.get_users(str(finding.get('project_name', ''))) notifications.notify_mobile( project_users, t('notifications.verified.title'), t('notifications.verified.content', finding=str(finding.get('finding', '')), project=str(finding.get('project_name', '')).upper())) return success
def send_remediation_email(user_email: str, finding_id: str, finding_name: str, project_name: str, justification: str): recipients = project_dal.get_users(project_name) base_url = 'https://fluidattacks.com/integrates/dashboard#!' email_send_thread = threading.Thread( name='Remediate finding email thread', target=send_mail_remediate_finding, args=(recipients, { 'project': project_name.lower(), 'finding_name': finding_name, 'finding_url': base_url + '/project/{project!s}/{finding!s}/description' .format(project=project_name, finding=finding_id), 'finding_id': finding_id, 'user_email': user_email, 'solution_description': justification })) email_send_thread.start()
def send_accepted_email(finding: Dict[str, FindingType], justification: str): project_name = str(finding.get('projectName', '')) finding_name = str(finding.get('finding', '')) last_historic_treatment = cast(List[Dict[str, str]], finding.get('historicTreatment'))[-1] recipients = project_dal.get_users(project_name) treatment = 'Accepted' if last_historic_treatment['treatment'] == 'ACCEPTED_UNDEFINED': treatment = 'Indefinitely accepted' email_send_thread = threading.Thread( name='Accepted finding email thread', target=send_mail_accepted_finding, args=(recipients, { 'finding_name': finding_name, 'finding_id': finding.get('finding_id'), 'project': project_name.capitalize(), 'justification': justification, 'user_email': last_historic_treatment['user'], 'treatment': treatment })) email_send_thread.start()
def send_comment_mail(comment_data: CommentType, entity_name: str, user_mail: str, comment_type: str = '', entity: Union[str, Dict[str, FindingType], EventType, ProjectType] = ''): parent = comment_data['parent'] base_url = 'https://fluidattacks.com/integrates/dashboard#!' email_context = { 'user_email': user_mail, 'comment': str(comment_data['content']).replace('\n', ' '), 'comment_type': comment_type, 'parent': parent, } if entity_name == 'finding': finding: Dict[str, FindingType] = cast(Dict[str, FindingType], entity) project_name = str(finding.get('projectName', '')) recipients = get_email_recipients(project_name, comment_type) is_draft = 'releaseDate' in finding email_context['finding_id'] = str(finding.get('findingId', '')) email_context['finding_name'] = str(finding.get('finding', '')) comment_url = ( base_url + '/project/{project}/{finding_type}/{id}/{comment_type}s'.format( comment_type=comment_type, finding_type='findings' if is_draft else 'drafts', id=finding.get('findingId'), project=project_name)) elif entity_name == 'event': event = cast(EventType, entity) event_id = str(event.get('event_id', '')) project_name = str(event.get('project_name', '')) recipients = project_dal.get_users(project_name, True) email_context['finding_id'] = event_id email_context['finding_name'] = f'Event #{event_id}' comment_url = ('https://fluidattacks.com/integrates/dashboard#!/' f'project/{project_name}/events/{event_id}/comments') elif entity_name == 'project': project_name = str(entity) recipients = get_email_recipients(project_name, True) comment_url = ( base_url + '/project/{project!s}/comments'.format(project=project_name)) email_context['comment_url'] = comment_url email_context['project'] = project_name recipients_customers = [ recipient for recipient in recipients if user_domain.get_data( recipient, 'role') in ['customer', 'customeradmin'] ] recipients_not_customers = [ recipient for recipient in recipients if user_domain.get_data( recipient, 'role') not in ['customer', 'customeradmin'] ] email_context_customers = email_context.copy() if user_domain.get_data(user_mail, 'role') not in ['customer', 'customeradmin']: email_context_customers['user_email'] = \ 'Hacker at ' + str(user_domain.get_data(user_mail, 'company')).capitalize() email_send_thread = threading.Thread( name='New {} email thread'.format(entity_name), target=send_mail_comment, args=([recipients_not_customers, recipients_customers], [email_context, email_context_customers])) email_send_thread.start()
def get_users(project_name: str, active: bool = True) -> List[str]: return project_dal.get_users(project_name, active)