mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-06 21:00:22 +00:00
VCard support added.
This commit is contained in:
parent
0394807018
commit
2f8bcf2a7a
@ -7,8 +7,11 @@
|
||||
|
||||
</configurations>
|
||||
<dependencies>
|
||||
<dependency conf="autopsy->default" org="org.apache.commons" name="commons-lang3" rev="3.8.1"/>
|
||||
<dependency conf="autopsy->default" org="org.apache.james" name="apache-mime4j-core" rev="0.8.0"/>
|
||||
<dependency conf="autopsy->default" org="org.apache.james" name="apache-mime4j-dom" rev="0.8.0"/>
|
||||
<dependency conf="autopsy->default" org="org.apache.james" name="apache-mime4j-mbox-iterator" rev="0.8.0"/>
|
||||
<dependency conf="autopsy->default" org="com.googlecode.ez-vcard" name="ez-vcard" rev="0.10.5"/>
|
||||
<dependency conf="autopsy->default" org="com.github.mangstadt" name="vinnie" rev="2.0.2"/>
|
||||
</dependencies>
|
||||
</ivy-module>
|
||||
|
@ -1,7 +1,10 @@
|
||||
file.reference.commons-lang3-3.8.1.jar=release/modules/ext/commons-lang3-3.8.1.jar
|
||||
file.reference.apache-mime4j-core-0.8.0.jar=release/modules/ext/apache-mime4j-core-0.8.0-SNAPSHOT.jar
|
||||
file.reference.apache-mime4j-dom-0.8.0.jar=release/modules/ext/apache-mime4j-dom-0.8.0-SNAPSHOT.jar
|
||||
file.reference.apache-mime4j-mbox-iterator-0.8.0.jar=release/modules/ext/apache-mime4j-mbox-iterator-0.8.0-SNAPSHOT.jar
|
||||
file.reference.java-libpst-1.0-SNAPSHOT.jar=release/modules/ext/java-libpst-1.0-SNAPSHOT.jar
|
||||
file.reference.ez-vcard-0.10.5.jar=release/modules/ext/ez-vcard-0.10.5.jar
|
||||
file.reference.vinnie-2.0.2.jar=release/modules/ext/vinnie-2.0.2.jar
|
||||
javac.source=1.8
|
||||
javac.compilerargs=-Xlint -Xlint:-serial
|
||||
license.file=../LICENSE-2.0.txt
|
||||
|
@ -50,6 +50,10 @@
|
||||
</dependency>
|
||||
</module-dependencies>
|
||||
<public-packages/>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/commons-lang3-3.8.1.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/commons-lang3-3.8.1.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/apache-mime4j-core-0.8.0-SNAPSHOT.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/apache-mime4j-core-0.8.0-SNAPSHOT.jar</binary-origin>
|
||||
@ -66,6 +70,14 @@
|
||||
<runtime-relative-path>ext/apache-mime4j-mbox-iterator-0.8.0-SNAPSHOT.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/apache-mime4j-mbox-iterator-0.8.0-SNAPSHOT.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/ez-vcard-0.10.5.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/ez-vcard-0.10.5.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/vinnie-2.0.2.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/vinnie-2.0.2.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
</data>
|
||||
</configuration>
|
||||
</project>
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2014 Basis Technology Corp.
|
||||
* Copyright 2011-2019 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -53,24 +53,30 @@ import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||
import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
|
||||
import org.sleuthkit.datamodel.DerivedFile;
|
||||
import org.sleuthkit.datamodel.Relationship;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.TskData;
|
||||
import org.sleuthkit.datamodel.TskDataException;
|
||||
import org.sleuthkit.datamodel.TskException;
|
||||
|
||||
/**
|
||||
* File-level ingest module that detects MBOX files based on signature.
|
||||
* Understands Thunderbird folder layout to provide additional structure and
|
||||
* metadata.
|
||||
* File-level ingest module that detects MBOX, PST, and vCard files based on
|
||||
* signature. Understands Thunderbird folder layout to provide additional
|
||||
* structure and metadata.
|
||||
*/
|
||||
public final class ThunderbirdMboxFileIngestModule implements FileIngestModule {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(ThunderbirdMboxFileIngestModule.class.getName());
|
||||
private IngestServices services = IngestServices.getInstance();
|
||||
private final IngestServices services = IngestServices.getInstance();
|
||||
private FileManager fileManager;
|
||||
private IngestJobContext context;
|
||||
private Blackboard blackboard;
|
||||
|
||||
private Case currentCase;
|
||||
private SleuthkitCase tskCase;
|
||||
|
||||
/**
|
||||
* Empty constructor.
|
||||
*/
|
||||
ThunderbirdMboxFileIngestModule() {
|
||||
}
|
||||
|
||||
@ -79,6 +85,8 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule {
|
||||
public void startUp(IngestJobContext context) throws IngestModuleException {
|
||||
this.context = context;
|
||||
try {
|
||||
currentCase = Case.getCurrentCaseThrows();
|
||||
tskCase = currentCase.getSleuthkitCase();
|
||||
fileManager = Case.getCurrentCaseThrows().getServices().getFileManager();
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
logger.log(Level.SEVERE, "Exception while getting open case.", ex);
|
||||
@ -133,6 +141,10 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule {
|
||||
return processPst(abstractFile);
|
||||
}
|
||||
|
||||
if (VcardParser.isVcardFile(abstractFile)) {
|
||||
return processVcard(abstractFile);
|
||||
}
|
||||
|
||||
return ProcessResult.OK;
|
||||
}
|
||||
|
||||
@ -177,13 +189,8 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule {
|
||||
PstParser.ParseResult result = parser.parse(file, abstractFile.getId());
|
||||
|
||||
if (result == PstParser.ParseResult.OK) {
|
||||
try {
|
||||
// parse success: Process email and add artifacts
|
||||
processEmails(parser.getResults(), abstractFile);
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
logger.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS
|
||||
return ProcessResult.ERROR;
|
||||
}
|
||||
// parse success: Process email and add artifacts
|
||||
processEmails(parser.getResults(), abstractFile);
|
||||
|
||||
} else if (result == PstParser.ParseResult.ENCRYPT) {
|
||||
// encrypted pst: Add encrypted file artifact
|
||||
@ -279,12 +286,7 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule {
|
||||
|
||||
MboxParser parser = new MboxParser(services, emailFolder);
|
||||
List<EmailMessage> emails = parser.parse(file, abstractFile.getId());
|
||||
try {
|
||||
processEmails(emails, abstractFile);
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
logger.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS
|
||||
return ProcessResult.ERROR;
|
||||
}
|
||||
processEmails(emails, abstractFile);
|
||||
|
||||
if (file.delete() == false) {
|
||||
logger.log(Level.INFO, "Failed to delete temp file: {0}", file.getName()); //NON-NLS
|
||||
@ -300,6 +302,63 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule {
|
||||
return ProcessResult.OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse and extract data from a vCard file.
|
||||
*
|
||||
* @param abstractFile The content to be processed.
|
||||
*
|
||||
* @return 'ERROR' whenever a NoCurrentCaseException is encountered;
|
||||
* otherwise 'OK'.
|
||||
*/
|
||||
@Messages({
|
||||
"# {0} - file name",
|
||||
"# {1} - file ID",
|
||||
"ThunderbirdMboxFileIngestModule.errorMessage.outOfDiskSpace=Out of disk space. Cannot copy '{0}' (id={1}) to parse."
|
||||
})
|
||||
private ProcessResult processVcard(AbstractFile abstractFile) {
|
||||
String fileName;
|
||||
try {
|
||||
fileName = getTempPath() + File.separator + abstractFile.getName()
|
||||
+ "-" + String.valueOf(abstractFile.getId());
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
logger.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS
|
||||
return ProcessResult.ERROR;
|
||||
}
|
||||
File file = new File(fileName);
|
||||
|
||||
long freeSpace = services.getFreeDiskSpace();
|
||||
if ((freeSpace != IngestMonitor.DISK_FREE_SPACE_UNKNOWN) && (abstractFile.getSize() >= freeSpace)) {
|
||||
logger.log(Level.WARNING, String.format("Not enough disk space to write file '%s' (id=%d) to disk.",
|
||||
abstractFile.getName(), abstractFile.getId())); //NON-NLS
|
||||
IngestMessage msg = IngestMessage.createErrorMessage(EmailParserModuleFactory.getModuleName(), EmailParserModuleFactory.getModuleName(),
|
||||
Bundle.ThunderbirdMboxFileIngestModule_errorMessage_outOfDiskSpace(abstractFile.getName(), abstractFile.getId()));
|
||||
services.postMessage(msg);
|
||||
return ProcessResult.OK;
|
||||
}
|
||||
|
||||
try {
|
||||
ContentUtils.writeToFile(abstractFile, file, context::fileIngestIsCancelled);
|
||||
} catch (IOException ex) {
|
||||
logger.log(Level.WARNING, String.format("Failed writing the vCard file '%s' (id=%d) to disk.",
|
||||
abstractFile.getName(), abstractFile.getId()), ex); //NON-NLS
|
||||
return ProcessResult.OK;
|
||||
}
|
||||
|
||||
try {
|
||||
VcardParser parser = new VcardParser(currentCase, context);
|
||||
parser.parse(file, abstractFile);
|
||||
} catch (IOException | NoCurrentCaseException ex) {
|
||||
logger.log(Level.WARNING, String.format("Exception while parsing the file '%s' (id=%d).", file.getName(), abstractFile.getId()), ex); //NON-NLS
|
||||
return ProcessResult.OK;
|
||||
}
|
||||
|
||||
if (file.delete() == false) {
|
||||
logger.log(Level.INFO, "Failed to delete temp file: {0}", file.getName()); //NON-NLS
|
||||
}
|
||||
|
||||
return ProcessResult.OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a path to a temporary folder.
|
||||
*
|
||||
@ -320,6 +379,7 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule {
|
||||
* Get a module output folder.
|
||||
*
|
||||
* @throws NoCurrentCaseException if there is no open case.
|
||||
*
|
||||
* @return the module output folder
|
||||
*/
|
||||
static String getModuleOutputPath() throws NoCurrentCaseException {
|
||||
@ -349,15 +409,14 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule {
|
||||
*
|
||||
* @param emails
|
||||
* @param abstractFile
|
||||
* @throws NoCurrentCaseException if there is no open case.
|
||||
*/
|
||||
private void processEmails(List<EmailMessage> emails, AbstractFile abstractFile) throws NoCurrentCaseException {
|
||||
private void processEmails(List<EmailMessage> emails, AbstractFile abstractFile) {
|
||||
List<AbstractFile> derivedFiles = new ArrayList<>();
|
||||
|
||||
|
||||
|
||||
for (EmailMessage email : emails) {
|
||||
BlackboardArtifact msgArtifact = addArtifact(email, abstractFile);
|
||||
BlackboardArtifact msgArtifact = addEmailArtifact(email, abstractFile);
|
||||
|
||||
if ((msgArtifact != null) && (email.hasAttachment())) {
|
||||
derivedFiles.addAll(handleAttachments(email.getAttachments(), abstractFile, msgArtifact ));
|
||||
@ -423,7 +482,7 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule {
|
||||
Pattern p = Pattern.compile("\\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}\\b",
|
||||
Pattern.CASE_INSENSITIVE);
|
||||
Matcher m = p.matcher(input);
|
||||
Set<String> emailAddresses = new HashSet<String>();
|
||||
Set<String> emailAddresses = new HashSet<>();
|
||||
while (m.find()) {
|
||||
emailAddresses.add( m.group());
|
||||
}
|
||||
@ -431,14 +490,15 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a blackboard artifact for the given email message.
|
||||
* Add a blackboard artifact for the given e-mail message.
|
||||
*
|
||||
* @param email
|
||||
* @param abstractFile
|
||||
* @throws NoCurrentCaseException if there is no open case.
|
||||
* @param email The e-mail message.
|
||||
* @param abstractFile The associated file.
|
||||
*
|
||||
* @return The generated e-mail message artifact.
|
||||
*/
|
||||
@Messages({"ThunderbirdMboxFileIngestModule.addArtifact.indexError.message=Failed to index email message detected artifact for keyword search."})
|
||||
private BlackboardArtifact addArtifact(EmailMessage email, AbstractFile abstractFile) throws NoCurrentCaseException {
|
||||
private BlackboardArtifact addEmailArtifact(EmailMessage email, AbstractFile abstractFile) {
|
||||
BlackboardArtifact bbart = null;
|
||||
List<BlackboardAttribute> bbattributes = new ArrayList<>();
|
||||
String to = email.getRecipients();
|
||||
@ -460,19 +520,17 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule {
|
||||
|
||||
AccountFileInstance senderAccountInstance = null;
|
||||
|
||||
Case openCase = Case.getCurrentCaseThrows();
|
||||
|
||||
if (senderAddressList.size() == 1) {
|
||||
senderAddress = senderAddressList.get(0);
|
||||
try {
|
||||
senderAccountInstance = openCase.getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.EMAIL, senderAddress, EmailParserModuleFactory.getModuleName(), abstractFile);
|
||||
senderAccountInstance = currentCase.getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.EMAIL, senderAddress, EmailParserModuleFactory.getModuleName(), abstractFile);
|
||||
}
|
||||
catch(TskCoreException ex) {
|
||||
logger.log(Level.WARNING, "Failed to create account for email address " + senderAddress, ex); //NON-NLS
|
||||
}
|
||||
}
|
||||
else {
|
||||
logger.log(Level.WARNING, "Failed to find sender address, from = "+ from); //NON-NLS
|
||||
logger.log(Level.WARNING, "Failed to find sender address, from = {0}", from); //NON-NLS
|
||||
}
|
||||
|
||||
List<String> recipientAddresses = new ArrayList<>();
|
||||
@ -484,7 +542,7 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule {
|
||||
recipientAddresses.forEach((addr) -> {
|
||||
try {
|
||||
AccountFileInstance recipientAccountInstance =
|
||||
openCase.getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.EMAIL, addr,
|
||||
currentCase.getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.EMAIL, addr,
|
||||
EmailParserModuleFactory.getModuleName(), abstractFile);
|
||||
recipientAccountInstances.add(recipientAccountInstance);
|
||||
}
|
||||
@ -493,25 +551,25 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule {
|
||||
}
|
||||
});
|
||||
|
||||
addEmailAttribute(headers, ATTRIBUTE_TYPE.TSK_HEADERS, bbattributes);
|
||||
addEmailAttribute(from, ATTRIBUTE_TYPE.TSK_EMAIL_FROM, bbattributes);
|
||||
addEmailAttribute(to, ATTRIBUTE_TYPE.TSK_EMAIL_TO, bbattributes);
|
||||
addEmailAttribute(subject, ATTRIBUTE_TYPE.TSK_SUBJECT, bbattributes);
|
||||
addArtifactAttribute(headers, ATTRIBUTE_TYPE.TSK_HEADERS, bbattributes);
|
||||
addArtifactAttribute(from, ATTRIBUTE_TYPE.TSK_EMAIL_FROM, bbattributes);
|
||||
addArtifactAttribute(to, ATTRIBUTE_TYPE.TSK_EMAIL_TO, bbattributes);
|
||||
addArtifactAttribute(subject, ATTRIBUTE_TYPE.TSK_SUBJECT, bbattributes);
|
||||
|
||||
addEmailAttribute(dateL, ATTRIBUTE_TYPE.TSK_DATETIME_RCVD, bbattributes);
|
||||
addEmailAttribute(dateL, ATTRIBUTE_TYPE.TSK_DATETIME_SENT, bbattributes);
|
||||
addArtifactAttribute(dateL, ATTRIBUTE_TYPE.TSK_DATETIME_RCVD, bbattributes);
|
||||
addArtifactAttribute(dateL, ATTRIBUTE_TYPE.TSK_DATETIME_SENT, bbattributes);
|
||||
|
||||
addEmailAttribute(body, ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_PLAIN, bbattributes);
|
||||
addArtifactAttribute(body, ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_PLAIN, bbattributes);
|
||||
|
||||
addEmailAttribute(((id < 0L) ? NbBundle.getMessage(this.getClass(), "ThunderbirdMboxFileIngestModule.notAvail") : String.valueOf(id)),
|
||||
addArtifactAttribute(((id < 0L) ? NbBundle.getMessage(this.getClass(), "ThunderbirdMboxFileIngestModule.notAvail") : String.valueOf(id)),
|
||||
ATTRIBUTE_TYPE.TSK_MSG_ID, bbattributes);
|
||||
|
||||
addEmailAttribute(((localPath.isEmpty() == false) ? localPath : "/foo/bar"),
|
||||
addArtifactAttribute(((localPath.isEmpty() == false) ? localPath : "/foo/bar"),
|
||||
ATTRIBUTE_TYPE.TSK_PATH, bbattributes);
|
||||
|
||||
addEmailAttribute(cc, ATTRIBUTE_TYPE.TSK_EMAIL_CC, bbattributes);
|
||||
addEmailAttribute(bodyHTML, ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_HTML, bbattributes);
|
||||
addEmailAttribute(rtf, ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_RTF, bbattributes);
|
||||
addArtifactAttribute(cc, ATTRIBUTE_TYPE.TSK_EMAIL_CC, bbattributes);
|
||||
addArtifactAttribute(bodyHTML, ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_HTML, bbattributes);
|
||||
addArtifactAttribute(rtf, ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_RTF, bbattributes);
|
||||
|
||||
|
||||
try {
|
||||
@ -520,7 +578,7 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule {
|
||||
bbart.addAttributes(bbattributes);
|
||||
|
||||
// Add account relationships
|
||||
openCase.getSleuthkitCase().getCommunicationsManager().addRelationships(senderAccountInstance, recipientAccountInstances, bbart,Relationship.Type.MESSAGE, dateL);
|
||||
currentCase.getSleuthkitCase().getCommunicationsManager().addRelationships(senderAccountInstance, recipientAccountInstances, bbart,Relationship.Type.MESSAGE, dateL);
|
||||
|
||||
try {
|
||||
// index the artifact for keyword search
|
||||
@ -536,22 +594,61 @@ public final class ThunderbirdMboxFileIngestModule implements FileIngestModule {
|
||||
return bbart;
|
||||
}
|
||||
|
||||
private void addEmailAttribute(String stringVal, ATTRIBUTE_TYPE attrType, Collection<BlackboardAttribute> bbattributes) {
|
||||
/**
|
||||
* Add an attribute of a specified type to a supplied Collection.
|
||||
*
|
||||
* @param stringVal The attribute value.
|
||||
* @param attrType The type of attribute to be added.
|
||||
* @param bbattributes The Collection to which the attribute will be added.
|
||||
*/
|
||||
static void addArtifactAttribute(String stringVal, BlackboardAttribute.Type attrType, Collection<BlackboardAttribute> bbattributes) {
|
||||
if (stringVal.isEmpty() == false) {
|
||||
bbattributes.add(new BlackboardAttribute(attrType, EmailParserModuleFactory.getModuleName(), stringVal));
|
||||
}
|
||||
}
|
||||
private void addEmailAttribute(long longVal, ATTRIBUTE_TYPE attrType, Collection<BlackboardAttribute> bbattributes) {
|
||||
|
||||
/**
|
||||
* Add an attribute of a specified type to a supplied Collection.
|
||||
*
|
||||
* @param stringVal The attribute value.
|
||||
* @param attrType The type of attribute to be added.
|
||||
* @param bbattributes The Collection to which the attribute will be added.
|
||||
*/
|
||||
static void addArtifactAttribute(String stringVal, ATTRIBUTE_TYPE attrType, Collection<BlackboardAttribute> bbattributes) {
|
||||
if (stringVal.isEmpty() == false) {
|
||||
bbattributes.add(new BlackboardAttribute(attrType, EmailParserModuleFactory.getModuleName(), stringVal));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an attribute of a specified type to a supplied Collection.
|
||||
*
|
||||
* @param longVal The attribute value.
|
||||
* @param attrType The type of attribute to be added.
|
||||
* @param bbattributes The Collection to which the attribute will be added.
|
||||
*/
|
||||
static void addArtifactAttribute(long longVal, ATTRIBUTE_TYPE attrType, Collection<BlackboardAttribute> bbattributes) {
|
||||
if (longVal > 0) {
|
||||
bbattributes.add(new BlackboardAttribute(attrType, EmailParserModuleFactory.getModuleName(), longVal));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Post an error message for the user.
|
||||
*
|
||||
* @param subj The error subject.
|
||||
* @param details The error details.
|
||||
*/
|
||||
void postErrorMessage(String subj, String details) {
|
||||
IngestMessage ingestMessage = IngestMessage.createErrorMessage(EmailParserModuleFactory.getModuleVersion(), subj, details);
|
||||
services.postMessage(ingestMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the IngestServices object.
|
||||
*
|
||||
* @return The IngestServices object.
|
||||
*/
|
||||
IngestServices getServices() {
|
||||
return services;
|
||||
}
|
||||
|
543
thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/VcardParser.java
Executable file
543
thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/VcardParser.java
Executable file
@ -0,0 +1,543 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2019 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.thunderbirdparser;
|
||||
|
||||
import ezvcard.Ezvcard;
|
||||
import ezvcard.VCard;
|
||||
import ezvcard.parameter.EmailType;
|
||||
import ezvcard.parameter.TelephoneType;
|
||||
import ezvcard.property.Email;
|
||||
import ezvcard.property.Organization;
|
||||
import ezvcard.property.Photo;
|
||||
import ezvcard.property.Telephone;
|
||||
import ezvcard.property.Url;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.casemodule.services.Blackboard;
|
||||
import org.sleuthkit.autopsy.casemodule.services.FileManager;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||
import org.sleuthkit.autopsy.ingest.IngestJobContext;
|
||||
import org.sleuthkit.autopsy.ingest.IngestServices;
|
||||
import org.sleuthkit.autopsy.ingest.ModuleContentEvent;
|
||||
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
|
||||
import static org.sleuthkit.autopsy.thunderbirdparser.ThunderbirdMboxFileIngestModule.getRelModuleOutputPath;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.Account;
|
||||
import org.sleuthkit.datamodel.AccountFileInstance;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.DataSource;
|
||||
import org.sleuthkit.datamodel.Relationship;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.TskData;
|
||||
import org.sleuthkit.datamodel.TskDataException;
|
||||
import org.sleuthkit.datamodel.TskException;
|
||||
|
||||
/**
|
||||
* A parser that can extract information from a vCard file and create the
|
||||
* appropriate artifacts.
|
||||
*/
|
||||
final class VcardParser {
|
||||
private static final String VCARD_HEADER = "BEGIN:VCARD";
|
||||
private static final long MIN_FILE_SIZE = 22;
|
||||
|
||||
private static final String PHOTO_TYPE_BMP = "bmp";
|
||||
private static final String PHOTO_TYPE_GIF = "gif";
|
||||
private static final String PHOTO_TYPE_JPEG = "jpeg";
|
||||
private static final String PHOTO_TYPE_PNG = "png";
|
||||
private static final Map<String, String> photoTypeExtensions;
|
||||
static {
|
||||
photoTypeExtensions = new HashMap<>();
|
||||
photoTypeExtensions.put(PHOTO_TYPE_BMP, ".bmp");
|
||||
photoTypeExtensions.put(PHOTO_TYPE_GIF, ".gif");
|
||||
photoTypeExtensions.put(PHOTO_TYPE_JPEG, ".jpg");
|
||||
photoTypeExtensions.put(PHOTO_TYPE_PNG, ".png");
|
||||
}
|
||||
|
||||
private static final Logger logger = Logger.getLogger(VcardParser.class.getName());
|
||||
|
||||
private final IngestServices services = IngestServices.getInstance();
|
||||
private final FileManager fileManager;
|
||||
private final IngestJobContext context;
|
||||
private final Blackboard blackboard;
|
||||
private final Case currentCase;
|
||||
private final SleuthkitCase tskCase;
|
||||
|
||||
/**
|
||||
* Create a VcardParser object.
|
||||
*/
|
||||
VcardParser(Case currentCase, IngestJobContext context) {
|
||||
this.context = context;
|
||||
this.currentCase = currentCase;
|
||||
tskCase = currentCase.getSleuthkitCase();
|
||||
blackboard = currentCase.getServices().getBlackboard();
|
||||
fileManager = currentCase.getServices().getFileManager();
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the supplied content a vCard file?
|
||||
*
|
||||
* @param content The content to check.
|
||||
*
|
||||
* @return True if the supplied content is a vCard file; otherwise false.
|
||||
*/
|
||||
static boolean isVcardFile(Content content) {
|
||||
try {
|
||||
if (content.getSize() > MIN_FILE_SIZE) {
|
||||
byte[] buffer = new byte[VCARD_HEADER.length()];
|
||||
int byteRead = content.read(buffer, 0, VCARD_HEADER.length());
|
||||
if (byteRead > 0) {
|
||||
String header = new String(buffer);
|
||||
return header.equalsIgnoreCase(VCARD_HEADER);
|
||||
}
|
||||
}
|
||||
} catch (TskException ex) {
|
||||
logger.log(Level.WARNING, String.format("Exception while detecting if the file '%s' (id=%d) is a vCard file.",
|
||||
content.getName(), content.getId())); //NON-NLS
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the VCard file and compile its data in a VCard object. The
|
||||
* corresponding artifacts will be created.
|
||||
*
|
||||
* @param vcardFile The VCard file to be parsed.
|
||||
* @param abstractFile The abstract file with which to associate artifacts.
|
||||
*
|
||||
* @throws IOException If there is an issue parsing the VCard
|
||||
* file.
|
||||
* @throws NoCurrentCaseException If there is no open case.
|
||||
*/
|
||||
void parse(File vcardFile, AbstractFile abstractFile) throws IOException, NoCurrentCaseException {
|
||||
VCard vcard = Ezvcard.parse(vcardFile).first();
|
||||
addContactArtifact(vcard, abstractFile);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Add a blackboard artifact for the given contact.
|
||||
*
|
||||
* @param vcard The VCard that contains the contact information.
|
||||
* @param abstractFile The file associated with the data.
|
||||
*
|
||||
* @throws NoCurrentCaseException if there is no open case.
|
||||
*
|
||||
* @return The generated contact artifact.
|
||||
*/
|
||||
@NbBundle.Messages({"VcardParser.addContactArtifact.indexError=Failed to index the contact artifact for keyword search."})
|
||||
private BlackboardArtifact addContactArtifact(VCard vcard, AbstractFile abstractFile) throws NoCurrentCaseException {
|
||||
List<BlackboardAttribute> attributes = new ArrayList<>();
|
||||
List<AccountFileInstance> accountInstances = new ArrayList<>();
|
||||
|
||||
extractPhotos(vcard, abstractFile);
|
||||
|
||||
ThunderbirdMboxFileIngestModule.addArtifactAttribute(vcard.getFormattedName().getValue(), BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME_PERSON, attributes);
|
||||
|
||||
for (Telephone telephone : vcard.getTelephoneNumbers()) {
|
||||
addPhoneAttributes(telephone, abstractFile, attributes);
|
||||
addPhoneAccountInstances(telephone, abstractFile, accountInstances);
|
||||
}
|
||||
|
||||
for (Email email : vcard.getEmails()) {
|
||||
addEmailAttributes(email, abstractFile, attributes);
|
||||
addEmailAccountInstances(email, abstractFile, accountInstances);
|
||||
}
|
||||
|
||||
for (Url url : vcard.getUrls()) {
|
||||
ThunderbirdMboxFileIngestModule.addArtifactAttribute(url.getValue(), BlackboardAttribute.ATTRIBUTE_TYPE.TSK_URL, attributes);
|
||||
}
|
||||
|
||||
for (Organization organization : vcard.getOrganizations()) {
|
||||
List<String> values = organization.getValues();
|
||||
if (values.isEmpty() == false) {
|
||||
ThunderbirdMboxFileIngestModule.addArtifactAttribute(values.get(0), BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ORGANIZATION, attributes);
|
||||
}
|
||||
}
|
||||
|
||||
AccountFileInstance deviceAccountInstance = addDeviceAccountInstance(abstractFile);
|
||||
|
||||
BlackboardArtifact artifact = null;
|
||||
org.sleuthkit.datamodel.Blackboard tskBlackboard = tskCase.getBlackboard();
|
||||
try {
|
||||
// Create artifact if it doesn't already exist.
|
||||
if (!tskBlackboard.artifactExists(abstractFile, BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT, attributes)) {
|
||||
artifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT);
|
||||
artifact.addAttributes(attributes);
|
||||
List<BlackboardArtifact> blackboardArtifacts = new ArrayList<>();
|
||||
blackboardArtifacts.add(artifact);
|
||||
|
||||
// Add account relationships.
|
||||
if (deviceAccountInstance != null) {
|
||||
try {
|
||||
currentCase.getSleuthkitCase().getCommunicationsManager().addRelationships(
|
||||
deviceAccountInstance, accountInstances, artifact, Relationship.Type.CONTACT, abstractFile.getCrtime());
|
||||
} catch (TskDataException ex) {
|
||||
logger.log(Level.SEVERE, String.format("Failed to create phone and e-mail account relationships (fileName='%s'; fileId=%d; accountId=%d).",
|
||||
abstractFile.getName(), abstractFile.getId(), deviceAccountInstance.getAccount().getAccountID()), ex); //NON-NLS
|
||||
}
|
||||
}
|
||||
|
||||
// Index the artifact for keyword search.
|
||||
try {
|
||||
blackboard.indexArtifact(artifact);
|
||||
} catch (Blackboard.BlackboardException ex) {
|
||||
logger.log(Level.SEVERE, "Unable to index blackboard artifact " + artifact.getArtifactID(), ex); //NON-NLS
|
||||
MessageNotifyUtil.Notify.error(Bundle.VcardParser_addContactArtifact_indexError(), artifact.getDisplayName());
|
||||
}
|
||||
|
||||
// Fire event to notify UI of this new artifact.
|
||||
IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent(
|
||||
EmailParserModuleFactory.getModuleName(), BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT,
|
||||
blackboardArtifacts));
|
||||
}
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, String.format("Failed to create contact artifact for vCard file '%s' (id=%d).",
|
||||
abstractFile.getName(), abstractFile.getId()), ex); //NON-NLS
|
||||
}
|
||||
|
||||
return artifact;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract photos from a given VCard and add them as derived files.
|
||||
*
|
||||
* @param vcard The VCard from which to extract the photos.
|
||||
* @param abstractFile The file associated with the data.
|
||||
*
|
||||
* @throws NoCurrentCaseException if there is no open case.
|
||||
*/
|
||||
private void extractPhotos(VCard vcard, AbstractFile abstractFile) throws NoCurrentCaseException {
|
||||
String parentFileName = getUniqueName(abstractFile);
|
||||
// Skip files that already have been extracted.
|
||||
try {
|
||||
String outputPath = getOutputFolderPath(parentFileName);
|
||||
if (new File(outputPath).exists()) {
|
||||
List<Photo> vcardPhotos = vcard.getPhotos();
|
||||
List<AbstractFile> derivedFilesCreated = new ArrayList<>();
|
||||
for (int i=0; i < vcardPhotos.size(); i++) {
|
||||
Photo photo = vcardPhotos.get(i);
|
||||
|
||||
if (photo.getUrl() != null) {
|
||||
// Skip this photo since its data is not embedded.
|
||||
continue;
|
||||
}
|
||||
|
||||
String type = photo.getType();
|
||||
if (type == null) {
|
||||
// Skip this photo since no type is defined.
|
||||
continue;
|
||||
}
|
||||
|
||||
type = type.toLowerCase();
|
||||
if (type.startsWith("image/")) {
|
||||
type = type.substring(6);
|
||||
}
|
||||
String extension = photoTypeExtensions.get(type);
|
||||
|
||||
byte[] data = photo.getData();
|
||||
String extractedFileName = String.format("photo_%d%s", i, extension == null ? "" : extension);
|
||||
String extractedFilePath = Paths.get(outputPath, extractedFileName).toString();
|
||||
try {
|
||||
writeExtractedImage(extractedFilePath, data);
|
||||
derivedFilesCreated.add(fileManager.addDerivedFile(extractedFileName, getFileRelativePath(parentFileName, extractedFileName), data.length,
|
||||
abstractFile.getCtime(), abstractFile.getCrtime(), abstractFile.getAtime(), abstractFile.getAtime(),
|
||||
true, abstractFile, null, EmailParserModuleFactory.getModuleName(), null, null, TskData.EncodingType.NONE));
|
||||
} catch (IOException | TskCoreException ex) {
|
||||
logger.log(Level.WARNING, String.format("Could not write image to '%s' (id=%d).", extractedFilePath, abstractFile.getId()), ex); //NON-NLS
|
||||
}
|
||||
}
|
||||
if (!derivedFilesCreated.isEmpty()) {
|
||||
services.fireModuleContentEvent(new ModuleContentEvent(abstractFile));
|
||||
context.addFilesToJob(derivedFilesCreated);
|
||||
}
|
||||
}
|
||||
else {
|
||||
logger.log(Level.INFO, String.format("Skipping photo extraction for file '%s' (id=%d), because it has already been processed.",
|
||||
abstractFile.getName(), abstractFile.getId())); //NON-NLS
|
||||
}
|
||||
} catch (SecurityException ex) {
|
||||
logger.log(Level.WARNING, String.format("Could not create extraction folder for '%s' (id=%d).", parentFileName, abstractFile.getId()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes image to the module output location.
|
||||
*
|
||||
* @param outputPath Path where images is written.
|
||||
* @param data Byte representation of the data to be written to the
|
||||
* specified location.
|
||||
*/
|
||||
private void writeExtractedImage(String outputPath, byte[] data) throws IOException {
|
||||
File outputFile = new File(outputPath);
|
||||
FileOutputStream outputStream = new FileOutputStream(outputFile);
|
||||
outputStream.write(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a unique name for a file by concatentating the file name and the
|
||||
* file object id.
|
||||
*
|
||||
* @param file The file.
|
||||
*
|
||||
* @return The unique file name.
|
||||
*/
|
||||
private String getUniqueName(AbstractFile file) {
|
||||
return file.getName() + "_" + file.getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the relative path to the file. The path is relative to the case
|
||||
* folder.
|
||||
*
|
||||
* @param fileName Name of the the file for which the path is to be
|
||||
* generated.
|
||||
*
|
||||
* @return The relative file path.
|
||||
*/
|
||||
private String getFileRelativePath(String parentFileName, String fileName) throws NoCurrentCaseException {
|
||||
// Used explicit FWD slashes to maintain DB consistency across operating systems.
|
||||
return "/" + getRelModuleOutputPath() + "/" + parentFileName + "/" + fileName; //NON-NLS
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets path to the output folder for file extraction. If the path does not
|
||||
* exist, it is created.
|
||||
*
|
||||
* @param parentFileName Name of the abstract file being processed.
|
||||
*
|
||||
* @throws NoCurrentCaseException if there is no open case.
|
||||
*
|
||||
* @return Path to the file extraction folder for a given abstract file.
|
||||
*/
|
||||
private String getOutputFolderPath(String parentFileName) throws NoCurrentCaseException {
|
||||
String outputFolderPath = ThunderbirdMboxFileIngestModule.getModuleOutputPath() + File.separator + parentFileName;
|
||||
File outputFilePath = new File(outputFolderPath);
|
||||
if (!outputFilePath.exists()) {
|
||||
outputFilePath.mkdirs();
|
||||
}
|
||||
return outputFolderPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate phone attributes for a given VCard Telephone object.
|
||||
*
|
||||
* @param telephone The VCard Telephone from which to generate attributes.
|
||||
* @param abstractFile The VCard file.
|
||||
* @param attributes The Collection to which generated attributes will be
|
||||
* added.
|
||||
*/
|
||||
private void addPhoneAttributes(Telephone telephone, AbstractFile abstractFile, Collection<BlackboardAttribute> attributes) {
|
||||
String telephoneText = telephone.getText();
|
||||
if (telephoneText == null || telephoneText.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Add phone number to collection for later creation of TSK_CONTACT.
|
||||
List<TelephoneType> telephoneTypes = telephone.getTypes();
|
||||
if (telephoneTypes.isEmpty()) {
|
||||
ThunderbirdMboxFileIngestModule.addArtifactAttribute(telephone.getText(), BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER, attributes);
|
||||
} else {
|
||||
for (TelephoneType type : telephoneTypes) {
|
||||
/*
|
||||
* Unfortunately, if the types are lower-case, they don't
|
||||
* get separated correctly into individual TelephoneTypes by
|
||||
* ez-vcard. Therefore, we must read them manually
|
||||
* ourselves.
|
||||
*/
|
||||
List<String> splitTelephoneTypes = Arrays.asList(
|
||||
type.getValue().toUpperCase().replaceAll("\\s+","").split(","));
|
||||
|
||||
for (String splitType : splitTelephoneTypes) {
|
||||
String attributeTypeName = "TSK_PHONE_" + splitType;
|
||||
try {
|
||||
BlackboardAttribute.Type attributeType = tskCase.getAttributeType(attributeTypeName);
|
||||
if (attributeType == null) {
|
||||
// Add this attribute type to the case database.
|
||||
attributeType = tskCase.addArtifactAttributeType(attributeTypeName,
|
||||
BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.STRING,
|
||||
String.format("Phone (%s)", StringUtils.capitalize(splitType.toLowerCase())));
|
||||
}
|
||||
ThunderbirdMboxFileIngestModule.addArtifactAttribute(telephone.getText(), attributeType, attributes);
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, String.format("Unable to retrieve attribute type '%s' for file '%s' (id=%d).", attributeTypeName, abstractFile.getName(), abstractFile.getId()), ex);
|
||||
} catch (TskDataException ex) {
|
||||
logger.log(Level.SEVERE, String.format("Unable to add custom attribute type '%s' for file '%s' (id=%d).", attributeTypeName, abstractFile.getName(), abstractFile.getId()), ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate e-mail attributes for a given VCard Email object.
|
||||
*
|
||||
* @param email The VCard Email from which to generate attributes.
|
||||
* @param abstractFile The VCard file.
|
||||
* @param attributes The Collection to which generated attributes will be
|
||||
* added.
|
||||
*/
|
||||
private void addEmailAttributes(Email email, AbstractFile abstractFile, Collection<BlackboardAttribute> attributes) {
|
||||
String emailValue = email.getValue();
|
||||
if (emailValue == null || emailValue.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Add phone number to collection for later creation of TSK_CONTACT.
|
||||
List<EmailType> emailTypes = email.getTypes();
|
||||
if (emailTypes.isEmpty()) {
|
||||
ThunderbirdMboxFileIngestModule.addArtifactAttribute(email.getValue(), BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL, attributes);
|
||||
} else {
|
||||
for (EmailType type : emailTypes) {
|
||||
/*
|
||||
* Unfortunately, if the types are lower-case, they don't
|
||||
* get separated correctly into individual EmailTypes by
|
||||
* ez-vcard. Therefore, we must read them manually
|
||||
* ourselves.
|
||||
*/
|
||||
List<String> splitEmailTypes = Arrays.asList(
|
||||
type.getValue().toUpperCase().replaceAll("\\s+","").split(","));
|
||||
|
||||
for (String splitType : splitEmailTypes) {
|
||||
String attributeTypeName = "TSK_EMAIL_" + splitType;
|
||||
try {
|
||||
BlackboardAttribute.Type attributeType = tskCase.getAttributeType(attributeTypeName);
|
||||
if (attributeType == null) {
|
||||
// Add this attribute type to the case database.
|
||||
attributeType = tskCase.addArtifactAttributeType(attributeTypeName,
|
||||
BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.STRING,
|
||||
String.format("Email (%s)", StringUtils.capitalize(splitType.toLowerCase())));
|
||||
}
|
||||
ThunderbirdMboxFileIngestModule.addArtifactAttribute(email.getValue(), attributeType, attributes);
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, String.format("Unable to retrieve attribute type '%s' for file '%s' (id=%d).", attributeTypeName, abstractFile.getName(), abstractFile.getId()), ex);
|
||||
} catch (TskDataException ex) {
|
||||
logger.log(Level.SEVERE, String.format("Unable to add custom attribute type '%s' for file '%s' (id=%d).", attributeTypeName, abstractFile.getName(), abstractFile.getId()), ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate account instances for a given VCard Telephone object.
|
||||
*
|
||||
* @param telephone The VCard Telephone from which to generate
|
||||
* account instances.
|
||||
* @param abstractFile The VCard file.
|
||||
* @param accountInstances The Collection to which generated account
|
||||
* instances will be added.
|
||||
*/
|
||||
private void addPhoneAccountInstances(Telephone telephone, AbstractFile abstractFile, Collection<AccountFileInstance> accountInstances) {
|
||||
String telephoneText = telephone.getText();
|
||||
if (telephoneText == null || telephoneText.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Add phone number as a TSK_ACCOUNT.
|
||||
try {
|
||||
AccountFileInstance phoneAccountInstance = tskCase.getCommunicationsManager().createAccountFileInstance(Account.Type.PHONE,
|
||||
telephoneText, EmailParserModuleFactory.getModuleName(), abstractFile);
|
||||
accountInstances.add(phoneAccountInstance);
|
||||
}
|
||||
catch(TskCoreException ex) {
|
||||
logger.log(Level.WARNING, String.format(
|
||||
"Failed to create account for phone number '%s' (content='%s'; id=%d).",
|
||||
telephoneText, abstractFile.getName(), abstractFile.getId()), ex); //NON-NLS
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate account instances for a given VCard Email object.
|
||||
*
|
||||
* @param telephone The VCard Email from which to generate account
|
||||
* instances.
|
||||
* @param abstractFile The VCard file.
|
||||
* @param accountInstances The Collection to which generated account
|
||||
* instances will be added.
|
||||
*/
|
||||
private void addEmailAccountInstances(Email email, AbstractFile abstractFile, Collection<AccountFileInstance> accountInstances) {
|
||||
String emailValue = email.getValue();
|
||||
if (emailValue == null || emailValue.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Add e-mail as a TSK_ACCOUNT.
|
||||
try {
|
||||
AccountFileInstance emailAccountInstance = tskCase.getCommunicationsManager().createAccountFileInstance(Account.Type.EMAIL,
|
||||
emailValue, EmailParserModuleFactory.getModuleName(), abstractFile);
|
||||
accountInstances.add(emailAccountInstance);
|
||||
}
|
||||
catch(TskCoreException ex) {
|
||||
logger.log(Level.WARNING, String.format(
|
||||
"Failed to create account for e-mail address '%s' (content='%s'; id=%d).",
|
||||
emailValue, abstractFile.getName(), abstractFile.getId()), ex); //NON-NLS
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate device account instance for a given file.
|
||||
*
|
||||
* @param abstractFile The VCard file.
|
||||
*
|
||||
* @return The generated device account instance.
|
||||
*/
|
||||
private AccountFileInstance addDeviceAccountInstance(AbstractFile abstractFile) {
|
||||
// Add 'DEVICE' TSK_ACCOUNT.
|
||||
AccountFileInstance deviceAccountInstance = null;
|
||||
String deviceId = null;
|
||||
try {
|
||||
long dataSourceObjId = abstractFile.getDataSourceObjectId();
|
||||
DataSource dataSource = tskCase.getDataSource(dataSourceObjId);
|
||||
deviceId = dataSource.getDeviceId();
|
||||
deviceAccountInstance = tskCase.getCommunicationsManager().createAccountFileInstance(Account.Type.DEVICE,
|
||||
deviceId, EmailParserModuleFactory.getModuleName(), abstractFile);
|
||||
}
|
||||
catch (TskCoreException ex) {
|
||||
logger.log(Level.WARNING, String.format(
|
||||
"Failed to create device account for '%s' (content='%s'; id=%d).",
|
||||
deviceId, abstractFile.getName(), abstractFile.getId()), ex); //NON-NLS
|
||||
}
|
||||
catch (TskDataException ex) {
|
||||
logger.log(Level.WARNING, String.format(
|
||||
"Failed to get the data source from the case database (id=%d).",
|
||||
abstractFile.getId()), ex); //NON-NLS
|
||||
}
|
||||
|
||||
return deviceAccountInstance;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user