getHeader() public method

Retrieve a specific Email Header
public getHeader ( string $name ) : string
$name string Header name (case-insensitive)
return string
Example #1
0
 /**
  * Create and return a Parser class and it's configuration
  * @param  \PhpMimeMailParser\Parser $parsedMail
  * @param  array $arfMail
  * @return object parser
  */
 public static function create($parsedMail, $arfMail)
 {
     /**
      * Loop through the parser list and try to find a match by
      * validating the send or the body according to the parsers'
      * configuration.
      */
     $parsers = Factory::getParsers();
     foreach ($parsers as $parserName) {
         $parserClass = 'AbuseIO\\Parsers\\' . $parserName;
         // Parser is enabled, see if we can match it's sender_map or body_map
         if (config("parsers.{$parserName}.parser.enabled") === true) {
             // Check validity of the 'report_file' setting before we continue
             // If no report_file is used, continue w/o validation
             $report_file = config("parsers.{$parserName}.parser.report_file");
             if ($report_file == null || is_string($report_file) && isValidRegex($report_file)) {
                 $isValidReport = true;
             } else {
                 $isValidReport = false;
                 Log::warning('AbuseIO\\Parsers\\Factory: ' . "The parser {$parserName} has an invalid value for 'report_file' (not a regex).");
                 break;
             }
             // Check the sender address
             foreach (config("parsers.{$parserName}.parser.sender_map") as $senderMap) {
                 if (isValidRegex($senderMap)) {
                     if (preg_match($senderMap, $parsedMail->getHeader('from')) && $isValidReport) {
                         return new $parserClass($parsedMail, $arfMail);
                     }
                 } else {
                     Log::warning('AbuseIO\\Parsers\\Factory: ' . "The parser {$parserName} has an invalid value for 'sender_map' (not a regex).");
                 }
             }
             // If no valid sender is found, check the body
             foreach (config("parsers.{$parserName}.parser.body_map") as $bodyMap) {
                 if (isValidRegex($bodyMap)) {
                     if (preg_match($bodyMap, $parsedMail->getMessageBody()) && $isValidReport) {
                         return new $parserClass($parsedMail, $arfMail);
                     }
                     if ($arfMail !== false) {
                         foreach ($arfMail as $mailPart) {
                             if (preg_match($bodyMap, $mailPart)) {
                                 return new $parserClass($parsedMail, $arfMail);
                             }
                         }
                     }
                 } else {
                     Log::warning('AbuseIO\\Parsers\\Factory: ' . "The parser {$parserName} has an invalid value for 'body_map' (not a regex).");
                 }
             }
         } else {
             Log::info('AbuseIO\\Parsers\\Factory: ' . "The parser {$parserName} has been disabled and will not be used for this message.");
         }
     }
     // No valid parsers found
     return false;
 }
 /**
  * @dataProvider provideData
  */
 public function testFromStream($mid, $subjectExpected, $fromExpected, $toExpected, $textExpected, $htmlExpected, $attachmentsExpected, $countEmbeddedExpected)
 {
     //Init
     $file = __DIR__ . '/mails/' . $mid;
     $attach_dir = __DIR__ . '/mails/attach_' . $mid . '/';
     //Load From Path
     $Parser = new Parser();
     $Parser->setStream(fopen($file, 'r'));
     //Test Header : subject
     $this->assertEquals($subjectExpected, $Parser->getHeader('subject'));
     $this->assertArrayHasKey('subject', $Parser->getHeaders());
     //Test Header : from
     $this->assertEquals($fromExpected, $Parser->getHeader('from'));
     $this->assertArrayHasKey('from', $Parser->getHeaders());
     //Test Header : to
     $this->assertEquals($toExpected, $Parser->getHeader('to'));
     $this->assertArrayHasKey('to', $Parser->getHeaders());
     //Test Invalid Header
     $this->assertFalse($Parser->getHeader('azerty'));
     $this->assertArrayNotHasKey('azerty', $Parser->getHeaders());
     //Test  Body : text
     if ($textExpected[0] == 'COUNT') {
         $this->assertEquals($textExpected[1], substr_count($Parser->getMessageBody('text'), $textExpected[2]));
     } elseif ($textExpected[0] == 'MATCH') {
         $this->assertEquals($textExpected[1], $Parser->getMessageBody('text'));
     }
     //Test Body : html
     if ($htmlExpected[0] == 'COUNT') {
         $this->assertEquals($htmlExpected[1], substr_count($Parser->getMessageBody('html'), $htmlExpected[2]));
     } elseif ($htmlExpected[0] == 'MATCH') {
         $this->assertEquals($htmlExpected[1], $Parser->getMessageBody('html'));
     }
     //Test Nb Attachments
     $attachments = $Parser->getAttachments();
     $this->assertEquals(count($attachmentsExpected), count($attachments));
     $iterAttachments = 0;
     //Test Attachments
     $attachmentsEmbeddedToCheck = array();
     if (count($attachmentsExpected) > 0) {
         //Save attachments
         $Parser->saveAttachments($attach_dir);
         foreach ($attachmentsExpected as $attachmentExpected) {
             //Test Exist Attachment
             $this->assertTrue(file_exists($attach_dir . $attachmentExpected[0]));
             //Test Filename Attachment
             $this->assertEquals($attachmentExpected[0], $attachments[$iterAttachments]->getFilename());
             //Test Size Attachment
             $this->assertEquals($attachmentExpected[1], filesize($attach_dir . $attachments[$iterAttachments]->getFilename()));
             //Test Inside Attachment
             if ($attachmentExpected[2] != '' && $attachmentExpected[3] > 0) {
                 $fileContent = file_get_contents($attach_dir . $attachments[$iterAttachments]->getFilename(), FILE_USE_INCLUDE_PATH);
                 $this->assertEquals($attachmentExpected[3], substr_count($fileContent, $attachmentExpected[2]));
                 $this->assertEquals($attachmentExpected[3], substr_count($attachments[$iterAttachments]->getContent(), $attachmentExpected[2]));
             }
             //Test ContentType Attachment
             $this->assertEquals($attachmentExpected[4], $attachments[$iterAttachments]->getContentType());
             //Test ContentDisposition Attachment
             $this->assertEquals($attachmentExpected[5], $attachments[$iterAttachments]->getContentDisposition());
             //Test md5 of Headers Attachment
             $this->assertEquals($attachmentExpected[6], md5(serialize($attachments[$iterAttachments]->getHeaders())));
             //Save embedded Attachments to check
             if ($attachmentExpected[7] != '') {
                 array_push($attachmentsEmbeddedToCheck, $attachmentExpected[7]);
             }
             //Remove Attachment
             unlink($attach_dir . $attachments[$iterAttachments]->getFilename());
             $iterAttachments++;
         }
         //Remove Attachment Directory
         rmdir($attach_dir);
     } else {
         $this->assertFalse($Parser->saveAttachments($attach_dir));
     }
     //Test embedded Attachments
     $htmlEmbedded = $Parser->getMessageBody('htmlEmbedded');
     $this->assertEquals($countEmbeddedExpected, substr_count($htmlEmbedded, "data:"));
     if (!empty($attachmentsEmbeddedToCheck)) {
         foreach ($attachmentsEmbeddedToCheck as $itemExpected) {
             $this->assertEquals(1, substr_count($htmlEmbedded, $itemExpected));
         }
     }
 }
Example #3
0
 /**
  * Return the raw evidence data
  * TODO: Need to fix json evidence. Needs to be treated the same as eml.
  *
  * @return bool|string
  */
 public function getDataAttribute()
 {
     $tempFilesystem = Storage::disk('local_temp');
     if (Storage::exists($this->filename)) {
         $data = Storage::get($this->filename);
         if (is_object(json_decode($data))) {
             // It's json data
             return ['headers' => ['from' => $this->sender, 'subject' => $this->subject], 'message' => json_decode($data), 'files' => []];
         } else {
             // It's a regular email, parse it!
             $cacheDir = $this->getCacheDir();
             if (!$tempFilesystem->exists($cacheDir)) {
                 if (!$tempFilesystem->makeDirectory($cacheDir)) {
                     Log::error(get_class($this) . ': ' . 'Unable to create temp directory: ' . $cacheDir);
                 }
             }
             $email = new MimeParser();
             $email->setText($data);
             foreach ($email->getAttachments() as $index => $attachment) {
                 $tempFilesystem->put("{$cacheDir}/{$attachment->filename}", $attachment->getContent());
                 $fileSizes[$index] = strlen($email->getMessageBody('text'));
             }
             return ['headers' => ['from' => $email->getHeader('from'), 'subject' => $email->getHeader('subject')], 'message' => $email->getMessageBody('text'), 'files' => $email->getAttachments(), 'files_dir' => $cacheDir];
         }
     }
     return false;
 }
Example #4
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);
 }
Example #5
0
 /**
  * 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');
     }
 }
Example #6
0
 /**
  * Execute the command.
  *
  * @return void
  */
 public function handle()
 {
     Log::info(get_class($this) . ': ' . 'Queued worker is starting the processing of email file: ' . $this->filename);
     $rawEmail = Storage::get($this->filename);
     $parsedMail = new MimeParser();
     $parsedMail->setText($rawEmail);
     // Sanity checks
     if (empty($parsedMail->getHeader('from')) || empty($parsedMail->getMessageBody())) {
         Log::warning(get_class($this) . ': ' . 'Missing e-mail headers from and/or empty body: ' . $this->filename);
         $this->exception();
         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(get_class($this) . ': ' . 'Loop prevention: Ignoring email from self ' . Config::get('main.notifications.from_address'));
         $this->exception();
         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(get_class($this) . ': ' . ': No parser available to handle message from : ' . $parsedMail->getHeader('from') . ' with subject: ' . $parsedMail->getHeader('subject'));
         $this->exception();
         return;
     }
     if ($parserResult !== false && $parserResult['errorStatus'] === true) {
         Log::error(get_class($parser) . ': ' . ': Parser has ended with fatal errors ! : ' . $parserResult['errorMessage']);
         $this->exception();
         return;
     } else {
         Log::info(get_class($parser) . ': ' . ': Parser completed with ' . $parserResult['warningCount'] . ' warnings and collected ' . count($parserResult['data']) . ' incidents to save');
     }
     if ($parserResult['warningCount'] !== 0 && Config::get('main.emailparser.notify_on_warnings') === true) {
         Log::error(get_class($this) . ': ' . 'Configuration has warnings set as critical and ' . $parserResult['warningCount'] . ' warnings were detected. Sending alert to administrator');
         $this->exception();
         return;
     }
     /*
      * build evidence model, but wait with saving it
      **/
     $evidence = new Evidence();
     $evidence->filename = $this->filename;
     $evidence->sender = $parsedMail->getHeader('from');
     $evidence->subject = $parsedMail->getHeader('subject');
     /*
      * Call IncidentsProcess to validate, store evidence and save incidents
      */
     $incidentsProcess = new IncidentsProcess($parserResult['data'], $evidence);
     // Only continue if not empty, empty set is acceptable (exit OK)
     if (!$incidentsProcess->notEmpty()) {
         return;
     }
     // Validate the data set
     if (!$incidentsProcess->validate()) {
         $this->exception();
         return;
     }
     // Write the data set to database
     if (!$incidentsProcess->save()) {
         $this->exception();
         return;
     }
     Log::info(get_class($this) . ': ' . 'Queued worker has ended the processing of email file: ' . $this->filename);
 }