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;
78 @Messages ({
"ThunderbirdMboxFileIngestModule.noOpenCase.errMsg=Exception while getting open case."})
84 logger.log(Level.SEVERE,
"Exception while getting open case.", ex);
95 logger.log(Level.SEVERE,
"Exception while getting open case.", ex);
100 if (abstractFile.getKnown().equals(TskData.FileKnown.KNOWN)) {
105 if ((abstractFile.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS)) ||
106 (abstractFile.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.SLACK))) {
110 if ((abstractFile.isFile() ==
false)) {
115 boolean isMbox =
false;
117 byte[] t =
new byte[64];
118 if (abstractFile.getSize() > 64) {
119 int byteRead = abstractFile.read(t, 0, 64);
121 isMbox = MboxParser.isValidMimeTypeMbox(t);
124 }
catch (TskException ex) {
125 logger.log(Level.WARNING, null, ex);
132 if (PstParser.isPstFile(abstractFile)) {
146 @Messages({
"ThunderbirdMboxFileIngestModule.processPst.indexError.message=Failed to index encryption detected artifact for keyword search."})
150 fileName = getTempPath() + File.separator + abstractFile.getName()
151 +
"-" + String.valueOf(abstractFile.getId());
153 logger.log(Level.SEVERE,
"Exception while getting open case.", ex);
156 File file =
new File(fileName);
160 logger.log(Level.WARNING,
"Not enough disk space to write file to disk.");
162 NbBundle.getMessage(this.getClass(),
163 "ThunderbirdMboxFileIngestModule.processPst.errMsg.outOfDiskSpace",
164 abstractFile.getName()));
171 }
catch (IOException ex) {
172 logger.log(Level.WARNING,
"Failed writing pst file to disk.", ex);
176 PstParser parser =
new PstParser(services);
177 PstParser.ParseResult result = parser.parse(file, abstractFile.getId());
179 if (result == PstParser.ParseResult.OK) {
184 logger.log(Level.SEVERE,
"Exception while getting open case.", ex);
188 }
else if (result == PstParser.ParseResult.ENCRYPT) {
191 BlackboardArtifact artifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED);
192 artifact.addAttribute(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME,
EmailParserModuleFactory.getModuleName(), NbBundle.getMessage(this.getClass(),
"ThunderbirdMboxFileIngestModule.encryptionFileLevel")));
199 logger.log(Level.SEVERE,
"Unable to index blackboard artifact " + artifact.getArtifactID(), ex);
203 }
catch (TskCoreException ex) {
204 logger.log(Level.INFO,
"Failed to add encryption attribute to file: {0}", abstractFile.getName());
209 NbBundle.getMessage(
this.getClass(),
"ThunderbirdMboxFileIngestModule.processPst.errProcFile.msg",
210 abstractFile.getName()),
211 NbBundle.getMessage(
this.getClass(),
212 "ThunderbirdMboxFileIngestModule.processPst.errProcFile.details"));
213 logger.log(Level.INFO,
"PSTParser failed to parse {0}", abstractFile.getName());
217 if (file.delete() ==
false) {
218 logger.log(Level.INFO,
"Failed to delete temp file: {0}", file.getName());
221 String errors = parser.getErrors();
222 if (errors.isEmpty() ==
false) {
224 NbBundle.getMessage(
this.getClass(),
"ThunderbirdMboxFileIngestModule.processPst.errProcFile.msg2",
225 abstractFile.getName()), errors);
239 String mboxFileName = abstractFile.getName();
240 String mboxParentDir = abstractFile.getParentPath();
242 String emailFolder =
"";
244 if (mboxParentDir.contains(
"/Mail/")) {
245 emailFolder = mboxParentDir.substring(mboxParentDir.indexOf(
"/Mail/") + 5);
246 }
else if (mboxParentDir.contains(
"/ImapMail/")) {
247 emailFolder = mboxParentDir.substring(mboxParentDir.indexOf(
"/ImapMail/") + 9);
249 emailFolder = emailFolder + mboxFileName;
250 emailFolder = emailFolder.replaceAll(
".sbd",
"");
254 fileName = getTempPath() + File.separator + abstractFile.getName()
255 +
"-" + String.valueOf(abstractFile.getId());
257 logger.log(Level.SEVERE,
"Exception while getting open case.", ex);
260 File file =
new File(fileName);
264 logger.log(Level.WARNING,
"Not enough disk space to write file to disk.");
266 NbBundle.getMessage(
this.getClass(),
"ThunderbirdMboxFileIngestModule.processMBox.errProcFile.msg",
267 abstractFile.getName()),
268 NbBundle.getMessage(
this.getClass(),
269 "ThunderbirdMboxFileIngestModule.processMBox.errProfFile.details"));
275 }
catch (IOException ex) {
276 logger.log(Level.WARNING,
"Failed writing mbox file to disk.", ex);
280 MboxParser parser =
new MboxParser(services, emailFolder);
281 List<EmailMessage> emails = parser.parse(file, abstractFile.getId());
285 logger.log(Level.SEVERE,
"Exception while getting open case.", ex);
289 if (file.delete() ==
false) {
290 logger.log(Level.INFO,
"Failed to delete temp file: {0}", file.getName());
293 String errors = parser.getErrors();
294 if (errors.isEmpty() ==
false) {
296 NbBundle.getMessage(
this.getClass(),
"ThunderbirdMboxFileIngestModule.processMBox.errProcFile.msg2",
297 abstractFile.getName()), errors);
312 File dir =
new File(tmpDir);
313 if (dir.exists() ==
false) {
325 static String getModuleOutputPath() throws NoCurrentCaseException {
326 String outDir = Case.getCurrentCaseThrows().getModuleDirectory() + File.separator
327 + EmailParserModuleFactory.getModuleName();
328 File dir =
new File(outDir);
329 if (dir.exists() ==
false) {
341 static String getRelModuleOutputPath() throws NoCurrentCaseException {
342 return Case.getCurrentCaseThrows().getModuleOutputDirectoryRelativePath() + File.separator
343 + EmailParserModuleFactory.getModuleName();
354 private void processEmails(List<EmailMessage> emails, AbstractFile abstractFile)
throws NoCurrentCaseException {
355 List<AbstractFile> derivedFiles =
new ArrayList<>();
359 for (EmailMessage email : emails) {
360 BlackboardArtifact msgArtifact =
addArtifact(email, abstractFile);
362 if ((msgArtifact != null) && (email.hasAttachment())) {
363 derivedFiles.addAll(
handleAttachments(email.getAttachments(), abstractFile, msgArtifact ));
367 if (derivedFiles.isEmpty() ==
false) {
368 for (AbstractFile derived : derivedFiles) {
386 private List<AbstractFile>
handleAttachments(List<EmailMessage.Attachment> attachments, AbstractFile abstractFile, BlackboardArtifact messageArtifact) {
387 List<AbstractFile> files =
new ArrayList<>();
388 for (EmailMessage.Attachment attach : attachments) {
389 String filename = attach.getName();
390 long crTime = attach.getCrTime();
391 long mTime = attach.getmTime();
392 long aTime = attach.getaTime();
393 long cTime = attach.getcTime();
394 String relPath = attach.getLocalPath();
395 long size = attach.getSize();
396 TskData.EncodingType encodingType = attach.getEncodingType();
400 size, cTime, crTime, aTime, mTime,
true, messageArtifact,
"",
403 }
catch (TskCoreException ex) {
405 NbBundle.getMessage(
this.getClass(),
"ThunderbirdMboxFileIngestModule.handleAttch.errMsg",
406 abstractFile.getName()),
407 NbBundle.getMessage(
this.getClass(),
408 "ThunderbirdMboxFileIngestModule.handleAttch.errMsg.details", filename));
409 logger.log(Level.INFO,
"", ex);
423 Pattern p = Pattern.compile(
"\\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}\\b",
424 Pattern.CASE_INSENSITIVE);
425 Matcher m = p.matcher(input);
426 Set<String> emailAddresses =
new HashSet<String>();
428 emailAddresses.add( m.group());
430 return emailAddresses;
440 @Messages({
"ThunderbirdMboxFileIngestModule.addArtifact.indexError.message=Failed to index email message detected artifact for keyword search."})
441 private BlackboardArtifact
addArtifact(EmailMessage email, AbstractFile abstractFile)
throws NoCurrentCaseException {
442 BlackboardArtifact bbart = null;
443 List<BlackboardAttribute> bbattributes =
new ArrayList<>();
444 String to = email.getRecipients();
445 String cc = email.getCc();
446 String bcc = email.getBcc();
447 String from = email.getSender();
448 long dateL = email.getSentDate();
449 String headers = email.getHeaders();
450 String body = email.getTextBody();
451 String bodyHTML = email.getHtmlBody();
452 String rtf = email.getRtfBody();
453 String subject = email.getSubject();
454 long id = email.getId();
455 String localPath = email.getLocalPath();
457 List<String> senderAddressList =
new ArrayList<>();
458 String senderAddress;
461 AccountFileInstance senderAccountInstance = null;
465 if (senderAddressList.size() == 1) {
466 senderAddress = senderAddressList.get(0);
468 senderAccountInstance = openCase.
getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.EMAIL, senderAddress,
EmailParserModuleFactory.getModuleName(), abstractFile);
470 catch(TskCoreException ex) {
471 logger.log(Level.WARNING,
"Failed to create account for email address " + senderAddress, ex);
475 logger.log(Level.WARNING,
"Failed to find sender address, from = "+ from);
478 List<String> recipientAddresses =
new ArrayList<>();
483 List<AccountFileInstance> recipientAccountInstances =
new ArrayList<>();
484 recipientAddresses.forEach((addr) -> {
486 AccountFileInstance recipientAccountInstance =
487 openCase.
getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.EMAIL, addr,
489 recipientAccountInstances.add(recipientAccountInstance);
491 catch(TskCoreException ex) {
492 logger.log(Level.WARNING,
"Failed to create account for email address " + addr, ex);
506 addEmailAttribute(((
id < 0L) ? NbBundle.getMessage(
this.getClass(),
"ThunderbirdMboxFileIngestModule.notAvail") : String.valueOf(
id)),
507 ATTRIBUTE_TYPE.TSK_MSG_ID, bbattributes);
510 ATTRIBUTE_TYPE.TSK_PATH, bbattributes);
513 addEmailAttribute(bodyHTML, ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_HTML, bbattributes);
519 bbart = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG);
520 bbart.addAttributes(bbattributes);
523 openCase.
getSleuthkitCase().getCommunicationsManager().addRelationships(senderAccountInstance, recipientAccountInstances, bbart,Relationship.Type.MESSAGE, dateL);
529 logger.log(Level.SEVERE,
"Unable to index blackboard artifact " + bbart.getArtifactID(), ex);
532 }
catch (TskCoreException | TskDataException ex) {
533 logger.log(Level.WARNING, null, ex);
539 private void addEmailAttribute(String stringVal, ATTRIBUTE_TYPE attrType, Collection<BlackboardAttribute> bbattributes) {
540 if (stringVal.isEmpty() ==
false) {
544 private void addEmailAttribute(
long longVal, ATTRIBUTE_TYPE attrType, Collection<BlackboardAttribute> bbattributes) {
550 void postErrorMessage(String subj, String details) {
555 IngestServices getServices() {
Set< String > findEmailAddresess(String input)
static final Logger logger
FileManager getFileManager()
String getTempDirectory()
static IngestMessage createErrorMessage(String source, String subject, String detailsHtml)
void addEmailAttribute(String stringVal, ATTRIBUTE_TYPE attrType, Collection< BlackboardAttribute > bbattributes)
BlackboardArtifact addArtifact(EmailMessage email, AbstractFile abstractFile)
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)
void addEmailAttribute(long longVal, ATTRIBUTE_TYPE attrType, Collection< BlackboardAttribute > bbattributes)
ProcessResult processMBox(AbstractFile abstractFile)
static final int DISK_FREE_SPACE_UNKNOWN
void processEmails(List< EmailMessage > emails, 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()