Merge branch 'release-4.13.0' of https://github.com/sleuthkit/autopsy into 5446-file-transfer-apps

This commit is contained in:
Raman 2019-09-19 17:44:44 -04:00
commit 71c47a40f9
9 changed files with 204 additions and 88 deletions

View File

@ -0,0 +1,49 @@
/*
* 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.casemodule;
import java.io.File;
import java.nio.file.Paths;
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
/**
* Class for methods to check if access should be limited to a feature
*
*/
final class AccessLimiterUtils {
private final static String MULTI_USER_ACCESS_FILE_NAME = "mualimit"; // NON-NLS
private final static String MULTI_USER_ACCESS_FILE_PATH = Paths.get(PlatformUtil.getUserConfigDirectory(), MULTI_USER_ACCESS_FILE_NAME).toString();
/**
* Check if privileges regarding multi-user cases should be restricted.
*
* @return True if privileges should be restricted, false otherwise.
*/
static boolean limitMultiUserAccess() {
return new File(MULTI_USER_ACCESS_FILE_PATH).exists();
}
/**
* Private constructor for a utility class
*/
private AccessLimiterUtils() {
//private constructer left empty intentionally
}
}

View File

@ -1049,7 +1049,7 @@ public class Case {
/* /*
* Enable the case-specific actions. * Enable the case-specific actions.
*/ */
CallableSystemAction.get(AddImageAction.class).setEnabled(true); CallableSystemAction.get(AddImageAction.class).setEnabled(Case.getCurrentCase().getMetadata().getCaseType() == CaseType.SINGLE_USER_CASE || !AccessLimiterUtils.limitMultiUserAccess());
CallableSystemAction.get(CaseCloseAction.class).setEnabled(true); CallableSystemAction.get(CaseCloseAction.class).setEnabled(true);
CallableSystemAction.get(CaseDetailsAction.class).setEnabled(true); CallableSystemAction.get(CaseDetailsAction.class).setEnabled(true);
CallableSystemAction.get(DataSourceSummaryAction.class).setEnabled(true); CallableSystemAction.get(DataSourceSummaryAction.class).setEnabled(true);

View File

@ -61,7 +61,7 @@ final class NewCaseVisualPanel1 extends JPanel implements DocumentListener {
*/ */
void readSettings() { void readSettings() {
caseNameTextField.setText(""); caseNameTextField.setText("");
if (UserPreferences.getIsMultiUserModeEnabled()) { if (UserPreferences.getIsMultiUserModeEnabled() && !AccessLimiterUtils.limitMultiUserAccess()) {
multiUserCaseRadioButton.setEnabled(true); multiUserCaseRadioButton.setEnabled(true);
multiUserCaseRadioButton.setSelected(true); multiUserCaseRadioButton.setSelected(true);
} else { } else {

View File

@ -29,6 +29,7 @@ import java.nio.file.Paths;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.logging.Level; import java.util.logging.Level;
@ -198,7 +199,8 @@ final class AddLogicalImageTask implements Runnable {
} }
List<Content> newDataSources = new ArrayList<>(); List<Content> newDataSources = new ArrayList<>();
Map<String, List<Long>> interestingFileMap = new HashMap<>();
if (imagePaths.isEmpty()) { if (imagePaths.isEmpty()) {
createVHD = false; createVHD = false;
// No VHD in src directory, try ingest the root directory as local files // No VHD in src directory, try ingest the root directory as local files
@ -214,7 +216,7 @@ final class AddLogicalImageTask implements Runnable {
try { try {
progressMonitor.setProgressText(Bundle.AddLogicalImageTask_addingExtractedFiles()); progressMonitor.setProgressText(Bundle.AddLogicalImageTask_addingExtractedFiles());
addExtractedFiles(dest, resultsPath, newDataSources); interestingFileMap = addExtractedFiles(dest, resultsPath, newDataSources);
progressMonitor.setProgressText(Bundle.AddLogicalImageTask_doneAddingExtractedFiles()); progressMonitor.setProgressText(Bundle.AddLogicalImageTask_doneAddingExtractedFiles());
} catch (IOException | TskCoreException ex) { } catch (IOException | TskCoreException ex) {
errorList.add(ex.getMessage()); errorList.add(ex.getMessage());
@ -241,6 +243,14 @@ final class AddLogicalImageTask implements Runnable {
callback.done(DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS, addMultipleImagesTask.getErrorMessages(), emptyDataSources); callback.done(DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS, addMultipleImagesTask.getErrorMessages(), emptyDataSources);
return; return;
} }
try {
interestingFileMap = getInterestingFileMapForVHD(Paths.get(dest.toString(), resultsFilename));
} catch (TskCoreException | IOException ex) {
errorList.add(Bundle.AddLogicalImageTask_failedToAddInterestingFiles(ex.getMessage()));
LOGGER.log(Level.SEVERE, "Failed to add interesting files", ex); // NON-NLS
callback.done(DataSourceProcessorCallback.DataSourceProcessorResult.NONCRITICAL_ERRORS, errorList, emptyDataSources);
}
} catch (NoCurrentCaseException ex) { } catch (NoCurrentCaseException ex) {
String msg = Bundle.AddLogicalImageTask_noCurrentCase(); String msg = Bundle.AddLogicalImageTask_noCurrentCase();
errorList.add(msg); errorList.add(msg);
@ -261,7 +271,7 @@ final class AddLogicalImageTask implements Runnable {
try { try {
progressMonitor.setProgressText(Bundle.AddLogicalImageTask_addingInterestingFiles()); progressMonitor.setProgressText(Bundle.AddLogicalImageTask_addingInterestingFiles());
addInterestingFiles(Paths.get(dest.toString(), resultsFilename), createVHD); addInterestingFiles(interestingFileMap);
progressMonitor.setProgressText(Bundle.AddLogicalImageTask_doneAddingInterestingFiles()); progressMonitor.setProgressText(Bundle.AddLogicalImageTask_doneAddingInterestingFiles());
if (createVHD) { if (createVHD) {
callback.done(addMultipleImagesTask.getResult(), addMultipleImagesTask.getErrorMessages(), addMultipleImagesTask.getNewDataSources()); callback.done(addMultipleImagesTask.getResult(), addMultipleImagesTask.getErrorMessages(), addMultipleImagesTask.getNewDataSources());
@ -332,13 +342,67 @@ final class AddLogicalImageTask implements Runnable {
"# {0} - target image path", "AddLogicalImageTask.cannotFindDataSourceObjId=Cannot find obj_id in tsk_image_names for {0}", "# {0} - target image path", "AddLogicalImageTask.cannotFindDataSourceObjId=Cannot find obj_id in tsk_image_names for {0}",
"# {0} - file number", "# {1} - total files", "AddLogicalImageTask.addingInterestingFile=Adding interesting files ({0}/{1})" "# {0} - file number", "# {1} - total files", "AddLogicalImageTask.addingInterestingFile=Adding interesting files ({0}/{1})"
}) })
private void addInterestingFiles(Path resultsPath, boolean createVHD) throws IOException, TskCoreException { private void addInterestingFiles(Map<String, List<Long>> interestingFileMap) throws IOException, TskCoreException {
int lineNumber = 0;
List<BlackboardArtifact> artifacts = new ArrayList<>();
Iterator<Map.Entry<String, List<Long>>> iterator = interestingFileMap.entrySet().iterator();
while (iterator.hasNext()) {
if (cancelled) {
// Don't delete destination directory once we started adding interesting files.
// At this point the database and destination directory are complete.
break;
}
Map.Entry<String, List<Long>> entry = iterator.next();
String key = entry.getKey();
String ruleSetName;
String ruleName;
String[] split = key.split("\t");
ruleSetName = split[0];
ruleName = split[1];
List<Long> fileIds = entry.getValue();
for (Long fileId: fileIds) {
if (lineNumber % 100 == 0) {
progressMonitor.setProgressText(Bundle.AddLogicalImageTask_addingInterestingFile(lineNumber, totalFiles));
}
addInterestingFileToArtifacts(fileId, ruleSetName, ruleName, artifacts);
lineNumber++;
}
iterator.remove();
}
try {
// index the artifact for keyword search
blackboard.postArtifacts(artifacts, MODULE_NAME);
} catch (Blackboard.BlackboardException ex) {
LOGGER.log(Level.SEVERE, "Unable to post artifacts to blackboard", ex); //NON-NLS
}
}
private void addInterestingFileToArtifacts(long fileId, String ruleSetName, String ruleName, List<BlackboardArtifact> artifacts) throws TskCoreException {
Collection<BlackboardAttribute> attributes = new ArrayList<>();
BlackboardAttribute setNameAttribute = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME, MODULE_NAME, ruleSetName);
attributes.add(setNameAttribute);
BlackboardAttribute ruleNameAttribute = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CATEGORY, MODULE_NAME, ruleName);
attributes.add(ruleNameAttribute);
BlackboardArtifact artifact = this.currentCase.getSleuthkitCase().newBlackboardArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT, fileId);
artifact.addAttributes(attributes);
artifacts.add(artifact);
}
@Messages({
"# {0} - file number", "# {1} - total files", "AddLogicalImageTask.searchingInterestingFile=Searching for interesting files ({0}/{1})"
})
private Map<String, List<Long>> getInterestingFileMapForVHD(Path resultsPath) throws TskCoreException, IOException {
Map<Long, List<String>> objIdToimagePathsMap = currentCase.getSleuthkitCase().getImagePaths(); Map<Long, List<String>> objIdToimagePathsMap = currentCase.getSleuthkitCase().getImagePaths();
imagePathToObjIdMap = imagePathsToDataSourceObjId(objIdToimagePathsMap); imagePathToObjIdMap = imagePathsToDataSourceObjId(objIdToimagePathsMap);
Map<String, List<Long>> interestingFileMap = new HashMap<>();
try (BufferedReader br = new BufferedReader(new InputStreamReader( try (BufferedReader br = new BufferedReader(new InputStreamReader(
new FileInputStream(resultsPath.toFile()), "UTF8"))) { // NON-NLS new FileInputStream(resultsPath.toFile()), "UTF8"))) { // NON-NLS
List<BlackboardArtifact> artifacts = new ArrayList<>();
String line; String line;
br.readLine(); // skip the header line br.readLine(); // skip the header line
int lineNumber = 2; int lineNumber = 2;
@ -363,47 +427,35 @@ final class AddLogicalImageTask implements Runnable {
String parentPath = fields[8]; String parentPath = fields[8];
if (lineNumber % 100 == 0) { if (lineNumber % 100 == 0) {
progressMonitor.setProgressText(Bundle.AddLogicalImageTask_addingInterestingFile(lineNumber, totalFiles)); progressMonitor.setProgressText(Bundle.AddLogicalImageTask_searchingInterestingFile(lineNumber, totalFiles));
} }
String query = makeQuery(createVHD, vhdFilename, fileMetaAddressStr, parentPath, filename);
// TODO - findAllFilesWhere should SQL-escape the query String query = makeQuery(vhdFilename, fileMetaAddressStr, parentPath, filename);
List<AbstractFile> matchedFiles = Case.getCurrentCase().getSleuthkitCase().findAllFilesWhere(query); List<AbstractFile> matchedFiles = Case.getCurrentCase().getSleuthkitCase().findAllFilesWhere(query);
List<Long> fileIds = new ArrayList<>();
for (AbstractFile file : matchedFiles) { for (AbstractFile file : matchedFiles) {
addInterestingFileToArtifacts(file, ruleSetName, ruleName, artifacts); fileIds.add(file.getId());
}
String key = String.format("%s\t%s", ruleSetName, ruleName);
if (interestingFileMap.containsKey(key)) {
interestingFileMap.get(key).addAll(fileIds);
} else {
interestingFileMap.put(key, fileIds);
} }
lineNumber++; lineNumber++;
} // end reading file } // end reading file }
try {
// index the artifact for keyword search
blackboard.postArtifacts(artifacts, MODULE_NAME);
} catch (Blackboard.BlackboardException ex) {
LOGGER.log(Level.SEVERE, "Unable to post artifacts to blackboard", ex); //NON-NLS
}
}
}
private void addInterestingFileToArtifacts(AbstractFile file, String ruleSetName, String ruleName, List<BlackboardArtifact> artifacts) throws TskCoreException {
Collection<BlackboardAttribute> attributes = new ArrayList<>();
BlackboardAttribute setNameAttribute = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME, MODULE_NAME, ruleSetName);
attributes.add(setNameAttribute);
BlackboardAttribute ruleNameAttribute = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CATEGORY, MODULE_NAME, ruleName);
attributes.add(ruleNameAttribute);
if (!blackboard.artifactExists(file, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT, attributes)) {
BlackboardArtifact artifact = this.currentCase.getSleuthkitCase().newBlackboardArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT, file.getId());
artifact.addAttributes(attributes);
artifacts.add(artifact);
} }
return interestingFileMap;
} }
@Messages({ @Messages({
"# {0} - file number", "# {1} - total files", "AddLogicalImageTask.addingExtractedFile=Adding extracted files ({0}/{1})" "# {0} - file number", "# {1} - total files", "AddLogicalImageTask.addingExtractedFile=Adding extracted files ({0}/{1})"
}) })
private void addExtractedFiles(File src, Path resultsPath, List<Content> newDataSources) throws TskCoreException, IOException { private Map<String, List<Long>> addExtractedFiles(File src, Path resultsPath, List<Content> newDataSources) throws TskCoreException, IOException {
SleuthkitCase skCase = Case.getCurrentCase().getSleuthkitCase(); SleuthkitCase skCase = Case.getCurrentCase().getSleuthkitCase();
SleuthkitCase.CaseDbTransaction trans = null; SleuthkitCase.CaseDbTransaction trans = null;
Map<String, List<Long>> interestingFileMap = new HashMap<>();
try { try {
trans = skCase.beginTransaction(); trans = skCase.beginTransaction();
LocalFilesDataSource localFilesDataSource = skCase.addLocalFilesDataSource(deviceId, this.src.getName(), timeZone, trans); LocalFilesDataSource localFilesDataSource = skCase.addLocalFilesDataSource(deviceId, this.src.getName(), timeZone, trans);
@ -417,7 +469,7 @@ final class AddLogicalImageTask implements Runnable {
while ((line = br.readLine()) != null) { while ((line = br.readLine()) != null) {
if (cancelled) { if (cancelled) {
rollbackTransaction(trans); rollbackTransaction(trans);
return; return new HashMap<>();
} }
String[] fields = line.split("\t", -1); // NON-NLS String[] fields = line.split("\t", -1); // NON-NLS
if (fields.length != 14) { if (fields.length != 14) {
@ -428,8 +480,8 @@ final class AddLogicalImageTask implements Runnable {
// String fileSystemOffsetStr = fields[1]; // String fileSystemOffsetStr = fields[1];
// String fileMetaAddressStr = fields[2]; // String fileMetaAddressStr = fields[2];
// String extractStatusStr = fields[3]; // String extractStatusStr = fields[3];
// String ruleSetName = fields[4]; String ruleSetName = fields[4];
// String ruleName = fields[5]; String ruleName = fields[5];
// String description = fields[6]; // String description = fields[6];
String filename = fields[7]; String filename = fields[7];
String parentPath = fields[8]; String parentPath = fields[8];
@ -445,7 +497,7 @@ final class AddLogicalImageTask implements Runnable {
} }
//addLocalFile here //addLocalFile here
fileImporter.addLocalFile( AbstractFile fileAdded = fileImporter.addLocalFile(
Paths.get(src.toString(), extractedFilePath).toFile(), Paths.get(src.toString(), extractedFilePath).toFile(),
filename, filename,
parentPath, parentPath,
@ -454,12 +506,19 @@ final class AddLogicalImageTask implements Runnable {
Long.parseLong(atime), Long.parseLong(atime),
Long.parseLong(mtime), Long.parseLong(mtime),
localFilesDataSource); localFilesDataSource);
String key = String.format("%s\t%s", ruleSetName, ruleName);
List<Long> value = new ArrayList<>();
if (interestingFileMap.containsKey(key)) {
value = interestingFileMap.get(key);
}
value.add(fileAdded.getId());
interestingFileMap.put(key, value);
lineNumber++; lineNumber++;
} // end reading file } // end reading file
} }
trans.commit(); trans.commit();
newDataSources.add(localFilesDataSource); newDataSources.add(localFilesDataSource);
return interestingFileMap;
} catch (NumberFormatException | TskCoreException ex) { } catch (NumberFormatException | TskCoreException ex) {
LOGGER.log(Level.SEVERE, "Error adding extracted files", ex); // NON-NLS LOGGER.log(Level.SEVERE, "Error adding extracted files", ex); // NON-NLS
@ -489,21 +548,16 @@ final class AddLogicalImageTask implements Runnable {
} }
} }
String makeQuery(boolean createVHD, String vhdFilename, String fileMetaAddressStr, String parentPath, String filename) throws TskCoreException { String makeQuery(String vhdFilename, String fileMetaAddressStr, String parentPath, String filename) throws TskCoreException {
String query; String query;
if (createVHD) { String targetImagePath = Paths.get(dest.toString(), vhdFilename).toString();
String targetImagePath = Paths.get(dest.toString(), vhdFilename).toString(); Long dataSourceObjId = imagePathToObjIdMap.get(targetImagePath);
Long dataSourceObjId = imagePathToObjIdMap.get(targetImagePath); if (dataSourceObjId == null) {
if (dataSourceObjId == null) { throw new TskCoreException(Bundle.AddLogicalImageTask_cannotFindDataSourceObjId(targetImagePath));
throw new TskCoreException(Bundle.AddLogicalImageTask_cannotFindDataSourceObjId(targetImagePath));
}
query = String.format("data_source_obj_id = '%s' AND meta_addr = '%s' AND name = '%s'", // NON-NLS
dataSourceObjId.toString(), fileMetaAddressStr, filename.replace("'", "''"));
} else {
String newParentPath = "/" + ROOT_STR + "/" + vhdFilename + "/" + parentPath;
query = String.format("name = '%s' AND parent_path = '%s'", // NON-NLS
filename.replace("'", "''"), newParentPath.replace("'", "''"));
} }
query = String.format("data_source_obj_id = '%s' AND meta_addr = '%s' AND name = '%s'", // NON-NLS
dataSourceObjId.toString(), fileMetaAddressStr, filename.replace("'", "''"));
// TODO - findAllFilesWhere should SQL-escape the query
return query; return query;
} }

View File

@ -46,6 +46,9 @@ AddLogicalImageTask.noCurrentCase=No current case
# {1} - fields length # {1} - fields length
# {2} - expected length # {2} - expected length
AddLogicalImageTask.notEnoughFields=File does not contain enough fields at line {0}, got {1}, expecting {2} AddLogicalImageTask.notEnoughFields=File does not contain enough fields at line {0}, got {1}, expecting {2}
# {0} - file number
# {1} - total files
AddLogicalImageTask.searchingInterestingFile=Searching for interesting files ({0}/{1})
# {0} - imageFilePath # {0} - imageFilePath
AddMultipleImagesTask.adding=Adding: {0} AddMultipleImagesTask.adding=Adding: {0}
# {0} - file # {0} - file

View File

@ -770,8 +770,11 @@ final public class ViewFrame extends BorderPane {
Notifications.create().owner(getScene().getWindow()) Notifications.create().owner(getScene().getWindow())
.text(Bundle.ViewFrame_pickerListener_errorMessage()) .text(Bundle.ViewFrame_pickerListener_errorMessage())
.showError(); .showError();
logger.log(Level.SEVERE, "Error responding to date/time picker change.", ex); logger.log(Level.WARNING, "Error responding to date/time picker change.", ex); //NON-NLS
} catch (IllegalArgumentException ex ) {
logger.log(Level.INFO, "Timeline: User supplied invalid time range."); //NON-NLS
} }
Platform.runLater(ViewFrame.this::refreshTimeUI); Platform.runLater(ViewFrame.this::refreshTimeUI);
} }
} }

View File

@ -192,33 +192,29 @@ The first question that you must answer is what type of data do you want the use
-# Data that is in a big text file or some other report that the user can review. To do this, you will use the Case.addReport() method to make the output available in the directory tree. -# Data that is in a big text file or some other report that the user can review. To do this, you will use the Case.addReport() method to make the output available in the directory tree.
\subsection ingest_modules_making_results_bb Posting Results to the Blackboard \subsection ingest_modules_making_results_bb Saving Results to the Blackboard
The blackboard is used to store results so that they are displayed in the results tree. The blackboard is used to store results so that they are displayed in the results tree.
See \ref platform_blackboard for details on posting results to it. You use the blackboard when you have specific items to show the user. if you want to just shown them a big report from another library or tool, see \ref mod_report_page. See \ref platform_blackboard for details on saving results to it. You use the blackboard when you have specific items to show the user. If you want to just shown them a big report from another library or tool, see \ref mod_report_page.
The blackboard defines artifacts for specific data types (such as web bookmarks). The blackboard defines artifacts for specific data types (such as web bookmarks).
You can use one of the standard artifact types or create your own. You can use one of the standard artifact types or create your own.
When modules add data to the blackboard, they should notify listeners of the new After you've added an artifact and all of its attributes to the blackboard, you should call <a href="http://sleuthkit.org/sleuthkit/docs/jni-docs/4.6/classorg_1_1sleuthkit_1_1datamodel_1_1_blackboard.html">sleuthkit.Blackboard.postArtifact()</a>, which will:
data by invoking the org.sleuthkit.autopsy.ingest.IngestServices.fireModuleDataEvent() method. <ul>
Do so as soon as you have added an artifact to the blackboard. <li>Analyze the artifact and add any timestamps to the Timeline tables
This allows other modules (and the main UI) to know when to query the blackboard <li>Send an event over the Sleuth Kit event bus that the artifact(s) was added
for the latest data. However, if you are writing a large number of blackboard <ul>
artifacts in a loop, it is better to invoke org.sleuthkit.autopsy.ingest.IngestServices.fireModuleDataEvent() <li>Autopsy is a listener of this event bus and will rebroadcast the event to other Autopsy modules
only once after the bulk write, so as not to flood the system with events. <li>Keyword search also listens for this event and will index the artifact
</ul>
</ul>
Further, when modules create artifacts, they should be indexed for keyword search, This means you no longer have to make separate calls to:
using the method org.sleuthkit.autopsy.casemodule.services.Blackboard.indexArtifact(BlackboardArtifact artifact). This can be done - Index the artifact
in the following way: - Fire the event to refresh the UI.
\code If you are creating a large number of artifacts, you may see better performance if you save all the artifacts you create and do one bulk post at the end using <a href="http://sleuthkit.org/sleuthkit/docs/jni-docs/4.6/classorg_1_1sleuthkit_1_1datamodel_1_1_blackboard.html">sleuthkit.Blackboard.postArtifacts()</a>. You can also post batches of artifacts instead of saving all of them until the end.
Blackboard blackboard = Case.getCurrentCase().getServices().getBlackboard();
try { You should not be using the Autopsy version of Blackboard. Those methods have all been deprecated and is another example of us moving "services" into the TSK data model.
blackboard.indexArtifact(artifact); //Your artifact as the argument.
}
catch (BlackboardException ex) {
//YOUR EXCEPTION BEHAVIOR HERE.
}
\endcode
\subsection ingest_modules_making_results_report Making a Report \subsection ingest_modules_making_results_report Making a Report

View File

@ -52,7 +52,7 @@ The blackboard allows modules to communicate with each other and the UI. It has
The blackboard is not unique to Autopsy. It is part of The Sleuth Kit datamodel and The Sleuth Kit Framework. In the name of reducing the amount of documentation that we need to maintain, we provide links here to those documentation sources. The blackboard is not unique to Autopsy. It is part of The Sleuth Kit datamodel and The Sleuth Kit Framework. In the name of reducing the amount of documentation that we need to maintain, we provide links here to those documentation sources.
- <a href="http://sleuthkit.org/sleuthkit/docs/jni-docs/4.3/mod_bbpage.html">The Blackboard</a> - <a href="http://sleuthkit.org/sleuthkit/docs/jni-docs/4.6/mod_bbpage.html">The Blackboard</a>
\subsection mod_dev_other_services Framework Services and Utilities \subsection mod_dev_other_services Framework Services and Utilities

View File

@ -224,8 +224,6 @@ final class VcardParser {
if (!tskBlackboard.artifactExists(abstractFile, BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT, attributes)) { if (!tskBlackboard.artifactExists(abstractFile, BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT, attributes)) {
artifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT); artifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT);
artifact.addAttributes(attributes); artifact.addAttributes(attributes);
List<BlackboardArtifact> blackboardArtifacts = new ArrayList<>();
blackboardArtifacts.add(artifact);
extractPhotos(vcard, abstractFile, artifact); extractPhotos(vcard, abstractFile, artifact);
@ -388,8 +386,12 @@ final class VcardParser {
*/ */
private void addPhoneAttributes(Telephone telephone, AbstractFile abstractFile, Collection<BlackboardAttribute> attributes) { private void addPhoneAttributes(Telephone telephone, AbstractFile abstractFile, Collection<BlackboardAttribute> attributes) {
String telephoneText = telephone.getText(); String telephoneText = telephone.getText();
if (telephoneText == null || telephoneText.isEmpty()) { if (telephoneText == null || telephoneText.isEmpty()) {
return; telephoneText = telephone.getUri().getNumber();
if (telephoneText == null || telephoneText.isEmpty()) {
return;
}
} }
// Add phone number to collection for later creation of TSK_CONTACT. // Add phone number to collection for later creation of TSK_CONTACT.
@ -408,20 +410,25 @@ final class VcardParser {
type.getValue().toUpperCase().replaceAll("\\s+","").split(",")); type.getValue().toUpperCase().replaceAll("\\s+","").split(","));
for (String splitType : splitTelephoneTypes) { for (String splitType : splitTelephoneTypes) {
String attributeTypeName = "TSK_PHONE_NUMBER_" + splitType; String attributeTypeName = "TSK_PHONE_NUMBER";
if(splitType != null && !splitType.isEmpty()) {
attributeTypeName = "TSK_PHONE_NUMBER_" + splitType;
}
try { try {
BlackboardAttribute.Type attributeType = tskCase.getAttributeType(attributeTypeName); BlackboardAttribute.Type attributeType = tskCase.getAttributeType(attributeTypeName);
if (attributeType == null) { if (attributeType == null) {
// Add this attribute type to the case database. // Add this attribute type to the case database.
attributeType = tskCase.addArtifactAttributeType(attributeTypeName, attributeType = tskCase.addArtifactAttributeType(attributeTypeName,
BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.STRING, BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.STRING,
String.format("Phone (%s)", StringUtils.capitalize(splitType.toLowerCase()))); String.format("Phone Number (%s)", StringUtils.capitalize(splitType.toLowerCase())));
} }
ThunderbirdMboxFileIngestModule.addArtifactAttribute(telephone.getText(), attributeType, attributes); ThunderbirdMboxFileIngestModule.addArtifactAttribute(telephoneText, attributeType, attributes);
} catch (TskCoreException ex) { } 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); logger.log(Level.WARNING, String.format("Unable to retrieve attribute type '%s' for file '%s' (id=%d).", attributeTypeName, abstractFile.getName(), abstractFile.getId()), ex);
} catch (TskDataException 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); logger.log(Level.WARNING, String.format("Unable to add custom attribute type '%s' for file '%s' (id=%d).", attributeTypeName, abstractFile.getName(), abstractFile.getId()), ex);
} }
} }
} }
@ -490,7 +497,11 @@ final class VcardParser {
private void addPhoneAccountInstances(Telephone telephone, AbstractFile abstractFile, Collection<AccountFileInstance> accountInstances) { private void addPhoneAccountInstances(Telephone telephone, AbstractFile abstractFile, Collection<AccountFileInstance> accountInstances) {
String telephoneText = telephone.getText(); String telephoneText = telephone.getText();
if (telephoneText == null || telephoneText.isEmpty()) { if (telephoneText == null || telephoneText.isEmpty()) {
return; telephoneText = telephone.getUri().getNumber();
if (telephoneText == null || telephoneText.isEmpty()) {
return;
}
} }
// Add phone number as a TSK_ACCOUNT. // Add phone number as a TSK_ACCOUNT.