/**
  * Wrapper for save data.
  *
  * @return bool
  */
 public function save()
 {
     /*
      * save evidence into table
      **/
     $this->evidence->save();
     /*
      * call saver
      **/
     $saver = new IncidentsSave();
     $saverResult = $saver->save($this->incidents, $this->evidence->id);
     /*
      * We've hit a snag, so we are gracefully killing ourselves
      * after we contact the admin about it. IncidentsSave should never
      * end with problems unless the mysql died while doing transactions
      **/
     if ($saverResult['errorStatus'] === true) {
         Log::error(get_class($saver) . ': ' . 'Saver has ended with errors ! : ' . $saverResult['errorMessage']);
         return false;
     }
     $linkedEvents = Event::where('evidence_id', '=', $this->evidence->id);
     if ($linkedEvents->count() == 0) {
         Log::info(get_class($saver) . ': ' . 'The evidence submitted was never linked to any ticket, thus removing it from the DB again');
         $this->evidence->forceDelete();
     }
     Log::info(get_class($saver) . ': ' . 'Saver has ended without errors');
     return true;
 }
 /**
  * Download a specific attachment.
  *
  * @param \AbuseIO\Models\Evidence $evidence
  * @param string                   $filename [description]
  *
  * @return \Illuminate\Http\Response
  */
 public function attachment(Evidence $evidence, $filename)
 {
     if ($attachment = $evidence->getAttachment($filename)) {
         return response($attachment->getContent(), 200)->header('Content-Type', $attachment->getContentType())->header('Content-Transfer-Encoding', 'Binary')->header('Content-Disposition', "attachment; filename=\"{$filename}\"");
     } else {
         return abort(404);
     }
 }
Beispiel #3
0
 /**
  * Walk thru mailarchive to see which need pruning
  *
  * @return boolean
  */
 private function mailarchivePruning()
 {
     $deleteOlderThen = strtotime(config('main.housekeeping.mailarchive_remove_after') . " ago");
     $validator = Validator::make(['mailarchive_remove_after' => $deleteOlderThen], ['mailarchive_remove_after' => 'required|timestamp']);
     if ($validator->fails()) {
         $messages = $validator->messages();
         $message = '';
         foreach ($messages->all() as $messagePart) {
             $message .= $messagePart . PHP_EOL;
         }
         echo $message;
         return false;
     } else {
         $evidences = Evidence::where('created_at', '<=', date('Y-m-d H:i:s', $deleteOlderThen))->get();
         $filesystem = new Filesystem();
         foreach ($evidences as $evidence) {
             $path = storage_path() . '/mailarchive/';
             $filesystem->delete($path . $evidence->filename);
             $evidence->delete();
         }
     }
     return true;
 }
Beispiel #4
0
 /**
  * Downloads the evidence for this ticket as EML
  *
  * @param Ticket $ticket        Ticket Model
  * @param integer $evidenceId
  * @return \Illuminate\Http\Response
  */
 public function downloadEvidence(Ticket $ticket, $evidenceId)
 {
     $evidence = Evidence::find($evidenceId);
     if (!$evidence) {
         return Redirect::route('admin.tickets.show', $ticket->id)->with('message', 'The evidence is no longer available for this event.');
     }
     if (is_file($evidence->filename)) {
         $evidenceData = file_get_contents($evidence->filename);
         $outputFilename = "ticket_{$ticket->id}_evidence_{$evidenceId}.eml";
         return response($evidenceData, 200)->header('Content-Type', 'message/rfc822')->header('Content-Transfer-Encoding', 'Binary')->header('Content-Disposition', 'attachment; filename="' . $outputFilename . '"');
     } else {
         return Redirect::route('admin.tickets.show', $ticket->id)->with('message', 'ERROR: The file was not available on the filesystem.');
     }
 }
Beispiel #5
0
 /**
  * Execute the command
  *
  * @return void
  */
 public function handle()
 {
     Log::info('(JOB ' . getmypid() . ') ' . get_class($this) . ': ' . 'Queued worker is starting the processing of email file: ' . $this->filename);
     $filesystem = new Filesystem();
     $rawEmail = $filesystem->get($this->filename);
     $parsedMail = new MimeParser();
     $parsedMail->setText($rawEmail);
     // Sanity checks
     if (empty($parsedMail->getHeader('from')) || empty($parsedMail->getMessageBody())) {
         Log::warning('(JOB ' . getmypid() . ') ' . get_class($this) . ': ' . 'Missing e-mail headers from and/or empty body: ' . $this->filename);
         $this->alertAdmin();
         return;
     }
     // Ignore email from our own notification address to prevent mail loops
     if (preg_match('/' . Config::get('main.notifications.from_address') . '/', $parsedMail->getHeader('from'))) {
         Log::warning('(JOB ' . getmypid() . ') ' . get_class($this) . ': ' . 'Loop prevention: Ignoring email from self ' . Config::get('main.notifications.from_address'));
         $this->alertAdmin();
         return;
     }
     // Start with detecting valid ARF e-mail
     $attachments = $parsedMail->getAttachments();
     $arfMail = [];
     foreach ($attachments as $attachment) {
         if ($attachment->contentType == 'message/feedback-report') {
             $arfMail['report'] = $attachment->getContent();
         }
         if ($attachment->contentType == 'message/rfc822') {
             $arfMail['evidence'] = utf8_encode($attachment->getContent());
         }
         if ($attachment->contentType == 'text/plain') {
             $arfMail['message'] = $attachment->getContent();
         }
     }
     /*
      * Sometimes the mime header does not set the main message correctly. This is ment as a fallback and will
      * use the original content body (which is basicly the same mime element). But only fallback if we actually
      * have a RFC822 message with a feedback report.
      */
     if (empty($arfMail['message']) && isset($arfMail['report']) && isset($arfMail['evidence'])) {
         $arfMail['message'] = $parsedMail->getMessageBody();
     }
     // If we do not have a complete e-mail, then we empty the perhaps partially filled arfMail
     // which is useless, hence reset to false
     if (!isset($arfMail['report']) || !isset($arfMail['evidence']) || !isset($arfMail['message'])) {
         $arfMail = false;
     }
     // Asking ParserFactory for an object based on mappings, or die trying
     $parser = ParserFactory::create($parsedMail, $arfMail);
     if ($parser !== false) {
         $parserResult = $parser->parse();
     } else {
         Log::error('(JOB ' . getmypid() . ') ' . get_class($this) . ': ' . ': No parser available to handle message from : ' . $parsedMail->getHeader('from') . ' with subject: ' . $parsedMail->getHeader('subject'));
         $this->alertAdmin();
         return;
     }
     if ($parserResult !== false && $parserResult['errorStatus'] === true) {
         Log::error('(JOB ' . getmypid() . ') ' . get_class($parser) . ': ' . ': Parser has ended with fatal errors ! : ' . $parserResult['errorMessage']);
         $this->alertAdmin();
         return;
     } else {
         Log::info('(JOB ' . getmypid() . ') ' . get_class($parser) . ': ' . ': Parser completed with ' . $parserResult['warningCount'] . ' warnings and collected ' . count($parserResult['data']) . ' events to save');
     }
     if ($parserResult['warningCount'] !== 0 && Config::get('main.emailparser.notify_on_warnings') === true) {
         Log::error('(JOB ' . getmypid() . ') ' . get_class($this) . ': ' . 'Configuration has warnings set as critical and ' . $parserResult['warningCount'] . ' warnings were detected. Sending alert to administrator');
         $this->alertAdmin();
         return;
     }
     if (count($parserResult['data']) !== 0) {
         // Call validator
         $validator = new EventsValidate();
         $validatorResult = $validator->check($parserResult['data']);
         if ($validatorResult['errorStatus'] === true) {
             Log::error('(JOB ' . getmypid() . ') ' . get_class($validator) . ': ' . 'Validator has ended with errors ! : ' . $validatorResult['errorMessage']);
             $this->alertAdmin();
             return;
         } else {
             Log::info('(JOB ' . getmypid() . ') ' . get_class($validator) . ': ' . 'Validator has ended without errors');
         }
         /**
          * save evidence into table
          **/
         $evidence = new Evidence();
         $evidence->filename = $this->filename;
         $evidence->sender = $parsedMail->getHeader('from');
         $evidence->subject = $parsedMail->getHeader('subject');
         $evidence->save();
         /**
          * call saver
          **/
         $saver = new EventsSave();
         $saverResult = $saver->save($parserResult['data'], $evidence->id);
         /**
          * We've hit a snag, so we are gracefully killing ourselves
          * after we contact the admin about it. EventsSave should never
          * end with problems unless the mysql died while doing transactions
          **/
         if ($saverResult['errorStatus'] === true) {
             Log::error('(JOB ' . getmypid() . ') ' . get_class($saver) . ': ' . 'Saver has ended with errors ! : ' . $saverResult['errorMessage']);
             $this->alertAdmin();
             return;
         } else {
             Log::info('(JOB ' . getmypid() . ') ' . get_class($saver) . ': ' . 'Saver has ended without errors');
         }
     } else {
         Log::warning('(JOB ' . getmypid() . ') ' . get_class($this) . ': ' . 'Parser did not return any events therefore skipping validation and saving a empty event set');
     }
     Log::info('(JOB ' . getmypid() . ') ' . get_class($this) . ': ' . 'Queued worker has ended the processing of email file: ' . $this->filename);
 }
 /**
  * Execute the command.
  *
  * @return void
  */
 public function handle()
 {
     Log::info(get_class($this) . ': Queued worker is starting the processing of email file: ' . $this->filename);
     $filesystem = new Filesystem();
     $rawEmail = $filesystem->get($this->filename);
     $parsedMail = new MimeParser();
     $parsedMail->setText($rawEmail);
     // Sanity checks
     if (empty($parsedMail->getHeader('from')) || empty($parsedMail->getMessageBody())) {
         Log::warning(get_class($this) . 'Validation failed on: ' . $this->filename);
         $this->exception();
     }
     // Ignore email from our own notification address to prevent mail loops
     if (preg_match('/' . Config::get('main.notifications.from_address') . '/', $parsedMail->getHeader('from'))) {
         Log::warning(get_class($this) . 'Loop prevention: Ignoring email from self ' . Config::get('main.notifications.from_address'));
         $this->exception();
     }
     // Start with detecting valid ARF e-mail
     $attachments = $parsedMail->getAttachments();
     $arfMail = [];
     foreach ($attachments as $attachment) {
         if ($attachment->contentType == 'message/feedback-report') {
             $arfMail['report'] = $attachment->getContent();
         }
         if ($attachment->contentType == 'message/rfc822') {
             $arfMail['evidence'] = $attachment->getContent();
         }
         if ($attachment->contentType == 'text/plain') {
             $arfMail['message'] = $attachment->getContent();
         }
     }
     // If we do not have a complete e-mail, then we empty the perhaps partially filled arfMail
     // which is useless, hence reset to false
     if (!isset($arfMail['report']) || !isset($arfMail['evidence']) || !isset($arfMail['message'])) {
         $arfMail = false;
     }
     // Asking GetParser for an object based on mappings, or die trying
     $parser = GetParser::object($parsedMail, $arfMail);
     $result = false;
     $events = false;
     if ($parser !== false) {
         $result = $parser->parse();
     } else {
         Log::error(get_class($this) . ': Unable to handle message from: ' . $parsedMail->getHeader('from') . ' with subject: ' . $parsedMail->getHeader('subject'));
         $this->exception();
     }
     if ($result !== false && $result['errorStatus'] !== true) {
         Log::info(get_class($parser) . ': Parser as ended without errors. Collected ' . count($result['data']) . ' events to save');
         $events = $result['data'];
     } else {
         Log::error(get_class($parser) . ': Parser as ended with errors ! : ' . $result['errorMessage']);
         $this->exception();
     }
     // call validater
     $validator = new EventsValidate($events);
     $return = $validator->handle();
     if ($return['errorStatus'] === false) {
         Log::error(get_class($validator) . ': Validator as ended with errors ! : ' . $result['errorMessage']);
         $this->exception();
     } else {
         Log::info(get_class($validator) . ': Validator as ended without errors');
     }
     // save evidence into table
     $evidence = new Evidence();
     $evidence->filename = $this->filename;
     $evidence->sender = $parsedMail->getHeader('from');
     $evidence->subject = $parsedMail->getHeader('subject');
     $evidence->save();
     // call saver
     $saver = new EventsSave($events, $evidence->id);
     $return = $saver->handle();
     if ($return['errorStatus'] === false) {
         Log::error(get_class($saver) . ': Saver as ended with errors ! : ' . $result['errorMessage']);
         $this->exception();
     } else {
         Log::info(get_class($saver) . ': Saver as ended without errors');
     }
 }
 /**
  * @param $ticket
  * @param $account
  */
 private function replayTicket($ticket, $account)
 {
     // Create the ticket as usual
     $newTicket = $this->createTicket($ticket, $account);
     // Now this is the little magic, we need to calculate the offset and make sure that the first
     // and lastseen moments exactly match and the increments between those events are within that
     // same timeframe, but NOT duplicate.
     $firstSeen = (int) $ticket->FirstSeen;
     $lastSeen = (int) $ticket->LastSeen;
     $elapsed = $lastSeen - $firstSeen;
     $step = (int) round($elapsed / $ticket->ReportCount);
     $offset = ['first' => $firstSeen, 'last' => $lastSeen, 'elapsed' => $elapsed, 'step' => $step];
     for ($counter = 0; $counter <= $ticket->ReportCount; $counter++) {
         $offset[$counter] = $firstSeen + $counter * $step;
     }
     // Make sure we end at the right point in time
     end($offset);
     $key = key($offset);
     $offset[$key] = $lastSeen;
     // Now recreate all the events
     for ($counter = 0; $counter <= $ticket->ReportCount; $counter++) {
         // Build new evidence file and write the evidence into the archive
         $evidence = new EvidenceSave();
         $evidenceData = ['createdBy' => '*****@*****.**', 'receivedOn' => time(), 'submittedData' => json_decode(json_encode($ticket), true), 'attachments' => []];
         if (!empty($attachment)) {
             $evidenceData['attachments'][0] = $attachment;
         }
         $evidenceFile = $evidence->save(json_encode($evidenceData));
         // Save the file reference into the database
         $evidenceSave = new Evidence();
         $evidenceSave->filename = $evidenceFile;
         $evidenceSave->sender = '*****@*****.**';
         $evidenceSave->subject = 'Migrated evidence with a little magic';
         $evidenceSave->save();
         // Write the event
         $newEvent = new Event();
         $newEvent->evidence_id = $evidenceSave->id;
         $newEvent->information = $ticket->Information;
         $newEvent->source = $ticket->Source;
         $newEvent->ticket_id = $newTicket->id;
         $newEvent->timestamp = $offset[$counter];
         // Validate the model before saving
         $validator = Validator::make(json_decode(json_encode($newEvent), true), Event::createRules());
         if ($validator->fails()) {
             $this->error('DevError: Internal validation failed when saving the Event object ' . implode(' ', $validator->messages()->all()));
             $this->exception();
         }
         $newEvent->save();
     }
 }
Beispiel #8
0
 public function testBelongsToRelation()
 {
     $this->initDB();
     $this->assertEquals(Evidence::find($this->evidenceId), Event::find($this->eventId)->evidence);
 }
Beispiel #9
0
 /**
  * Testing the events() method on the model.
  */
 public function testHasManyEvents()
 {
     $this->initDB();
     $this->assertTrue(Evidence::find($this->evidenceId)->events->contains(Event::find($this->eventId)->id));
 }
Beispiel #10
0
 /**
  * Execute the command
  *
  * @return boolean
  */
 public function handle()
 {
     Log::info(get_class($this) . ': ' . 'Queued worker is starting the collector: ' . $this->collector);
     $collector = collectorFactory::create($this->collector);
     if (!$collector) {
         Log::error("The requested collector {$this->collector} could not be started check logs for PID:" . getmypid());
         $this->exception();
     }
     $collectorResult = $collector->parse();
     if ($collectorResult['errorStatus'] == true) {
         Log::error("The requested collector {$this->collector} returned an error. check logs for PID:" . getmypid());
         $this->exception();
     }
     if (count($collectorResult['data']) !== 0) {
         // Call validator
         $validator = new EventsValidate();
         $validatorResult = $validator->check($collectorResult['data']);
         if ($validatorResult['errorStatus'] === true) {
             Log::error(get_class($validator) . ': ' . 'Validator has ended with errors ! : ' . $validatorResult['errorMessage']);
             $this->exception();
             return;
         } else {
             Log::info(get_class($validator) . ': ' . 'Validator has ended without errors');
         }
         /**
          * save evidence onto disk
          */
         $filesystem = new Filesystem();
         $datefolder = Carbon::now()->format('Ymd');
         $path = storage_path() . '/mailarchive/' . $datefolder . '/';
         $file = Uuid::generate(4) . '.eml';
         $filename = $path . $file;
         if (!$filesystem->isDirectory($path)) {
             // If a datefolder does not exist, then create it or die trying
             if (!$filesystem->makeDirectory($path)) {
                 Log::error(get_class($this) . ': ' . 'Unable to create directory: ' . $path);
                 $this->exception();
             }
             chown($path, 'abuseio');
             chgrp($path, 'abuseio');
         }
         if ($filesystem->isFile($filename)) {
             Log::error(get_class($this) . ': ' . 'File aready exists: ' . $filename);
             $this->exception();
         }
         if ($filesystem->put($filename, json_encode(['collectorName' => $this->collector, 'collectorData' => $collectorResult])) === false) {
             Log::error(get_class($this) . ': ' . 'Unable to write file: ' . $filename);
             $this->exception();
         }
         chown($path . $filename, 'abuseio');
         chgrp($path . $filename, 'abuseio');
         /**
          * save evidence into table
          **/
         $evidence = new Evidence();
         $evidence->filename = $filename;
         $evidence->sender = 'abuse@localhost';
         $evidence->subject = "CLI Collector {$this->collector}";
         $evidence->save();
         /**
          * call saver
          **/
         $saver = new EventsSave();
         $saverResult = $saver->save($collectorResult['data'], $evidence->id);
         /**
          * We've hit a snag, so we are gracefully killing ourselves
          * after we contact the admin about it. EventsSave should never
          * end with problems unless the mysql died while doing transactions
          **/
         if ($saverResult['errorStatus'] === true) {
             Log::error(get_class($saver) . ': ' . 'Saver has ended with errors ! : ' . $saverResult['errorMessage']);
             $this->exception();
             return;
         } else {
             Log::info(get_class($saver) . ': ' . 'Saver has ended without errors');
         }
     } else {
         Log::warning(get_class($this) . ': ' . 'Collector did not return any events therefore skipping validation and saving a empty event set');
     }
     Log::info(get_class($this) . ': ' . 'Queued worker has ended the processing of collector: ' . $this->collector);
 }