19 package org.sleuthkit.autopsy.thunderbirdparser;
22 import java.io.IOException;
23 import java.util.ArrayList;
24 import java.util.Collection;
25 import java.util.HashSet;
26 import java.util.List;
28 import java.util.logging.Level;
29 import java.util.regex.Matcher;
30 import java.util.regex.Pattern;
31 import org.openide.util.NbBundle;
32 import org.openide.util.NbBundle.Messages;
53 import org.
sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
82 @Messages ({
"ThunderbirdMboxFileIngestModule.noOpenCase.errMsg=Exception while getting open case."})
89 logger.log(Level.SEVERE,
"Exception while getting open case.", ex);
100 logger.log(Level.SEVERE,
"Exception while getting open case.", ex);
105 if (abstractFile.getKnown().equals(TskData.FileKnown.KNOWN)) {
110 if ((abstractFile.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS)) ||
111 (abstractFile.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.SLACK))) {
115 if ((abstractFile.isFile() ==
false)) {
120 boolean isMbox =
false;
122 byte[] t =
new byte[64];
123 if (abstractFile.getSize() > 64) {
124 int byteRead = abstractFile.read(t, 0, 64);
126 isMbox = MboxParser.isValidMimeTypeMbox(t);
129 }
catch (TskException ex) {
130 logger.log(Level.WARNING, null, ex);
137 if (PstParser.isPstFile(abstractFile)) {
141 if (VcardParser.isVcardFile(abstractFile)) {
155 @Messages({
"ThunderbirdMboxFileIngestModule.processPst.indexError.message=Failed to index encryption detected artifact for keyword search."})
159 fileName = getTempPath() + File.separator + abstractFile.getName()
160 +
"-" + String.valueOf(abstractFile.getId());
162 logger.log(Level.SEVERE,
"Exception while getting open case.", ex);
165 File file =
new File(fileName);
169 logger.log(Level.WARNING,
"Not enough disk space to write file to disk.");
171 NbBundle.getMessage(this.getClass(),
172 "ThunderbirdMboxFileIngestModule.processPst.errMsg.outOfDiskSpace",
173 abstractFile.getName()));
180 }
catch (IOException ex) {
181 logger.log(Level.WARNING,
"Failed writing pst file to disk.", ex);
185 PstParser parser =
new PstParser(services);
186 PstParser.ParseResult result = parser.parse(file, abstractFile.getId());
188 if (result == PstParser.ParseResult.OK) {
192 }
else if (result == PstParser.ParseResult.ENCRYPT) {
195 BlackboardArtifact artifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED);
196 artifact.addAttribute(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME,
EmailParserModuleFactory.getModuleName(), NbBundle.getMessage(this.getClass(),
"ThunderbirdMboxFileIngestModule.encryptionFileLevel")));
203 logger.log(Level.SEVERE,
"Unable to index blackboard artifact " + artifact.getArtifactID(), ex);
207 }
catch (TskCoreException ex) {
208 logger.log(Level.INFO,
"Failed to add encryption attribute to file: {0}", abstractFile.getName());
213 NbBundle.getMessage(
this.getClass(),
"ThunderbirdMboxFileIngestModule.processPst.errProcFile.msg",
214 abstractFile.getName()),
215 NbBundle.getMessage(
this.getClass(),
216 "ThunderbirdMboxFileIngestModule.processPst.errProcFile.details"));
217 logger.log(Level.INFO,
"PSTParser failed to parse {0}", abstractFile.getName());
221 if (file.delete() ==
false) {
222 logger.log(Level.INFO,
"Failed to delete temp file: {0}", file.getName());
225 String errors = parser.getErrors();
226 if (errors.isEmpty() ==
false) {
228 NbBundle.getMessage(
this.getClass(),
"ThunderbirdMboxFileIngestModule.processPst.errProcFile.msg2",
229 abstractFile.getName()), errors);
243 String mboxFileName = abstractFile.getName();
244 String mboxParentDir = abstractFile.getParentPath();
246 String emailFolder =
"";
248 if (mboxParentDir.contains(
"/Mail/")) {
249 emailFolder = mboxParentDir.substring(mboxParentDir.indexOf(
"/Mail/") + 5);
250 }
else if (mboxParentDir.contains(
"/ImapMail/")) {
251 emailFolder = mboxParentDir.substring(mboxParentDir.indexOf(
"/ImapMail/") + 9);
253 emailFolder = emailFolder + mboxFileName;
254 emailFolder = emailFolder.replaceAll(
".sbd",
"");
258 fileName = getTempPath() + File.separator + abstractFile.getName()
259 +
"-" + String.valueOf(abstractFile.getId());
261 logger.log(Level.SEVERE,
"Exception while getting open case.", ex);
264 File file =
new File(fileName);
268 logger.log(Level.WARNING,
"Not enough disk space to write file to disk.");
270 NbBundle.getMessage(
this.getClass(),
"ThunderbirdMboxFileIngestModule.processMBox.errProcFile.msg",
271 abstractFile.getName()),
272 NbBundle.getMessage(
this.getClass(),
273 "ThunderbirdMboxFileIngestModule.processMBox.errProfFile.details"));
279 }
catch (IOException ex) {
280 logger.log(Level.WARNING,
"Failed writing mbox file to disk.", ex);
284 MboxParser parser =
new MboxParser(services, emailFolder);
285 List<EmailMessage> emails = parser.parse(file, abstractFile.getId());
288 if (file.delete() ==
false) {
289 logger.log(Level.INFO,
"Failed to delete temp file: {0}", file.getName());
292 String errors = parser.getErrors();
293 if (errors.isEmpty() ==
false) {
295 NbBundle.getMessage(
this.getClass(),
"ThunderbirdMboxFileIngestModule.processMBox.errProcFile.msg2",
296 abstractFile.getName()), errors);
313 "ThunderbirdMboxFileIngestModule.errorMessage.outOfDiskSpace=Out of disk space. Cannot copy '{0}' (id={1}) to parse."
318 fileName = getTempPath() + File.separator + abstractFile.getName()
319 +
"-" + String.valueOf(abstractFile.getId());
321 logger.log(Level.SEVERE,
"Exception while getting open case.", ex);
324 File file =
new File(fileName);
328 logger.log(Level.WARNING, String.format(
"Not enough disk space to write file '%s' (id=%d) to disk.",
329 abstractFile.getName(), abstractFile.getId()));
331 Bundle.ThunderbirdMboxFileIngestModule_errorMessage_outOfDiskSpace(abstractFile.getName(), abstractFile.getId()));
338 }
catch (IOException ex) {
339 logger.log(Level.WARNING, String.format(
"Failed writing the vCard file '%s' (id=%d) to disk.",
340 abstractFile.getName(), abstractFile.getId()), ex);
345 VcardParser parser =
new VcardParser(currentCase, context);
346 parser.parse(file, abstractFile);
348 logger.log(Level.WARNING, String.format(
"Exception while parsing the file '%s' (id=%d).", file.getName(), abstractFile.getId()), ex);
352 if (file.delete() ==
false) {
353 logger.log(Level.INFO,
"Failed to delete temp file: {0}", file.getName());
368 File dir =
new File(tmpDir);
369 if (dir.exists() ==
false) {
382 static String getModuleOutputPath() throws NoCurrentCaseException {
383 String outDir = Case.getCurrentCaseThrows().getModuleDirectory() + File.separator
384 + EmailParserModuleFactory.getModuleName();
385 File dir =
new File(outDir);
386 if (dir.exists() ==
false) {
398 static String getRelModuleOutputPath() throws NoCurrentCaseException {
399 return Case.getCurrentCaseThrows().getModuleOutputDirectoryRelativePath() + File.separator
400 + EmailParserModuleFactory.getModuleName();
410 private void processEmails(List<EmailMessage> emails, AbstractFile abstractFile) {
411 List<AbstractFile> derivedFiles =
new ArrayList<>();
415 for (EmailMessage email : emails) {
418 if ((msgArtifact != null) && (email.hasAttachment())) {
419 derivedFiles.addAll(
handleAttachments(email.getAttachments(), abstractFile, msgArtifact ));
423 if (derivedFiles.isEmpty() ==
false) {
424 for (AbstractFile derived : derivedFiles) {
442 private List<AbstractFile>
handleAttachments(List<EmailMessage.Attachment> attachments, AbstractFile abstractFile, BlackboardArtifact messageArtifact) {
443 List<AbstractFile> files =
new ArrayList<>();
444 for (EmailMessage.Attachment attach : attachments) {
445 String filename = attach.getName();
446 long crTime = attach.getCrTime();
447 long mTime = attach.getmTime();
448 long aTime = attach.getaTime();
449 long cTime = attach.getcTime();
450 String relPath = attach.getLocalPath();
451 long size = attach.getSize();
452 TskData.EncodingType encodingType = attach.getEncodingType();
456 size, cTime, crTime, aTime, mTime,
true, messageArtifact,
"",
459 }
catch (TskCoreException ex) {
461 NbBundle.getMessage(
this.getClass(),
"ThunderbirdMboxFileIngestModule.handleAttch.errMsg",
462 abstractFile.getName()),
463 NbBundle.getMessage(
this.getClass(),
464 "ThunderbirdMboxFileIngestModule.handleAttch.errMsg.details", filename));
465 logger.log(Level.INFO,
"", ex);
479 Pattern p = Pattern.compile(
"\\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}\\b",
480 Pattern.CASE_INSENSITIVE);
481 Matcher m = p.matcher(input);
482 Set<String> emailAddresses =
new HashSet<>();
484 emailAddresses.add( m.group());
486 return emailAddresses;
497 @Messages({
"ThunderbirdMboxFileIngestModule.addArtifact.indexError.message=Failed to index email message detected artifact for keyword search."})
498 private BlackboardArtifact
addEmailArtifact(EmailMessage email, AbstractFile abstractFile) {
499 BlackboardArtifact bbart = null;
500 List<BlackboardAttribute> bbattributes =
new ArrayList<>();
501 String to = email.getRecipients();
502 String cc = email.getCc();
503 String bcc = email.getBcc();
504 String from = email.getSender();
505 long dateL = email.getSentDate();
506 String headers = email.getHeaders();
507 String body = email.getTextBody();
508 String bodyHTML = email.getHtmlBody();
509 String rtf = email.getRtfBody();
510 String subject = email.getSubject();
511 long id = email.getId();
512 String localPath = email.getLocalPath();
514 List<String> senderAddressList =
new ArrayList<>();
515 String senderAddress;
518 AccountFileInstance senderAccountInstance = null;
520 if (senderAddressList.size() == 1) {
521 senderAddress = senderAddressList.get(0);
523 senderAccountInstance = currentCase.
getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.EMAIL, senderAddress,
EmailParserModuleFactory.getModuleName(), abstractFile);
525 catch(TskCoreException ex) {
526 logger.log(Level.WARNING,
"Failed to create account for email address " + senderAddress, ex);
530 logger.log(Level.WARNING,
"Failed to find sender address, from = {0}", from);
533 List<String> recipientAddresses =
new ArrayList<>();
538 List<AccountFileInstance> recipientAccountInstances =
new ArrayList<>();
539 recipientAddresses.forEach((addr) -> {
541 AccountFileInstance recipientAccountInstance =
542 currentCase.
getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.EMAIL, addr,
544 recipientAccountInstances.add(recipientAccountInstance);
546 catch(TskCoreException ex) {
547 logger.log(Level.WARNING,
"Failed to create account for email address " + addr, ex);
551 addArtifactAttribute(headers, ATTRIBUTE_TYPE.TSK_HEADERS, bbattributes);
552 addArtifactAttribute(from, ATTRIBUTE_TYPE.TSK_EMAIL_FROM, bbattributes);
553 addArtifactAttribute(to, ATTRIBUTE_TYPE.TSK_EMAIL_TO, bbattributes);
554 addArtifactAttribute(subject, ATTRIBUTE_TYPE.TSK_SUBJECT, bbattributes);
556 addArtifactAttribute(dateL, ATTRIBUTE_TYPE.TSK_DATETIME_RCVD, bbattributes);
557 addArtifactAttribute(dateL, ATTRIBUTE_TYPE.TSK_DATETIME_SENT, bbattributes);
559 addArtifactAttribute(body, ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_PLAIN, bbattributes);
561 addArtifactAttribute(((
id < 0L) ? NbBundle.getMessage(
this.getClass(),
"ThunderbirdMboxFileIngestModule.notAvail") : String.valueOf(
id)),
562 ATTRIBUTE_TYPE.TSK_MSG_ID, bbattributes);
564 addArtifactAttribute(((localPath.isEmpty() ==
false) ? localPath :
"/foo/bar"),
565 ATTRIBUTE_TYPE.TSK_PATH, bbattributes);
567 addArtifactAttribute(cc, ATTRIBUTE_TYPE.TSK_EMAIL_CC, bbattributes);
568 addArtifactAttribute(bodyHTML, ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_HTML, bbattributes);
569 addArtifactAttribute(rtf, ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_RTF, bbattributes);
574 bbart = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG);
575 bbart.addAttributes(bbattributes);
578 currentCase.
getSleuthkitCase().getCommunicationsManager().addRelationships(senderAccountInstance, recipientAccountInstances, bbart,Relationship.Type.MESSAGE, dateL);
584 logger.log(Level.SEVERE,
"Unable to index blackboard artifact " + bbart.getArtifactID(), ex);
587 }
catch (TskCoreException | TskDataException ex) {
588 logger.log(Level.WARNING, null, ex);
601 static void addArtifactAttribute(String stringVal, BlackboardAttribute.Type attrType, Collection<BlackboardAttribute> bbattributes) {
602 if (stringVal.isEmpty() ==
false) {
614 static void addArtifactAttribute(String stringVal, ATTRIBUTE_TYPE attrType, Collection<BlackboardAttribute> bbattributes) {
615 if (stringVal.isEmpty() ==
false) {
616 bbattributes.add(
new BlackboardAttribute(attrType, EmailParserModuleFactory.getModuleName(), stringVal));
627 static void addArtifactAttribute(
long longVal, ATTRIBUTE_TYPE attrType, Collection<BlackboardAttribute> bbattributes) {
629 bbattributes.add(
new BlackboardAttribute(attrType, EmailParserModuleFactory.getModuleName(), longVal));
639 void postErrorMessage(String subj, String details) {
640 IngestMessage ingestMessage = IngestMessage.createErrorMessage(EmailParserModuleFactory.getModuleVersion(), subj, details);
649 IngestServices getServices() {
Set< String > findEmailAddresess(String input)
static final Logger logger
FileManager getFileManager()
String getTempDirectory()
static IngestMessage createErrorMessage(String source, String subject, String detailsHtml)
BlackboardArtifact addEmailArtifact(EmailMessage email, AbstractFile abstractFile)
final IngestServices services
static< T > long writeToFile(Content content, java.io.File outputFile, ProgressHandle progress, Future< T > worker, boolean source)
synchronized DerivedFile addDerivedFile(String fileName, String localPath, long size, long ctime, long crtime, long atime, long mtime, boolean isFile, Content parentObj, String rederiveDetails, String toolName, String toolVersion, String otherDetails, TskData.EncodingType encodingType)
ProcessResult processMBox(AbstractFile abstractFile)
static final int DISK_FREE_SPACE_UNKNOWN
void processEmails(List< EmailMessage > emails, AbstractFile abstractFile)
ProcessResult processVcard(AbstractFile abstractFile)
void addFilesToJob(List< AbstractFile > files)
void postMessage(final IngestMessage message)
void fireModuleDataEvent(ModuleDataEvent moduleDataEvent)
ProcessResult process(AbstractFile abstractFile)
SleuthkitCase getSleuthkitCase()
ProcessResult processPst(AbstractFile abstractFile)
void startUp(IngestJobContext context)
Blackboard getBlackboard()
void fireModuleContentEvent(ModuleContentEvent moduleContentEvent)
static void error(String title, String message)
synchronized void indexArtifact(BlackboardArtifact artifact)
synchronized static Logger getLogger(String name)
static Case getCurrentCaseThrows()
List< AbstractFile > handleAttachments(List< EmailMessage.Attachment > attachments, AbstractFile abstractFile, BlackboardArtifact messageArtifact)
static synchronized IngestServices getInstance()