mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-17 10:17:41 +00:00
Merge pull request #3482 from dgrove727/3437_ReadContentInputStreamError_1
3437 read content input stream error 1
This commit is contained in:
commit
f93bfe9965
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2017 Basis Technology Corp.
|
||||
* Copyright 2011-2018 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -44,6 +44,7 @@ import org.sleuthkit.datamodel.LayoutFile;
|
||||
import org.sleuthkit.datamodel.LocalFile;
|
||||
import org.sleuthkit.datamodel.LocalDirectory;
|
||||
import org.sleuthkit.datamodel.ReadContentInputStream;
|
||||
import org.sleuthkit.datamodel.ReadContentInputStream.ReadContentInputStreamException;
|
||||
import org.sleuthkit.datamodel.SlackFile;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.VirtualDirectory;
|
||||
@ -69,18 +70,20 @@ public final class ContentUtils {
|
||||
});
|
||||
}
|
||||
|
||||
// don't instantiate
|
||||
/**
|
||||
* Don't instantiate
|
||||
*/
|
||||
private ContentUtils() {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert epoch seconds to a string value in the given time zone
|
||||
* Convert epoch seconds to a string value in the given time zone.
|
||||
*
|
||||
* @param epochSeconds
|
||||
* @param tzone
|
||||
* @param epochSeconds Epoch seconds
|
||||
* @param tzone Time zone
|
||||
*
|
||||
* @return
|
||||
* @return The time
|
||||
*/
|
||||
public static String getStringTime(long epochSeconds, TimeZone tzone) {
|
||||
String time = "0000-00-00 00:00:00";
|
||||
@ -93,6 +96,14 @@ public final class ContentUtils {
|
||||
return time;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert epoch seconds to a string value (ISO8601) in the given time zone.
|
||||
*
|
||||
* @param epochSeconds Epoch seconds
|
||||
* @param tzone Time zone
|
||||
*
|
||||
* @return The time
|
||||
*/
|
||||
public static String getStringTimeISO8601(long epochSeconds, TimeZone tzone) {
|
||||
String time = "0000-00-00T00:00:00Z"; //NON-NLS
|
||||
if (epochSeconds != 0) {
|
||||
@ -109,12 +120,12 @@ public final class ContentUtils {
|
||||
* Convert epoch seconds to a string value (convenience method)
|
||||
*
|
||||
* @param epochSeconds
|
||||
* @param c
|
||||
* @param content
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static String getStringTime(long epochSeconds, Content c) {
|
||||
return getStringTime(epochSeconds, getTimeZone(c));
|
||||
public static String getStringTime(long epochSeconds, Content content) {
|
||||
return getStringTime(epochSeconds, getTimeZone(content));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -130,13 +141,13 @@ public final class ContentUtils {
|
||||
return getStringTimeISO8601(epochSeconds, getTimeZone(c));
|
||||
}
|
||||
|
||||
public static TimeZone getTimeZone(Content c) {
|
||||
public static TimeZone getTimeZone(Content content) {
|
||||
|
||||
try {
|
||||
if (!shouldDisplayTimesInLocalTime()) {
|
||||
return TimeZone.getTimeZone("GMT");
|
||||
} else {
|
||||
final Content dataSource = c.getDataSource();
|
||||
final Content dataSource = content.getDataSource();
|
||||
if ((dataSource != null) && (dataSource instanceof Image)) {
|
||||
Image image = (Image) dataSource;
|
||||
return TimeZone.getTimeZone(image.getTimeZone());
|
||||
@ -151,10 +162,21 @@ public final class ContentUtils {
|
||||
}
|
||||
private static final SystemNameVisitor systemName = new SystemNameVisitor();
|
||||
|
||||
/**
|
||||
* Get system name from content using SystemNameVisitor.
|
||||
*
|
||||
* @param content The content object.
|
||||
*
|
||||
* @return The system name.
|
||||
*/
|
||||
public static String getSystemName(Content content) {
|
||||
return content.accept(systemName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Visitor designed to handle the system name (content name and ID
|
||||
* appended).
|
||||
*/
|
||||
private static class SystemNameVisitor extends ContentVisitor.Default<String> {
|
||||
|
||||
SystemNameVisitor() {
|
||||
@ -220,27 +242,37 @@ public final class ContentUtils {
|
||||
return totalRead;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write content to an output file.
|
||||
*
|
||||
* @param content The Content object.
|
||||
* @param outputFile The output file.
|
||||
*
|
||||
* @throws IOException If the file could not be written.
|
||||
*/
|
||||
public static void writeToFile(Content content, java.io.File outputFile) throws IOException {
|
||||
writeToFile(content, outputFile, null, null, false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reads all the data from any content object and writes (extracts) it to a
|
||||
* file, using a cancellation check instead of a Future object method.
|
||||
*
|
||||
*
|
||||
* @param content Any content object.
|
||||
* @param outputFile Will be created if it doesn't exist, and overwritten
|
||||
* if it does
|
||||
* @param cancelCheck A function used to check if the file write process
|
||||
* should be terminated.
|
||||
*
|
||||
* @return number of bytes extracted
|
||||
*
|
||||
* @throws IOException if file could not be written
|
||||
*/
|
||||
public static long writeToFile(Content content, java.io.File outputFile,
|
||||
Supplier<Boolean> cancelCheck) throws IOException {
|
||||
InputStream in = new ReadContentInputStream(content);
|
||||
long totalRead = 0;
|
||||
|
||||
|
||||
try (FileOutputStream out = new FileOutputStream(outputFile, false)) {
|
||||
byte[] buffer = new byte[TO_FILE_BUFFER_SIZE];
|
||||
int len = in.read(buffer);
|
||||
@ -260,7 +292,9 @@ public final class ContentUtils {
|
||||
|
||||
/**
|
||||
* Helper to ignore the '.' and '..' directories
|
||||
* @param dir the directory to check
|
||||
*
|
||||
* @param dir the directory to check
|
||||
*
|
||||
* @return true if dir is a '.' or '..' directory, false otherwise
|
||||
*/
|
||||
public static boolean isDotDirectory(AbstractFile dir) {
|
||||
@ -313,61 +347,81 @@ public final class ContentUtils {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(File f) {
|
||||
public Void visit(File file) {
|
||||
try {
|
||||
ContentUtils.writeToFile(f, dest, progress, worker, source);
|
||||
ContentUtils.writeToFile(file, dest, progress, worker, source);
|
||||
} catch (ReadContentInputStreamException ex) {
|
||||
logger.log(Level.WARNING,
|
||||
String.format("Error reading file '%s' (id=%d).",
|
||||
file.getName(), file.getId()), ex); //NON-NLS
|
||||
} catch (IOException ex) {
|
||||
logger.log(Level.SEVERE,
|
||||
"Trouble extracting file to " + dest.getAbsolutePath(), //NON-NLS
|
||||
ex);
|
||||
String.format("Error extracting file '%s' (id=%d) to '%s'.",
|
||||
file.getName(), file.getId(), dest.getAbsolutePath()), ex); //NON-NLS
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(LayoutFile f) {
|
||||
public Void visit(LayoutFile file) {
|
||||
try {
|
||||
ContentUtils.writeToFile(f, dest, progress, worker, source);
|
||||
ContentUtils.writeToFile(file, dest, progress, worker, source);
|
||||
} catch (ReadContentInputStreamException ex) {
|
||||
logger.log(Level.WARNING,
|
||||
String.format("Error reading file '%s' (id=%d).",
|
||||
file.getName(), file.getId()), ex); //NON-NLS
|
||||
} catch (IOException ex) {
|
||||
logger.log(Level.SEVERE,
|
||||
"Trouble extracting unallocated content file to " + dest.getAbsolutePath(), //NON-NLS
|
||||
ex);
|
||||
String.format("Error extracting unallocated content file '%s' (id=%d) to '%s'.",
|
||||
file.getName(), file.getId(), dest.getAbsolutePath()), ex); //NON-NLS
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(DerivedFile df) {
|
||||
public Void visit(DerivedFile file) {
|
||||
try {
|
||||
ContentUtils.writeToFile(df, dest, progress, worker, source);
|
||||
ContentUtils.writeToFile(file, dest, progress, worker, source);
|
||||
} catch (ReadContentInputStreamException ex) {
|
||||
logger.log(Level.WARNING,
|
||||
String.format("Error reading file '%s' (id=%d).",
|
||||
file.getName(), file.getId()), ex); //NON-NLS
|
||||
} catch (IOException ex) {
|
||||
logger.log(Level.SEVERE,
|
||||
"Error extracting derived file to " + dest.getAbsolutePath(), //NON-NLS
|
||||
ex);
|
||||
String.format("Error extracting derived file '%s' (id=%d) to '%s'.",
|
||||
file.getName(), file.getId(), dest.getAbsolutePath()), ex); //NON-NLS
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(LocalFile lf) {
|
||||
public Void visit(LocalFile file) {
|
||||
try {
|
||||
ContentUtils.writeToFile(lf, dest, progress, worker, source);
|
||||
ContentUtils.writeToFile(file, dest, progress, worker, source);
|
||||
} catch (ReadContentInputStreamException ex) {
|
||||
logger.log(Level.WARNING,
|
||||
String.format("Error reading file '%s' (id=%d).",
|
||||
file.getName(), file.getId()), ex); //NON-NLS
|
||||
} catch (IOException ex) {
|
||||
logger.log(Level.SEVERE,
|
||||
"Error extracting local file to " + dest.getAbsolutePath(), //NON-NLS
|
||||
ex);
|
||||
String.format("Error extracting local file '%s' (id=%d) to '%s'.",
|
||||
file.getName(), file.getId(), dest.getAbsolutePath()), ex); //NON-NLS
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Void visit(SlackFile f) {
|
||||
public Void visit(SlackFile file) {
|
||||
try {
|
||||
ContentUtils.writeToFile(f, dest, progress, worker, source);
|
||||
ContentUtils.writeToFile(file, dest, progress, worker, source);
|
||||
} catch (ReadContentInputStreamException ex) {
|
||||
logger.log(Level.WARNING,
|
||||
String.format("Error reading file '%s' (id=%d).",
|
||||
file.getName(), file.getId()), ex); //NON-NLS
|
||||
} catch (IOException ex) {
|
||||
logger.log(Level.SEVERE,
|
||||
"Trouble extracting slack file to " + dest.getAbsolutePath(), //NON-NLS
|
||||
ex);
|
||||
String.format("Error extracting slack file '%s' (id=%d) to '%s'.",
|
||||
file.getName(), file.getId(), dest.getAbsolutePath()), ex); //NON-NLS
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@ -381,15 +435,15 @@ public final class ContentUtils {
|
||||
public Void visit(VirtualDirectory dir) {
|
||||
return visitDir(dir);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Void visit(LocalDirectory dir) {
|
||||
return visitDir(dir);
|
||||
}
|
||||
|
||||
private java.io.File getFsContentDest(Content fsc) {
|
||||
private java.io.File getFsContentDest(Content content) {
|
||||
String path = dest.getAbsolutePath() + java.io.File.separator
|
||||
+ fsc.getName();
|
||||
+ content.getName();
|
||||
return new java.io.File(path);
|
||||
}
|
||||
|
||||
@ -406,7 +460,7 @@ public final class ContentUtils {
|
||||
int numProcessed = 0;
|
||||
// recurse on children
|
||||
for (Content child : dir.getChildren()) {
|
||||
if (child instanceof AbstractFile){ //ensure the directory's artifact children are ignored
|
||||
if (child instanceof AbstractFile) { //ensure the directory's artifact children are ignored
|
||||
java.io.File childFile = getFsContentDest(child);
|
||||
ExtractFscContentVisitor<T, V> childVisitor
|
||||
= new ExtractFscContentVisitor<>(childFile, progress, worker, false);
|
||||
@ -414,10 +468,10 @@ public final class ContentUtils {
|
||||
// will have a progress and worker, and will keep track
|
||||
// of the progress bar's progress
|
||||
if (worker != null && worker.isCancelled()) {
|
||||
break;
|
||||
break;
|
||||
}
|
||||
if (progress != null && source) {
|
||||
progress.progress(child.getName(), numProcessed);
|
||||
progress.progress(child.getName(), numProcessed);
|
||||
}
|
||||
child.accept(childVisitor);
|
||||
numProcessed++;
|
||||
@ -447,5 +501,5 @@ public final class ContentUtils {
|
||||
public static boolean shouldDisplayTimesInLocalTime() {
|
||||
return displayTimesInLocalTime;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2014 Basis Technology Corp.
|
||||
* Copyright 2014-2018 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -37,10 +37,14 @@ import org.sleuthkit.autopsy.ingest.IngestJobContext;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||
import org.sleuthkit.datamodel.ReadContentInputStream.ReadContentInputStreamException;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
class CallLogAnalyzer {
|
||||
/**
|
||||
* Look for call logs and allow resulting blackboard artifacts to be generated.
|
||||
*/
|
||||
final class CallLogAnalyzer {
|
||||
|
||||
private Connection connection = null;
|
||||
private ResultSet resultSet = null;
|
||||
@ -48,10 +52,15 @@ class CallLogAnalyzer {
|
||||
private String dbPath = "";
|
||||
private long fileId = 0;
|
||||
private java.io.File jFile = null;
|
||||
private String moduleName = iOSModuleFactory.getModuleName();
|
||||
private final String moduleName = iOSModuleFactory.getModuleName();
|
||||
private static final Logger logger = Logger.getLogger(CallLogAnalyzer.class.getName());
|
||||
private Blackboard blackboard;
|
||||
|
||||
/**
|
||||
* Find call logs given an ingest job context and index the results.
|
||||
*
|
||||
* @param context The ingest job context.
|
||||
*/
|
||||
public void findCallLogs(IngestJobContext context) {
|
||||
blackboard = Case.getCurrentCase().getServices().getBlackboard();
|
||||
List<AbstractFile> absFiles;
|
||||
@ -61,15 +70,17 @@ class CallLogAnalyzer {
|
||||
if (absFiles.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
for (AbstractFile AF : absFiles) {
|
||||
for (AbstractFile file : absFiles) {
|
||||
try {
|
||||
jFile = new java.io.File(Case.getCurrentCase().getTempDirectory(), AF.getName().replaceAll("[<>%|\"/:*\\\\]", ""));
|
||||
ContentUtils.writeToFile(AF, jFile, context::dataSourceIngestIsCancelled);
|
||||
jFile = new java.io.File(Case.getCurrentCase().getTempDirectory(), file.getName().replaceAll("[<>%|\"/:*\\\\]", ""));
|
||||
dbPath = jFile.toString(); //path of file as string
|
||||
fileId = AF.getId();
|
||||
fileId = file.getId();
|
||||
ContentUtils.writeToFile(file, jFile, context::dataSourceIngestIsCancelled);
|
||||
findCallLogsInDB(dbPath, fileId);
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.SEVERE, "Error parsing Call logs", e); //NON-NLS
|
||||
} catch (ReadContentInputStreamException ex) {
|
||||
logger.log(Level.WARNING, String.format("Error reading content from file '%s' (id=%d).", file.getName(), fileId), ex); //NON-NLS
|
||||
} catch (Exception ex) {
|
||||
logger.log(Level.SEVERE, String.format("Error writing content from file '%s' (id=%d) to '%s'.", file.getName(), fileId, dbPath), ex); //NON-NLS
|
||||
}
|
||||
}
|
||||
} catch (TskCoreException e) {
|
||||
@ -77,8 +88,14 @@ class CallLogAnalyzer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Index results for call logs found in the database.
|
||||
*
|
||||
* @param DatabasePath The path to the database.
|
||||
* @param fileId The ID of the file associated with artifacts.
|
||||
*/
|
||||
@Messages({"CallLogAnalyzer.indexError.message=Failed to index call log artifact for keyword search."})
|
||||
private void findCallLogsInDB(String DatabasePath, long fId) {
|
||||
private void findCallLogsInDB(String DatabasePath, long fileId) {
|
||||
if (DatabasePath == null || DatabasePath.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
@ -93,9 +110,9 @@ class CallLogAnalyzer {
|
||||
Case currentCase = Case.getCurrentCase();
|
||||
SleuthkitCase skCase = currentCase.getSleuthkitCase();
|
||||
try {
|
||||
AbstractFile f = skCase.getAbstractFileById(fId);
|
||||
if (f == null) {
|
||||
logger.log(Level.SEVERE, "Error getting abstract file " + fId); //NON-NLS
|
||||
AbstractFile file = skCase.getAbstractFileById(fileId);
|
||||
if (file == null) {
|
||||
logger.log(Level.SEVERE, "Error getting abstract file {0}", fileId); //NON-NLS
|
||||
return;
|
||||
}
|
||||
|
||||
@ -117,7 +134,7 @@ class CallLogAnalyzer {
|
||||
date = resultSet.getString("date"); //NON-NLS
|
||||
type = resultSet.getString("type"); //NON-NLS
|
||||
|
||||
bba = f.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG); //create a call log and then add attributes from result set.
|
||||
bba = file.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG); //create a call log and then add attributes from result set.
|
||||
Collection<BlackboardAttribute> attributes = new ArrayList<>();
|
||||
if (type.equalsIgnoreCase("outgoing")) { //NON-NLS
|
||||
attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO, moduleName, number));
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2014 Basis Technology Corp.
|
||||
* Copyright 2014-2018 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -43,10 +43,14 @@ import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||
import org.sleuthkit.datamodel.ReadContentInputStream;
|
||||
import org.sleuthkit.datamodel.ReadContentInputStream.ReadContentInputStreamException;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
class ContactAnalyzer {
|
||||
/**
|
||||
* Look for call logs and allow resulting blackboard artifacts to be generated.
|
||||
*/
|
||||
final class ContactAnalyzer {
|
||||
|
||||
private Connection connection = null;
|
||||
private ResultSet resultSet = null;
|
||||
@ -54,10 +58,15 @@ class ContactAnalyzer {
|
||||
private String dbPath = "";
|
||||
private long fileId = 0;
|
||||
private java.io.File jFile = null;
|
||||
private String moduleName = iOSModuleFactory.getModuleName();
|
||||
private final String moduleName = iOSModuleFactory.getModuleName();
|
||||
private static final Logger logger = Logger.getLogger(ContactAnalyzer.class.getName());
|
||||
private Blackboard blackboard;
|
||||
|
||||
/**
|
||||
* Find contacts given an ingest job context and index the results.
|
||||
*
|
||||
* @param context The ingest job context.
|
||||
*/
|
||||
public void findContacts(IngestJobContext context) {
|
||||
|
||||
blackboard = Case.getCurrentCase().getServices().getBlackboard();
|
||||
@ -68,18 +77,16 @@ class ContactAnalyzer {
|
||||
if (absFiles.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
for (AbstractFile AF : absFiles) {
|
||||
for (AbstractFile file : absFiles) {
|
||||
try {
|
||||
jFile = new java.io.File(Case.getCurrentCase().getTempDirectory(), AF.getName().replaceAll("[<>%|\"/:*\\\\]", ""));
|
||||
//jFile = new java.io.File(Case.getCurrentCase().getTempDirectory(), i+".txt");
|
||||
ContentUtils.writeToFile(AF, jFile, context::dataSourceIngestIsCancelled);
|
||||
//copyFileUsingStreams(AF,jFile);
|
||||
//copyFileUsingStream(AF,jFile);
|
||||
jFile = new java.io.File(Case.getCurrentCase().getTempDirectory(), file.getName().replaceAll("[<>%|\"/:*\\\\]", ""));
|
||||
dbPath = jFile.toString(); //path of file as string
|
||||
fileId = AF.getId();
|
||||
//findContactsInDB(dbPath, fileId);
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.SEVERE, "Error parsing Contacts", e); //NON-NLS
|
||||
fileId = file.getId();
|
||||
ContentUtils.writeToFile(file, jFile, context::dataSourceIngestIsCancelled);
|
||||
} catch (ReadContentInputStreamException ex) {
|
||||
logger.log(Level.WARNING, String.format("Error reading content from file '%s' (id=%d).", file.getName(), fileId), ex); //NON-NLS
|
||||
} catch (Exception ex) {
|
||||
logger.log(Level.SEVERE, String.format("Error writing content from file '%s' (id=%d) to '%s'.", file.getName(), fileId, dbPath), ex); //NON-NLS
|
||||
}
|
||||
}
|
||||
} catch (TskCoreException e) {
|
||||
@ -88,14 +95,14 @@ class ContactAnalyzer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create blackboard artifacts and index results for call logs found in the
|
||||
* database.
|
||||
*
|
||||
* @param DatabasePath
|
||||
* @param fId Will create artifact from a database given by the
|
||||
* path The fileId will be the Abstract file associated
|
||||
* with the artifacts
|
||||
* @param DatabasePath The path to the database.
|
||||
* @param fileId The ID of the file associated with artifacts.
|
||||
*/
|
||||
@Messages({"ContactAnalyzer.indexError.message=Failed to index contact artifact for keyword search."})
|
||||
private void findContactsInDB(String DatabasePath, long fId) {
|
||||
private void findContactsInDB(String DatabasePath, long fileId) {
|
||||
if (DatabasePath == null || DatabasePath.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
@ -110,9 +117,9 @@ class ContactAnalyzer {
|
||||
Case currentCase = Case.getCurrentCase();
|
||||
SleuthkitCase skCase = currentCase.getSleuthkitCase();
|
||||
try {
|
||||
AbstractFile f = skCase.getAbstractFileById(fId);
|
||||
if (f == null) {
|
||||
logger.log(Level.SEVERE, "Error getting abstract file " + fId); //NON-NLS
|
||||
AbstractFile file = skCase.getAbstractFileById(fileId);
|
||||
if (file == null) {
|
||||
logger.log(Level.SEVERE, "Error getting abstract file {0}", fileId); //NON-NLS
|
||||
return;
|
||||
}
|
||||
|
||||
@ -129,7 +136,7 @@ class ContactAnalyzer {
|
||||
+ "ORDER BY name_raw_contact.display_name ASC;"); //NON-NLS
|
||||
|
||||
BlackboardArtifact bba;
|
||||
bba = f.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT);
|
||||
bba = file.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT);
|
||||
Collection<BlackboardAttribute> attributes = new ArrayList<>();
|
||||
String name;
|
||||
String oldName = "";
|
||||
@ -148,7 +155,7 @@ class ContactAnalyzer {
|
||||
attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL, moduleName, data1));
|
||||
}
|
||||
oldName = name;
|
||||
|
||||
|
||||
bba.addAttributes(attributes);
|
||||
try {
|
||||
// index the artifact for keyword search
|
||||
@ -157,7 +164,7 @@ class ContactAnalyzer {
|
||||
logger.log(Level.SEVERE, "Unable to index blackboard artifact " + bba.getArtifactID(), ex); //NON-NLS
|
||||
MessageNotifyUtil.Notify.error(
|
||||
Bundle.ContactAnalyzer_indexError_message(), bba.getDisplayName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2014 Basis Technology Corp.
|
||||
* Copyright 2014-2018 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -38,9 +38,14 @@ import org.sleuthkit.autopsy.ingest.IngestJobContext;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||
import org.sleuthkit.datamodel.ReadContentInputStream;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* Look for text messages and allow resulting blackboard artifacts to be
|
||||
* generated.
|
||||
*/
|
||||
class TextMessageAnalyzer {
|
||||
|
||||
private Connection connection = null;
|
||||
@ -50,10 +55,15 @@ class TextMessageAnalyzer {
|
||||
private long fileId = 0;
|
||||
private java.io.File jFile = null;
|
||||
List<AbstractFile> absFiles;
|
||||
private String moduleName = iOSModuleFactory.getModuleName();
|
||||
private final String moduleName = iOSModuleFactory.getModuleName();
|
||||
private static final Logger logger = Logger.getLogger(TextMessageAnalyzer.class.getName());
|
||||
private Blackboard blackboard;
|
||||
|
||||
/**
|
||||
* Find text messages given an ingest job context and index the results.
|
||||
*
|
||||
* @param context The ingest job context.
|
||||
*/
|
||||
void findTexts(IngestJobContext context) {
|
||||
blackboard = Case.getCurrentCase().getServices().getBlackboard();
|
||||
try {
|
||||
@ -62,15 +72,17 @@ class TextMessageAnalyzer {
|
||||
if (absFiles.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
for (AbstractFile AF : absFiles) {
|
||||
for (AbstractFile file : absFiles) {
|
||||
try {
|
||||
jFile = new java.io.File(Case.getCurrentCase().getTempDirectory(), AF.getName().replaceAll("[<>%|\"/:*\\\\]", ""));
|
||||
ContentUtils.writeToFile(AF, jFile, context::dataSourceIngestIsCancelled);
|
||||
jFile = new java.io.File(Case.getCurrentCase().getTempDirectory(), file.getName().replaceAll("[<>%|\"/:*\\\\]", ""));
|
||||
dbPath = jFile.toString(); //path of file as string
|
||||
fileId = AF.getId();
|
||||
fileId = file.getId();
|
||||
ContentUtils.writeToFile(file, jFile, context::dataSourceIngestIsCancelled);
|
||||
findTextsInDB(dbPath, fileId);
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.SEVERE, "Error parsing text messages", e); //NON-NLS
|
||||
} catch (ReadContentInputStream.ReadContentInputStreamException ex) {
|
||||
logger.log(Level.WARNING, String.format("Error reading content from file '%s' (id=%d).", file.getName(), fileId), ex); //NON-NLS
|
||||
} catch (Exception ex) {
|
||||
logger.log(Level.SEVERE, String.format("Error writing content from file '%s' (id=%d) to '%s'.", file.getName(), fileId, dbPath), ex); //NON-NLS
|
||||
}
|
||||
}
|
||||
} catch (TskCoreException e) {
|
||||
@ -78,8 +90,15 @@ class TextMessageAnalyzer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create blackboard artifacts and index results for text messages found in
|
||||
* the database.
|
||||
*
|
||||
* @param DatabasePath The path to the database.
|
||||
* @param fileId The ID of the file associated with artifacts.
|
||||
*/
|
||||
@Messages({"TextMessageAnalyzer.indexError.message=Failed to index text message artifact for keyword search."})
|
||||
private void findTextsInDB(String DatabasePath, long fId) {
|
||||
private void findTextsInDB(String DatabasePath, long fileId) {
|
||||
if (DatabasePath == null || DatabasePath.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
@ -94,9 +113,9 @@ class TextMessageAnalyzer {
|
||||
Case currentCase = Case.getCurrentCase();
|
||||
SleuthkitCase skCase = currentCase.getSleuthkitCase();
|
||||
try {
|
||||
AbstractFile f = skCase.getAbstractFileById(fId);
|
||||
if (f == null) {
|
||||
logger.log(Level.SEVERE, "Error getting abstract file " + fId); //NON-NLS
|
||||
AbstractFile file = skCase.getAbstractFileById(fileId);
|
||||
if (file == null) {
|
||||
logger.log(Level.SEVERE, "Error getting abstract file {0}", fileId); //NON-NLS
|
||||
return;
|
||||
}
|
||||
|
||||
@ -117,7 +136,7 @@ class TextMessageAnalyzer {
|
||||
subject = resultSet.getString("subject"); //NON-NLS
|
||||
body = resultSet.getString("body"); //NON-NLS
|
||||
|
||||
bba = f.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE); //create Message artifact and then add attributes from result set.
|
||||
bba = file.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE); //create Message artifact and then add attributes from result set.
|
||||
Collection<BlackboardAttribute> attributes = new ArrayList<>();
|
||||
// @@@ NEed to put into more specific TO or FROM
|
||||
if (type.equals("1")) {
|
||||
|
@ -1,16 +1,16 @@
|
||||
/*
|
||||
*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
*
|
||||
* Copyright 2014-2018 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.
|
||||
@ -43,6 +43,7 @@ import org.jdom2.output.Format;
|
||||
import org.jdom2.output.XMLOutputter;
|
||||
import org.jdom2.CDATA;
|
||||
import org.openide.filesystems.FileUtil;
|
||||
import org.sleuthkit.datamodel.ReadContentInputStream.ReadContentInputStreamException;
|
||||
|
||||
/**
|
||||
* Generates a KML file based on geospatial information from the BlackBoard.
|
||||
@ -67,7 +68,7 @@ class ReportKML implements GeneralReportModule {
|
||||
PURPLE("style.kml#purpleFeature"),
|
||||
WHITE("style.kml#whiteFeature"),
|
||||
YELLOW("style.kml#yellowFeature");
|
||||
private String color;
|
||||
private final String color;
|
||||
|
||||
FeatureColor(String color) {
|
||||
this.color = color;
|
||||
@ -104,7 +105,7 @@ class ReportKML implements GeneralReportModule {
|
||||
progressPanel.start();
|
||||
progressPanel.updateStatusLabel(NbBundle.getMessage(this.getClass(), "ReportKML.progress.querying"));
|
||||
String kmlFileFullPath = baseReportDir + REPORT_KML; //NON-NLS
|
||||
|
||||
|
||||
currentCase = Case.getCurrentCase();
|
||||
skCase = currentCase.getSleuthkitCase();
|
||||
|
||||
@ -197,6 +198,8 @@ class ReportKML implements GeneralReportModule {
|
||||
*/
|
||||
try {
|
||||
for (BlackboardArtifact artifact : skCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF)) {
|
||||
String fileName = "";
|
||||
long fileId = 0;
|
||||
try {
|
||||
Long timestamp = getLong(artifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_CREATED);
|
||||
String desc = getDescriptionFromArtifact(artifact, "EXIF Metadata With Locations"); //NON-NLS
|
||||
@ -206,7 +209,9 @@ class ReportKML implements GeneralReportModule {
|
||||
|
||||
if (lat != null && lat != 0.0 && lon != null && lon != 0.0) {
|
||||
AbstractFile abstractFile = artifact.getSleuthkitCase().getAbstractFileById(artifact.getObjectID());
|
||||
Path path = null;
|
||||
fileName = abstractFile.getName();
|
||||
fileId = abstractFile.getId();
|
||||
Path path;
|
||||
copyFileUsingStream(abstractFile, Paths.get(baseReportDir, abstractFile.getName()).toFile());
|
||||
try {
|
||||
path = Paths.get(removeLeadingImgAndVol(abstractFile.getUniquePath()));
|
||||
@ -219,6 +224,8 @@ class ReportKML implements GeneralReportModule {
|
||||
}
|
||||
gpsExifMetadataFolder.addContent(makePlacemarkWithPicture(abstractFile.getName(), FeatureColor.RED, desc, timestamp, point, path, formattedCoordinates));
|
||||
}
|
||||
} catch (ReadContentInputStreamException ex) {
|
||||
logger.log(Level.WARNING, String.format("Error reading file '%s' (id=%d).", fileName, fileId), ex);
|
||||
} catch (Exception ex) {
|
||||
logger.log(Level.SEVERE, "Could not extract photo information.", ex); //NON-NLS
|
||||
result = ReportProgressPanel.ReportStatus.ERROR;
|
||||
@ -404,9 +411,7 @@ class ReportKML implements GeneralReportModule {
|
||||
BlackboardAttribute bba = artifact.getAttribute(new BlackboardAttribute.Type(type));
|
||||
if (bba != null) {
|
||||
Double value = bba.getValueDouble();
|
||||
if (value != null) {
|
||||
returnValue = value;
|
||||
}
|
||||
returnValue = value;
|
||||
}
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Error getting Double value: " + type.toString(), ex); //NON-NLS
|
||||
@ -428,9 +433,7 @@ class ReportKML implements GeneralReportModule {
|
||||
BlackboardAttribute bba = artifact.getAttribute(new BlackboardAttribute.Type(type));
|
||||
if (bba != null) {
|
||||
Long value = bba.getValueLong();
|
||||
if (value != null) {
|
||||
returnValue = value;
|
||||
}
|
||||
returnValue = value;
|
||||
}
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Error getting Long value: " + type.toString(), ex); //NON-NLS
|
||||
@ -452,9 +455,7 @@ class ReportKML implements GeneralReportModule {
|
||||
BlackboardAttribute bba = artifact.getAttribute(new BlackboardAttribute.Type(type));
|
||||
if (bba != null) {
|
||||
Integer value = bba.getValueInt();
|
||||
if (value != null) {
|
||||
returnValue = value;
|
||||
}
|
||||
returnValue = value;
|
||||
}
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Error getting Integer value: " + type.toString(), ex); //NON-NLS
|
||||
@ -661,12 +662,12 @@ class ReportKML implements GeneralReportModule {
|
||||
Element coordinates = new Element("coordinates", ns).addContent(longitude + "," + latitude + "," + altitude); //NON-NLS
|
||||
|
||||
if (altitude != 0) {
|
||||
/*
|
||||
Though we are including a non-zero altitude, clamp it to the
|
||||
ground because inaccuracies from the GPS data can cause the terrain
|
||||
to occlude points when zoomed in otherwise. Show the altitude, but
|
||||
keep the point clamped to the ground. We may change this later for
|
||||
flying GPS sensors.
|
||||
/*
|
||||
* Though we are including a non-zero altitude, clamp it to the
|
||||
* ground because inaccuracies from the GPS data can cause the
|
||||
* terrain to occlude points when zoomed in otherwise. Show the
|
||||
* altitude, but keep the point clamped to the ground. We may change
|
||||
* this later for flying GPS sensors.
|
||||
*/
|
||||
Element altitudeMode = new Element("altitudeMode", ns).addContent("clampToGround"); //NON-NLS
|
||||
point.addContent(altitudeMode);
|
||||
@ -811,9 +812,11 @@ class ReportKML implements GeneralReportModule {
|
||||
* @param inputFile The input AbstractFile to copy
|
||||
* @param outputFile the output file
|
||||
*
|
||||
* @throws IOException
|
||||
* @throws ReadContentInputStreamException When a read error occurs.
|
||||
* @throws IOException When a general file exception
|
||||
* occurs.
|
||||
*/
|
||||
private void copyFileUsingStream(AbstractFile inputFile, File outputFile) throws IOException {
|
||||
private void copyFileUsingStream(AbstractFile inputFile, File outputFile) throws ReadContentInputStreamException, IOException {
|
||||
byte[] buffer = new byte[65536];
|
||||
int length;
|
||||
outputFile.createNewFile();
|
||||
|
Loading…
x
Reference in New Issue
Block a user