def update_paused(): """ Update paused tickets """ now = int(time()) for ticket in Ticket.objects.filter(status=PAUSED): try: if now > int(mktime(ticket.pauseStart.timetuple()) + ticket.pauseDuration): Logger.debug( str('Updating status for ticket %s ' % (ticket.id)), extra={ 'ticket': ticket.id, } ) if ticket.previousStatus == WAITING and ticket.snoozeDuration and ticket.snoozeStart: ticket.snoozeDuration = ticket.snoozeDuration + (datetime.now() - ticket.pauseStart).seconds ticket.status = ticket.previousStatus ticket.pauseStart = None ticket.pauseDuration = None ticket.previousStatus = PAUSED ticket.save() database.log_action_on_ticket( ticket=ticket, action='change_status', previous_value=ticket.previousStatus, new_value=ticket.status ) except (AttributeError, ValueError) as ex: Logger.debug(unicode('Error while updating ticket %d : %s' % (ticket.id, ex)))
def _apply_timeout_action(ticket, ip_addr, action): Logger.info(unicode('Executing action %s for ticket %d' % (action.name, ticket.id))) ticket.action = action database.log_action_on_ticket( ticket=ticket, action='set_action', action_name=action.name ) ticket.save() async_job = utils.scheduler.schedule( scheduled_time=datetime.utcnow() + timedelta(seconds=3), func='action.apply_action', kwargs={ 'ticket_id': ticket.id, 'action_id': action.id, 'ip_addr': ip_addr, 'user_id': BOT_USER.id, }, interval=1, repeat=1, result_ttl=500, timeout=3600, ) Logger.info(unicode('Task has %s job id' % (async_job.id))) job = ServiceActionJob.objects.create(ip=ip_addr, action=action, asynchronousJobId=async_job.id, creationDate=datetime.now()) ticket.jobs.add(job) while not async_job.is_finished: sleep(5) return async_job
def update_waiting(): """ Update waiting answer tickets """ now = int(time()) for ticket in Ticket.objects.filter(status=WAITING): try: if now > int(mktime(ticket.snoozeStart.timetuple()) + ticket.snoozeDuration): Logger.debug( unicode('Updating status for ticket %s ' % (ticket.id)), extra={ 'ticket': ticket.id, } ) _check_auto_unassignation(ticket) ticket.status = ALARM ticket.snoozeStart = None ticket.snoozeDuration = None ticket.previousStatus = WAITING ticket.reportTicket.all().update(status='Attached') ticket.save() database.log_action_on_ticket( ticket=ticket, action='change_status', previous_value=ticket.previousStatus, new_value=ticket.status ) except (AttributeError, ValueError) as ex: Logger.debug(unicode('Error while updating ticket %d : %s' % (ticket.id, ex)))
def send_email(ticket, emails, template_codename, lang='EN', acknowledged_report_id=None): """ Wrapper to send email """ prefetched_email = ImplementationFactory.instance.get_singleton_of('MailerServiceBase').prefetch_email_from_template( ticket, template_codename, lang=lang, acknowledged_report=acknowledged_report_id, ) for email in emails: try: validate_email(email) except ValidationError: continue ImplementationFactory.instance.get_singleton_of('MailerServiceBase').send_email( ticket, email, prefetched_email.subject, prefetched_email.body, prefetched_email.category ) database.log_action_on_ticket( ticket=ticket, action='send_email', email=email )
def timeout(ticket_id=None): """ If ticket timeout , apply action on service (if defendant not internal/VIP) and ticket is not assigned :param int ticket_id: The id of the Cerberus `abuse.models.Ticket` """ try: ticket = Ticket.objects.get(id=ticket_id) except (AttributeError, ObjectDoesNotExist, ValueError): Logger.error(unicode('Ticket %d cannot be found in DB. Skipping...' % (ticket_id))) return if not _check_timeout_ticket_conformance(ticket): return action = ImplementationFactory.instance.get_singleton_of('ActionServiceBase').get_action_for_timeout(ticket) if not action: Logger.error(unicode('Ticket %d service %s: action not found, exiting ...' % (ticket_id, ticket.service.componentType))) return # Maybe customer fixed, closing ticket if ticket.category.name.lower() == 'phishing' and phishing.is_all_down_for_ticket(ticket): Logger.info(unicode('All items are down for ticket %d, closing ticket' % (ticket_id))) close_ticket(ticket, reason=settings.CODENAMES['fixed_customer'], service_blocked=False) return # Getting ip for action ip_addr = _get_ip_for_action(ticket) if not ip_addr: Logger.error(unicode('Error while getting IP for action, exiting')) ticket.status = ticket.previousStatus ticket.status = 'ActionError' database.log_action_on_ticket( ticket=ticket, action='change_status', previous_value=ticket.previousStatus, new_value=ticket.status ) comment = Comment.objects.create(user=BOT_USER, comment='None or multiple ip addresses for this ticket') TicketComment.objects.create(ticket=ticket, comment=comment) database.log_action_on_ticket( ticket=ticket, action='add_comment' ) ticket.save() return # Apply action service_action_job = _apply_timeout_action(ticket, ip_addr, action) if not service_action_job.result: Logger.debug(unicode('Error while executing service action, exiting')) return Logger.info(unicode('All done, sending close notification to provider(s)')) ticket = Ticket.objects.get(id=ticket.id) # Closing ticket close_ticket(ticket, reason=settings.CODENAMES['fixed'], service_blocked=True)
def apply_if_no_reply(ticket_id=None, action_id=None, ip_addr=None, resolution_id=None, user_id=None, close=False): """ Action if no reply from customer :param int ticket_id: The id of the Cerberus `Ticket` :param int action_id: The id of the Cerberus `ServiceAction` :param str ip_addr: The ip address :param int resolution_id: The id of the Cerberus `Resolution` :param int user_id: The id of the Cerberus `User` :param bool close: If the ticket has to be closed after action """ # Checking conformance if not all((ticket_id, action_id, user_id)): Logger.error(unicode( 'Invalid parameters [ticket_id=%s, action_id=%s, user_id=%s]' % (ticket_id, action_id, user_id) )) return if close and not resolution_id: Logger.error(unicode('Close requested but no resolution submitted')) return if resolution_id and not Resolution.objects.filter(id=resolution_id).exists(): Logger.error(unicode('Ticket resolution %d not found, Skipping...' % (resolution_id))) return # Apply action applied = apply_action(ticket_id, action_id, ip_addr, user_id) if not applied: return # Updating ticket info ticket = Ticket.objects.get(id=ticket_id) user = User.objects.get(id=user_id) ticket.previousStatus = ticket.status ticket.snoozeDuration = None ticket.snoozeStart = None close_reason = None if close and resolution_id: __close_ticket(ticket, resolution_id) close_reason = ticket.resolution.codename else: ticket.status = 'Alarm' ticket.save() database.log_action_on_ticket( ticket=ticket, action='change_status', user=user, previous_value=ticket.previousStatus, new_value=ticket.status, close_reason=close_reason ) Logger.info(unicode('Ticket %d processed. Next !' % (ticket_id)))
def __create_threshold_ticket(data, thres): service = Service.objects.filter(id=data[1]).last() defendant = Defendant.objects.filter(customerId=data[0]).last() ticket = database.create_ticket(defendant, thres.category, service) database.log_action_on_ticket( ticket=ticket, action='create_threshold', threshold_count=thres.threshold, threshold_interval=thres.interval, ) return ticket
def close_ticket(ticket, reason=settings.CODENAMES['fixed_customer'], service_blocked=False): """ Close ticket and add autoclosed Tag """ # Send "case closed" email to already contacted Provider(s) providers_emails = ContactedProvider.objects.filter(ticket_id=ticket.id).values_list('provider__email', flat=True).distinct() for email in providers_emails: try: validate_email(email.strip()) _send_email(ticket, email, settings.CODENAMES['case_closed']) ticket.save() Logger.info(unicode('Mail sent to provider %s' % (email))) except (AttributeError, TypeError, ValueError, ValidationError): pass if service_blocked: template = settings.CODENAMES['service_blocked'] else: template = settings.CODENAMES['ticket_closed'] # Send "ticket closed" email to defendant _send_email(ticket, ticket.defendant.details.email, template, lang=ticket.defendant.details.lang) if ticket.mailerId: ImplementationFactory.instance.get_singleton_of('MailerServiceBase').close_thread(ticket) resolution = Resolution.objects.get(codename=reason) ticket.resolution = resolution ticket.previousStatus = ticket.status ticket.status = 'Closed' ticket.reportTicket.all().update(status='Archived') tag_name = settings.TAGS['phishing_autoclosed'] if ticket.category.name.lower() == 'phishing' else settings.TAGS['copyright_autoclosed'] ticket.tags.add(Tag.objects.get(name=tag_name)) ticket.save() database.log_action_on_ticket( ticket=ticket, action='change_status', previous_value=ticket.previousStatus, new_value=ticket.status, close_reason=ticket.resolution.codename ) database.log_action_on_ticket( ticket=ticket, action='add_tag', tag_name=tag_name )
def _update_ticket_if_answer(ticket, category, recipient, abuse_report, filename): """ If the email is an answer to a cerberus ticket: - update ticket status - cancel all pending ServiceAction jobs and ticket.timeout jobs - append response to ticket's email thread - save attachments :param `abuse.models.Ticket` ticket: A Cerberus `abuse.models.Ticket` instance :param str category: The category of the answer ('Defendant', 'Plaintiff' or 'Other) :param str recipient: The recipient of the answer :param `worker.parsing.parser.ParsedEmail` abuse_report: The ParsedEmail :param str filename: The filename of the email """ Logger.debug( unicode('New %s answer from %s for ticket %s' % (category, abuse_report.provider, ticket.id)), extra={ 'from': abuse_report.provider, 'action': 'new answer', 'hash': filename, 'ticket': ticket.id, } ) database.log_action_on_ticket( ticket=ticket, action='receive_email', email=abuse_report.provider ) try: if ticket.treatedBy.operator.role.modelsAuthorizations['ticket'].get('unassignedOnAnswer'): ticket.treatedBy = None except (AttributeError, KeyError, ObjectDoesNotExist, ValueError): pass if abuse_report.attachments: _save_attachments( filename, abuse_report.attachments, tickets=[ticket], ) for workflow in TicketAnswerWorkflowFactory.instance.registered_instances: if workflow.identify(ticket, abuse_report, recipient, category) and workflow.apply(ticket, abuse_report, recipient, category): Logger.debug(unicode('Specific workflow %s applied' % (str(workflow.__class__.__name__)))) return
def close_ticket(report, resolution_codename=None, user=None): """ Close a `abuse.models.Ticket` """ resolution = Resolution.objects.get(codename=resolution_codename) report.ticket.resolution = resolution report.ticket.previousStatus = report.ticket.status report.ticket.status = 'Closed' report.status = 'Archived' database.log_action_on_ticket( ticket=report.ticket, action='change_status', user=user, previous_value=report.ticket.previousStatus, new_value=report.ticket.status, close_reason=report.ticket.resolution.codename ) report.ticket.save() report.save()
def create_ticket(report, denied_by=None, attach_new=False): """ Create a `abuse.models.Ticket` """ ticket = database.create_ticket(report.defendant, report.category, report.service, priority=report.provider.priority, attach_new=attach_new) database.log_action_on_ticket( ticket=ticket, action='attach_report', new_ticket=True, report=report ) if denied_by: user = User.objects.get(id=denied_by) database.log_action_on_ticket( ticket=ticket, action='deny_phishtocheck', user=user, report=report ) return ticket
def _reinject_validated(report, user): trusted = True ticket = None if all((report.defendant, report.category, report.service)): msg = 'Looking for opened ticket for (%s, %s, %s)' Logger.debug(unicode(msg % (report.defendant.customerId, report.category.name, report.service.name))) ticket = database.search_ticket(report.defendant, report.category, report.service) # Checking specific processing workflow for workflow in ReportWorkflowFactory.instance.registered_instances: if workflow.identify(report, ticket, is_trusted=trusted) and workflow.apply(report, ticket, trusted, False): Logger.debug(unicode('Specific workflow %s applied' % (str(workflow.__class__.__name__)))) return # Create ticket if trusted new_ticket = False if not ticket: ticket = database.create_ticket(report.defendant, report.category, report.service, priority=report.provider.priority) new_ticket = True if ticket: report.ticket = Ticket.objects.get(id=ticket.id) report.status = 'Attached' report.save() database.set_ticket_higher_priority(report.ticket) database.log_action_on_ticket( ticket=ticket, action='attach_report', report=report, new_ticket=new_ticket, user=user ) try: __send_ack(report, lang='EN') except MailerServiceException as ex: raise MailerServiceException(ex)
def _check_auto_unassignation(ticket): history = ticket.ticketHistory.filter(actionType='ChangeStatus').order_by('-date').values_list('ticketStatus', flat=True)[:3] try: unassigned_on_multiple_alarm = ticket.treatedBy.operator.role.modelsAuthorizations['ticket']['unassignedOnMultipleAlarm'] if unassigned_on_multiple_alarm and len(history) == 3 and all([STATUS_SEQUENCE[i] == history[i] for i in xrange(3)]): database.log_action_on_ticket( ticket=ticket, action='change_treatedby', previous_value=ticket.treatedBy ) database.log_action_on_ticket( ticket=ticket, action='update_property', property='escalated', previous_value=ticket.escalated, new_value=True, ) ticket.treatedBy = None ticket.escalated = True Logger.debug(unicode('Unassigning ticket %d because of operator role configuration' % (ticket.id))) except (AttributeError, KeyError, ObjectDoesNotExist, ValueError): pass
def apply_then_close(ticket_id=None, action_id=None, ip_addr=None, resolution_id=None, user_id=None): """ Action on service then close :param int ticket_id: The id of the Cerberus `Ticket` :param int action_id: The id of the Cerberus `ServiceAction` :param str ip_addr: The ip address :param int resolution_id: The id of the Cerberus `Resolution` :param int user_id: The id of the Cerberus `User` """ # Checking conformance if not all((ticket_id, action_id, resolution_id, user_id)): msg = 'Invalid parameters submitted [ticket_id=%d, action_id=%s, resolution_id=%s, user_id=%s]' Logger.error(unicode(msg % (ticket_id, action_id, resolution_id, user_id))) return # Apply action applied = apply_action(ticket_id, action_id, ip_addr, user_id) if not applied: return # Closing ticket and updating ticket info ticket = Ticket.objects.get(id=ticket_id) user = User.objects.get(id=user_id) __close_ticket(ticket, resolution_id) database.log_action_on_ticket( ticket=ticket, action='change_status', user=user, previous_value=ticket.previousStatus, new_value=ticket.status, close_reason=ticket.resolution.codename ) ticket.resolution_id = resolution_id ticket.save() Logger.info(unicode('Ticket %d processed. Next !' % (ticket_id)))
def __create_with_services(abuse_report, filename, services): """ Create report(s), ticket(s), item(s), defendant(s), service(s), attachment(s) in Cerberus :param `ParsedEmail` abuse_report: The `ParsedEmail` :param str filename: The filename of the email :param dict services: The identified service(s) (see adapters/dao/customer/abstract.py) :rtype: list :returns: The list of Cerberus `abuse.models.Report` created """ created_reports = [] for data in services: # For identified (service, defendant, items) tuple report = __create_without_services(abuse_report, filename) created_reports.append(report) report.defendant = data['defendant'] report.service = data['service'] report.save() if report.status == 'Archived': # because autoarchive tag continue _, attach_only, no_phishtocheck = __get_attributes_based_on_tags(report, abuse_report.recipients) __insert_items(report.id, data['items']) # The provider or the way we received the report trusted = True if report.provider.trusted or abuse_report.trusted else False # Looking for existing open ticket for same (service, defendant, category) ticket = None if all((report.defendant, report.category, report.service)): msg = 'Looking for opened ticket for (%s, %s, %s)' Logger.debug(unicode(msg % (report.defendant.customerId, report.category.name, report.service.name))) ticket = database.search_ticket(report.defendant, report.category, report.service) # Checking specific processing workflow is_workflow_applied = False for workflow in ReportWorkflowFactory.instance.registered_instances: if workflow.identify(report, ticket, is_trusted=trusted): is_workflow_applied = workflow.apply(report, ticket, trusted, no_phishtocheck) if is_workflow_applied: database.set_report_specificworkflow_tag(report, str(workflow.__class__.__name__)) Logger.debug(unicode('Specific workflow %s applied' % str(workflow.__class__.__name__))) break if is_workflow_applied: continue # If attach report only and no ticket found, continue if not ticket and attach_only: report.status = 'Archived' report.save() continue # Create ticket if trusted new_ticket = False if not ticket and trusted: ticket = database.create_ticket(report.defendant, report.category, report.service, priority=report.provider.priority) new_ticket = True if ticket: report.ticket = Ticket.objects.get(id=ticket.id) report.status = 'Attached' report.save() database.set_ticket_higher_priority(report.ticket) database.log_action_on_ticket( ticket=ticket, action='attach_report', report=report, new_ticket=new_ticket ) return created_reports
def __create_contact_tickets(services, campaign_name, ip_address, category, email_subject, email_body, user): # Create fake report report_subject = 'Campaign %s for ip %s' % (campaign_name, ip_address) report_body = 'Campaign: %s\nIP Address: %s\n' % (campaign_name, ip_address) filename = hashlib.sha256(report_body.encode('utf-8')).hexdigest() __save_email(filename, report_body) for data in services: # For identified (service, defendant, items) tuple actions = [] # Create report report = Report.objects.create(**{ 'provider': database.get_or_create_provider('mass_contact'), 'receivedDate': datetime.now(), 'subject': report_subject, 'body': report_body, 'category': category, 'filename': filename, 'status': 'Archived', 'defendant': database.get_or_create_defendant(data['defendant']), 'service': database.get_or_create_service(data['service']), }) database.log_new_report(report) # Create item item_dict = {'itemType': 'IP', 'report_id': report.id, 'rawItem': ip_address} item_dict.update(utils.get_reverses_for_item(ip_address, nature='IP')) ReportItem.objects.create(**item_dict) # Create ticket ticket = database.create_ticket( report.defendant, report.category, report.service, priority=report.provider.priority, attach_new=False, ) database.add_mass_contact_tag(ticket, campaign_name) actions.append({'ticket': ticket, 'action': 'create_masscontact', 'campaign_name': campaign_name}) actions.append({'ticket': ticket, 'action': 'change_treatedby', 'new_value': user.username}) report.ticket = ticket report.save() Logger.debug(unicode( 'ticket %d successfully created for (%s, %s)' % (ticket.id, report.defendant.customerId, report.service.name) )) # Send email to defendant __send_mass_contact_email(ticket, email_subject, email_body) actions.append({'ticket': ticket, 'action': 'send_email', 'email': report.defendant.details.email}) # Close ticket/report ticket.resolution = Resolution.objects.get(codename=settings.CODENAMES['fixed_customer']) ticket.previousStatus = ticket.status ticket.status = 'Closed' ticket.save() actions.append({ 'ticket': ticket, 'action': 'change_status', 'previous_value': ticket.previousStatus, 'new_value': ticket.status, 'close_reason': ticket.resolution.codename }) for action in actions: database.log_action_on_ticket(**action)
def apply_action(ticket_id=None, action_id=None, ip_addr=None, user_id=None): """ Apply given action on customer service :param int ticket_id: The id of the Cerberus `Ticket` :param int action_id: The id of the Cerberus `ServiceAction` :param int user_id: The id of the Cerberus `User` :rtype: bool :returns: if action has been applied """ current_job = get_current_job() # Checking conformance if not all((ticket_id, action_id, user_id)): msg = 'Invalid parameters submitted [ticket_id=%d, action_id=%s, user_id=%s]' Logger.error(unicode(msg % (ticket_id, action_id, user_id))) return False # Fetching Django model object Logger.info(unicode('Starting process ticket %d with params [%d]' % (ticket_id, action_id))) try: ticket = Ticket.objects.get(id=ticket_id) user = User.objects.get(id=user_id) except (ObjectDoesNotExist, ValueError): Logger.error(unicode('Ticket %d or user %d cannot be found in DB. Skipping...' % (ticket_id, user_id))) return False if ticket.status in ['Closed', 'Answered']: __cancel_by_status(ticket) ticket.previousStatus = ticket.status ticket.status = 'ActionError' ticket.save() database.log_action_on_ticket( ticket=ticket, action='change_status', user=user, previous_value=ticket.previousStatus, new_value=ticket.status, ) return False # Call action service try: result = ImplementationFactory.instance.get_singleton_of( 'ActionServiceBase' ).apply_action_on_service( ticket_id, action_id, ip_addr, user.id ) _update_job(current_job.id, todo_id=result.todo_id, status=result.status, comment=result.comment) return True except ActionServiceException as ex: Logger.info(unicode('Service Action not apply for ticket %d' % (ticket_id))) _update_job(current_job.id, status='actionError', comment=str(ex)) ticket.previousStatus = ticket.status ticket.status = 'ActionError' ticket.save() database.log_action_on_ticket( ticket=ticket, action='change_status', user=user, previous_value=ticket.previousStatus, new_value=ticket.status, ) return False
def create_ticket_from_phishtocheck(report=None, user=None): """ Create/attach report to ticket + block_url + mail to defendant + email to provider :param int report: The id of the `abuse.models.Report` :param int user: The id of the `abuse.models.User` """ if not isinstance(report, Report): try: report = Report.objects.get(id=report) except (AttributeError, ObjectDoesNotExist, TypeError, ValueError): Logger.error(unicode('Report %d cannot be found in DB. Skipping...' % (report))) return if not isinstance(user, User): try: user = User.objects.get(id=user) except (AttributeError, ObjectDoesNotExist, TypeError, ValueError): Logger.error(unicode('User %d cannot be found in DB. Skipping...' % (user))) return # Create/attach to ticket ticket = database.search_ticket(report.defendant, report.category, report.service) new_ticket = False if not ticket: ticket = database.create_ticket(report.defendant, report.category, report.service, priority=report.provider.priority) new_ticket = True utils.scheduler.enqueue_in( timedelta(seconds=settings.GENERAL_CONFIG['phishing']['wait']), 'ticket.timeout', ticket_id=ticket.id, timeout=3600, ) common.get_temp_proofs(ticket, only_urls=True) report.ticket = ticket report.status = 'Attached' report.save() database.log_action_on_ticket( ticket=ticket, action='attach_report', report=report, new_ticket=new_ticket ) database.log_action_on_ticket( ticket=ticket, action='validate_phishtocheck', user=user, report=report ) # Sending email to provider if settings.TAGS['no_autoack'] not in report.provider.tags.all().values_list('name', flat=True): common.send_email( ticket, [report.provider.email], settings.CODENAMES['ack_received'], acknowledged_report_id=report.id, ) utils.default_queue.enqueue('phishing.block_url_and_mail', ticket_id=ticket.id, report_id=report.id) return ticket