def get_defendant_services(customer_id): """ Get services for a defendant """ try: response = ImplementationFactory.instance.get_singleton_of('CustomerDaoBase').get_customer_services(customer_id) schema.valid_adapter_response('CustomerDaoBase', 'get_customer_services', response) except (CustomerDaoException, schema.InvalidFormatError, schema.SchemaNotFound) as ex: return 500, {'status': 'Internal Server Error', 'code': 500, 'message': str(ex)} return 200, response
def mass_contact(ip_address=None, category=None, campaign_name=None, email_subject=None, email_body=None, user_id=None): """ Try to identify customer based on `ip_address`, creates Cerberus ticket then send email to customer and finally close ticket. The use case is: a trusted provider sent you a list of vulnerable DNS servers (DrDOS amp) for example. To prevent abuse on your network, you notify customer of this vulnerability. :param str ip_address: The IP address :param str category: The category of the abuse :param str campaign_name: The name if the "mass-conctact" campaign :param str email_subject: The subject of the email to send to defendant :param str email_body: The body of the email to send to defendant :param int user_id: The id of the Cerberus `abuse.models.User` who created the campaign """ # Check params _, _, _, values = inspect.getargvalues(inspect.currentframe()) if not all(values.values()): Logger.error(unicode('invalid parameters submitted %s' % str(values))) return try: validate_ipv46_address(ip_address) except (TypeError, ValidationError): Logger.error(unicode('invalid ip addresses submitted')) return # Get Django model objects try: category = Category.objects.get(name=category) user = User.objects.get(id=user_id) except (AttributeError, ObjectDoesNotExist, TypeError): Logger.error(unicode('invalid user or category')) return # Identify service for ip_address try: services = ImplementationFactory.instance.get_singleton_of('CustomerDaoBase').get_services_from_items(ips=[ip_address]) schema.valid_adapter_response('CustomerDaoBase', 'get_services_from_items', services) except CustomerDaoException as ex: Logger.error(unicode('Exception while identifying defendants for ip %s -> %s ' % (ip_address, str(ex)))) raise CustomerDaoException(ex) # Create report/ticket if services: Logger.debug(unicode('creating report/ticket for ip address %s' % (ip_address))) with pglocks.advisory_lock('cerberus_lock'): __create_contact_tickets(services, campaign_name, ip_address, category, email_subject, email_body, user) return True else: Logger.debug(unicode('no service found for ip address %s' % (ip_address))) return False
def get_or_create(customer_id=None): """ Get or create defendant Attach previous tag if updated defendant infos """ if not customer_id: return None defendant = None try: defendant = Defendant.objects.get(customerId=customer_id) except (TypeError, ObjectDoesNotExist): try: revision_infos = ImplementationFactory.instance.get_singleton_of('CustomerDaoBase').get_customer_infos(customer_id) schema.valid_adapter_response('CustomerDaoBase', 'get_customer_infos', revision_infos) revision_infos.pop('customerId', None) except (CustomerDaoException, schema.InvalidFormatError, schema.SchemaNotFound): return None revision, _ = DefendantRevision.objects.get_or_create(**revision_infos) defendant = Defendant.objects.create(customerId=customer_id, details=revision) DefendantHistory.objects.create(defendant=defendant, revision=revision) return defendant
def refresh_defendant_infos(defendant_id=None): """ Try to update `abuse.models.Defendant`'s revision """ try: defendant = Defendant.objects.get(id=defendant_id) except (AttributeError, ObjectDoesNotExist, ValueError): pass fresh_defendant_infos = None try: fresh_defendant_infos = ImplementationFactory.instance.get_singleton_of('CustomerDaoBase').get_customer_infos(defendant.customerId) schema.valid_adapter_response('CustomerDaoBase', 'get_customer_infos', fresh_defendant_infos) fresh_defendant_infos.pop('customerId', None) if DefendantRevision.objects.filter(**fresh_defendant_infos).count(): revision = DefendantRevision.objects.filter(**fresh_defendant_infos).last() else: revision = DefendantRevision.objects.create(**fresh_defendant_infos) DefendantHistory.objects.create(defendant=defendant, revision=revision) defendant.details = revision defendant.save() except (CustomerDaoException, schema.InvalidFormatError, schema.SchemaNotFound): pass
def create_from_email(email_content=None, filename=None, lang='EN', send_ack=False): """ Create Cerberus report(s) based on email content If send_ack is True and report is attached to a ticket, then an acknowledgement is sent to the email provider. :param str email_content: The raw email content :param str filename: The name of the raw email file :param str lang: Langage to use if send_ack is True :param bool send_ack: If an acknowledgment have to be sent to provider :raises CustomerDaoException: if exception while identifying defendants from items :raises MailerServiceException: if exception while updating ticket's emails :raises StorageServiceException: if exception while accessing storage """ # This function use a lock/commit_on_succes on db when creating reports # # Huge blocks of code are under transaction because it's important to # rollback if ANYTHING goes wrong in the report creation workflow. # # Concurrent transactions (with multiple workers), on defendant/service creation # can result in unconsistent data, So a pg_lock is used. # # `abuse.models.Defendant` and `abuse.models.Service` HAVE to be unique. if not email_content: Logger.error(unicode('Missing email content')) return if not filename: # Worker have to push email to Storage Service filename = hashlib.sha256(email_content).hexdigest() __save_email(filename, email_content) # Parse email content abuse_report = Parser.parse(email_content) Logger.debug(unicode('New email from %s' % (abuse_report.provider)), extra={'from': abuse_report.provider, 'action': 'new email'}) # Check if provider is not blacklisted if abuse_report.provider in settings.PARSING['providers_to_ignore']: Logger.error(unicode('Provider %s is blacklisted, skipping ...' % (abuse_report.provider))) return # Check if it's an answer to a ticket(s) tickets = ImplementationFactory.instance.get_singleton_of('MailerServiceBase').is_email_ticket_answer(abuse_report) if tickets: for ticket, category, recipient in tickets: if all((ticket, category, recipient)) and not ticket.locked: # OK it's an anwser, updating ticket and exiting _update_ticket_if_answer(ticket, category, recipient, abuse_report, filename) return # Check if items are linked to customer and get corresponding services try: services = ImplementationFactory.instance.get_singleton_of('CustomerDaoBase').get_services_from_items( urls=abuse_report.urls, ips=abuse_report.ips, fqdn=abuse_report.fqdn ) schema.valid_adapter_response('CustomerDaoBase', 'get_services_from_items', services) except CustomerDaoException as ex: Logger.error(unicode('Exception while identifying defendants from items for mail %s -> %s ' % (filename, str(ex)))) raise CustomerDaoException(ex) # Create report(s) with identified services if not services: created_reports = [__create_without_services(abuse_report, filename)] else: with pglocks.advisory_lock('cerberus_lock'): __create_defendants_and_services(services) created_reports = __create_with_services(abuse_report, filename, services) # Upload attachments if abuse_report.attachments: _save_attachments(filename, abuse_report.attachments, reports=created_reports) # Send acknowledgement to provider (only if send_ack = True and report is attached to a ticket) for report in created_reports: if send_ack and report.ticket: try: __send_ack(report, lang=lang) except MailerServiceException as ex: raise MailerServiceException(ex) # Index to SearchService if ImplementationFactory.instance.is_implemented('SearchServiceBase'): __index_report_to_searchservice(abuse_report, filename, [rep.id for rep in created_reports]) Logger.info(unicode('All done successfully for email %s' % (filename)))