Merge branch 'develop' of https://github.com/sleuthkit/autopsy into 1143-cache-for-updatefile

# Conflicts:
#	Core/src/org/sleuthkit/autopsy/modules/exif/ExifParserFileIngestModule.java
This commit is contained in:
Raman 2018-12-07 14:03:02 -05:00
commit 43b580052b
65 changed files with 2355 additions and 914 deletions

View File

@ -32,6 +32,8 @@
<dependency conf="core->default" org="org.jsoup" name="jsoup" rev="1.10.3"/>
<dependency conf="core->default" org="com.googlecode.plist" name="dd-plist" rev="1.20"/>
<dependency conf="core->default" org="com.fasterxml.jackson.core" name="jackson-core" rev="2.9.7"/>
<dependency conf="core->default" org="commons-validator" name="commons-validator" rev="1.6"/>
</dependencies>

View File

@ -4,6 +4,7 @@ file.reference.commons-compress-1.14.jar=release/modules/ext/commons-compress-1.
file.reference.commons-dbcp2-2.1.1.jar=release\\modules\\ext\\commons-dbcp2-2.1.1.jar
file.reference.commons-pool2-2.4.2.jar=release\\modules\\ext\\commons-pool2-2.4.2.jar
file.reference.dd-plist-1.20.jar=release/modules/ext/dd-plist-1.20.jar
file.reference.jackson-core-2.9.7.jar=release/modules/ext/jackson-core-2.9.7.jar
file.reference.jdom-2.0.5-contrib.jar=release/modules/ext/jdom-2.0.5-contrib.jar
file.reference.jdom-2.0.5.jar=release/modules/ext/jdom-2.0.5.jar
file.reference.jgraphx-v3.8.0.jar=release/modules/ext/jgraphx-v3.8.0.jar

View File

@ -433,6 +433,10 @@
<runtime-relative-path>ext/curator-client-2.8.0.jar</runtime-relative-path>
<binary-origin>release/modules/ext/curator-client-2.8.0.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/jackson-core-2.9.7.jar</runtime-relative-path>
<binary-origin>release/modules/ext/jackson-core-2.9.7.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/cxf-rt-frontend-jaxrs-3.0.16.jar</runtime-relative-path>
<binary-origin>release/modules/ext/cxf-rt-frontend-jaxrs-3.0.16.jar</binary-origin>

View File

@ -1120,7 +1120,12 @@ public class Case {
/*
* Enable the case-specific actions.
*/
CallableSystemAction.get(AddImageAction.class).setEnabled(true);
//Deny ability to add a data source if the special admin access file is present.
File denyAddDataSourcePermissions = new File(PlatformUtil.getUserConfigDirectory(), "_ndsp");
if(!denyAddDataSourcePermissions.exists()) {
CallableSystemAction.get(AddImageAction.class).setEnabled(true);
}
CallableSystemAction.get(CaseCloseAction.class).setEnabled(true);
CallableSystemAction.get(CasePropertiesAction.class).setEnabled(true);
CallableSystemAction.get(CaseDeleteAction.class).setEnabled(true);

View File

@ -25,36 +25,41 @@ import org.apache.commons.validator.routines.DomainValidator;
import org.apache.commons.validator.routines.EmailValidator;
/**
* Provides functions for normalizing data by attribute type before insertion or querying.
* Provides functions for normalizing data by attribute type before insertion or
* querying.
*/
final public class CorrelationAttributeNormalizer {
//common seperators that may be removed for normalizing
private static final String SEPERATORS_REGEX = "[\\s-:]";
/**
* This is a utility class - no need for constructing or subclassing, etc...
*/
private CorrelationAttributeNormalizer() { }
private CorrelationAttributeNormalizer() {
}
/**
* Normalize the data. Converts text to lower case, and ensures that the
* Normalize the data. Converts text to lower case, and ensures that the
* data is a valid string of the format expected given the attributeType.
*
* @param attributeType correlation type of data
* @param data data to normalize
* @param data data to normalize
*
* @return normalized data
*/
public static String normalize(CorrelationAttributeInstance.Type attributeType, String data) throws CorrelationAttributeNormalizationException {
if(attributeType == null){
if (attributeType == null) {
throw new CorrelationAttributeNormalizationException("Attribute type was null.");
}
if(data == null){
if (data == null) {
throw new CorrelationAttributeNormalizationException("Data was null.");
}
String trimmedData = data.trim();
switch(attributeType.getId()){
switch (attributeType.getId()) {
case CorrelationAttributeInstance.FILES_TYPE_ID:
return normalizeMd5(trimmedData);
case CorrelationAttributeInstance.DOMAIN_TYPE_ID:
@ -66,15 +71,16 @@ final public class CorrelationAttributeNormalizer {
case CorrelationAttributeInstance.USBID_TYPE_ID:
return normalizeUsbId(trimmedData);
case CorrelationAttributeInstance.SSID_TYPE_ID:
return trimmedData;
return verifySsid(trimmedData);
case CorrelationAttributeInstance.MAC_TYPE_ID:
return trimmedData;
return normalizeMac(trimmedData);
case CorrelationAttributeInstance.IMEI_TYPE_ID:
return trimmedData;
return normalizeImei(trimmedData);
case CorrelationAttributeInstance.IMSI_TYPE_ID:
return trimmedData;
return normalizeImsi(trimmedData);
case CorrelationAttributeInstance.ICCID_TYPE_ID:
return trimmedData;
return normalizeIccid(trimmedData);
default:
final String errorMessage = String.format(
"Validator function not found for attribute type: %s",
@ -84,11 +90,11 @@ final public class CorrelationAttributeNormalizer {
}
/**
* Validate the data. Converts text to lower case, and ensures that the
* data is a valid string of the format expected given the attributeType.
* Validate the data. Converts text to lower case, and ensures that the data
* is a valid string of the format expected given the attributeType.
*
* @param attributeTypeId correlation type of data
* @param data data to normalize
* @param data data to normalize
*
* @return normalized data
*/
@ -97,7 +103,7 @@ final public class CorrelationAttributeNormalizer {
List<CorrelationAttributeInstance.Type> defaultTypes = CorrelationAttributeInstance.getDefaultCorrelationTypes();
Optional<CorrelationAttributeInstance.Type> typeOption = defaultTypes.stream().filter(attributeType -> attributeType.getId() == attributeTypeId).findAny();
if(typeOption.isPresent()){
if (typeOption.isPresent()) {
CorrelationAttributeInstance.Type type = typeOption.get();
return CorrelationAttributeNormalizer.normalize(type, data);
} else {
@ -114,7 +120,7 @@ final public class CorrelationAttributeNormalizer {
private static String normalizeMd5(String data) throws CorrelationAttributeNormalizationException {
final String validMd5Regex = "^[a-f0-9]{32}$";
final String dataLowered = data.toLowerCase();
if(dataLowered.matches(validMd5Regex)){
if (dataLowered.matches(validMd5Regex)) {
return dataLowered;
} else {
throw new CorrelationAttributeNormalizationException(String.format("Data purporting to be an MD5 was found not to comform to expected format: %s", data));
@ -122,15 +128,16 @@ final public class CorrelationAttributeNormalizer {
}
/**
* Verify there are no slashes or invalid domain name characters (such as '?' or \: ). Normalize to lower case.
* Verify there are no slashes or invalid domain name characters (such as
* '?' or \: ). Normalize to lower case.
*/
private static String normalizeDomain(String data) throws CorrelationAttributeNormalizationException {
DomainValidator validator = DomainValidator.getInstance(true);
if(validator.isValid(data)){
if (validator.isValid(data)) {
return data.toLowerCase();
} else {
final String validIpAddressRegex = "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$";
if(data.matches(validIpAddressRegex)){
if (data.matches(validIpAddressRegex)) {
return data;
} else {
throw new CorrelationAttributeNormalizationException(String.format("Data was expected to be a valid domain: %s", data));
@ -139,11 +146,12 @@ final public class CorrelationAttributeNormalizer {
}
/**
* Verify that there is an '@' and no invalid characters. Should normalize to lower case.
* Verify that there is an '@' and no invalid characters. Should normalize
* to lower case.
*/
private static String normalizeEmail(String data) throws CorrelationAttributeNormalizationException {
EmailValidator validator = EmailValidator.getInstance(true, true);
if(validator.isValid(data)){
if (validator.isValid(data)) {
return data.toLowerCase();
} else {
throw new CorrelationAttributeNormalizationException(String.format("Data was expected to be a valid email address: %s", data));
@ -154,7 +162,7 @@ final public class CorrelationAttributeNormalizer {
* Verify it is only numbers and '+'. Strip spaces, dashes, and parentheses.
*/
private static String normalizePhone(String data) throws CorrelationAttributeNormalizationException {
if(data.matches("\\+?[0-9()\\-\\s]+")){
if (data.matches("\\+?[0-9()\\-\\s]+")) {
String phoneNumber = data.replaceAll("[^0-9\\+]", "");
return phoneNumber;
} else {
@ -169,4 +177,137 @@ final public class CorrelationAttributeNormalizer {
//TODO replace with correct usb id validation at a later date
return data;
}
/**
* Verify the wireless network name is valid
*
* SSIDs for wireless networks can be at most 32 characters, are case
* sensitive, and allow special characters.
*
* @param data The string to normalize and validate
*
* @return the unmodified data if the data was a valid length to be an SSID
*
* @throws CorrelationAttributeNormalizationException if the data was not a
* valid SSID
*/
private static String verifySsid(String data) throws CorrelationAttributeNormalizationException {
if (data.length() <= 32) {
return data;
} else {
throw new CorrelationAttributeNormalizationException("Name provided was longer than the maximum valid SSID (32 characters). Name: " + data);
}
}
/**
* Verify the ICCID (Integrated Circuit Card Identifier) number and
* normalize format.
*
* E.118 defines as up to 22 digits long including luhn check digit while
* GSM Phase 1 defines it as a 20 digit operator specific structure. They
* begin with 89 which is the ISO 7812 Major Industry Identifier for
* telecommunication, followed by a contry code of 1-3 digits as definted by
* ITU-T E.164, followed by issuer identifier 1-4 digits, followed by 1 luhn
* checksum digit (sometimes omitted). The hexidecimal digit F is used as
* filler when necessary in GSM Phase 1 specification.
*
* 18 digits appears to be the shortest ICCID in use.
*
* @param data The string to normalize and validate
*
* @return the data with common number seperators removed and lower cased if
* the data was determined to be a possible ICCID
*
* @throws CorrelationAttributeNormalizationException if the data was not a
* valid ICCID
*/
private static String normalizeIccid(String data) throws CorrelationAttributeNormalizationException {
final String validIccidRegex = "^89[f0-9]{17,22}$";
final String iccidWithoutSeperators = data.toLowerCase().replaceAll(SEPERATORS_REGEX, "");
if (iccidWithoutSeperators.matches(validIccidRegex)) {
return iccidWithoutSeperators;
} else {
throw new CorrelationAttributeNormalizationException("Data provided was not a valid ICCID. : " + data);
}
}
/**
* Verify the IMSI (International mobile subscriber identity) number and
* normalize format.
*
* First 3 digits Mobile Country Code 2-3 digits Mobile Network Code Up to
* 10 digits for mobile subscriber identification number MSIN
*
* Length will be 14 or 15 digits total
*
* @param data The string to normalize and validate
*
* @return the data with common number seperators removed if the data was
* determined to be a possible IMSI
*
* @throws CorrelationAttributeNormalizationException if the data was not a
* valid IMSI
*/
private static String normalizeImsi(String data) throws CorrelationAttributeNormalizationException {
final String validImsiRegex = "^[0-9]{14,15}$";
final String imsiWithoutSeperators = data.replaceAll(SEPERATORS_REGEX, "");
if (imsiWithoutSeperators.matches(validImsiRegex)) {
return imsiWithoutSeperators;
} else {
throw new CorrelationAttributeNormalizationException("Data provided was not a valid Imsi. : " + data);
}
}
/**
* Verify the MAC (media access control) address and normalize format.
*
* A 12 or 16 Hexadecimal digits long depending on standard (Possible
* standards EUI-48, MAC-48, EUI-64)
*
* @param data The string to normalize and validate
*
* @return the data with common number seperators removed and lowercased if
* the data was determined to be a possible MAC
*
* @throws CorrelationAttributeNormalizationException if the data was not a
* valid MAC
*/
private static String normalizeMac(String data) throws CorrelationAttributeNormalizationException {
final String validMacRegex = "^([a-f0-9]{12}|[a-f0-9]{16})$";
final String macWithoutSeperators = data.toLowerCase().replaceAll(SEPERATORS_REGEX, "");
if (macWithoutSeperators.matches(validMacRegex)) {
return macWithoutSeperators;
} else {
throw new CorrelationAttributeNormalizationException("Data provided was not a valid Imsi. : " + data);
}
}
/**
* Verify the IMEI (International Mobile Equipment Identity) number and
* normalize format.
*
* 14 to 16 digits digits 1 through 6 are TAC (Type Allocation Code) digits
* 7 and 8 are also part of the TAC in phones made in 2003 or later digits 7
* and 8 are FAC (Final Assembly Code) in phones made prior to 2003 digits 9
* through 14 are the serial number digits 15 and 16 if present represent an
* optional luhn checksum (or software version number when dealing with an
* IMEI software version)
*
* @param data The string to normalize and validate
*
* @return the data with common number seperators removed if the data was
* determined to be a possible IMEI
*
* @throws CorrelationAttributeNormalizationException if the data was not a
* valid IMEI
*/
private static String normalizeImei(String data) throws CorrelationAttributeNormalizationException {
final String validImeiRegex = "^[0-9]{14,16}$";
final String imeiWithoutSeperators = data.replaceAll(SEPERATORS_REGEX, "");
if (imeiWithoutSeperators.matches(validImeiRegex)) {
return imeiWithoutSeperators;
} else {
throw new CorrelationAttributeNormalizationException("Data provided was not a valid Imsi. : " + data);
}
}
}

View File

@ -48,6 +48,7 @@ import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb;
import org.sleuthkit.autopsy.coreutils.ThreadUtils;
import org.sleuthkit.datamodel.SleuthkitCase;
/**
* Listen for ingest events and update entries in the Central Repository
@ -168,29 +169,34 @@ public class IngestEventsListener {
static private void postCorrelatedBadArtifactToBlackboard(BlackboardArtifact bbArtifact, List<String> caseDisplayNames) {
try {
AbstractFile af = bbArtifact.getSleuthkitCase().getAbstractFileById(bbArtifact.getObjectID());
Collection<BlackboardAttribute> attributes = new ArrayList<>();
String MODULE_NAME = Bundle.IngestEventsListener_ingestmodule_name();
BlackboardArtifact tifArtifact = af.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT);
BlackboardAttribute att = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME, MODULE_NAME,
Bundle.IngestEventsListener_prevTaggedSet_text());
BlackboardAttribute att2 = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT, MODULE_NAME,
Bundle.IngestEventsListener_prevCaseComment_text() + caseDisplayNames.stream().distinct().collect(Collectors.joining(",", "", "")));
attributes.add(att);
attributes.add(att2);
Collection<BlackboardAttribute> attributes = new ArrayList<>();
attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME, MODULE_NAME,
Bundle.IngestEventsListener_prevTaggedSet_text()));
attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT, MODULE_NAME,
Bundle.IngestEventsListener_prevCaseComment_text() + caseDisplayNames.stream().distinct().collect(Collectors.joining(",", "", ""))));
attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT, MODULE_NAME, bbArtifact.getArtifactID()));
tifArtifact.addAttributes(attributes);
try {
// index the artifact for keyword search
Blackboard blackboard = Case.getCurrentCaseThrows().getServices().getBlackboard();
blackboard.indexArtifact(tifArtifact);
} catch (Blackboard.BlackboardException | NoCurrentCaseException ex) {
LOGGER.log(Level.SEVERE, "Unable to index blackboard artifact " + tifArtifact.getArtifactID(), ex); //NON-NLS
}
SleuthkitCase tskCase = bbArtifact.getSleuthkitCase();
AbstractFile abstractFile = tskCase.getAbstractFileById(bbArtifact.getObjectID());
org.sleuthkit.datamodel.Blackboard tskBlackboard = tskCase.getBlackboard();
// Create artifact if it doesn't already exist.
if (!tskBlackboard.artifactExists(abstractFile, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT, attributes)) {
BlackboardArtifact tifArtifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT);
tifArtifact.addAttributes(attributes);
// fire event to notify UI of this new artifact
IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent(MODULE_NAME, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT));
try {
// index the artifact for keyword search
Blackboard blackboard = Case.getCurrentCaseThrows().getServices().getBlackboard();
blackboard.indexArtifact(tifArtifact);
} catch (Blackboard.BlackboardException | NoCurrentCaseException ex) {
LOGGER.log(Level.SEVERE, "Unable to index blackboard artifact " + tifArtifact.getArtifactID(), ex); //NON-NLS
}
// fire event to notify UI of this new artifact
IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent(MODULE_NAME, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT));
}
} catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, "Failed to create BlackboardArtifact.", ex); // NON-NLS
} catch (IllegalStateException ex) {
@ -211,26 +217,33 @@ public class IngestEventsListener {
static private void postCorrelatedPreviousArtifactToBlackboard(BlackboardArtifact bbArtifact) {
try {
AbstractFile af = bbArtifact.getSleuthkitCase().getAbstractFileById(bbArtifact.getObjectID());
Collection<BlackboardAttribute> attributes = new ArrayList<>();
String MODULE_NAME = Bundle.IngestEventsListener_ingestmodule_name();
BlackboardArtifact tifArtifact = af.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT);
Collection<BlackboardAttribute> attributes = new ArrayList<>();
BlackboardAttribute att = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME, MODULE_NAME,
Bundle.IngestEventsListener_prevExists_text());
attributes.add(att);
attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT, MODULE_NAME, bbArtifact.getArtifactID()));
tifArtifact.addAttributes(attributes);
try {
// index the artifact for keyword search
Blackboard blackboard = Case.getCurrentCaseThrows().getServices().getBlackboard();
blackboard.indexArtifact(tifArtifact);
} catch (Blackboard.BlackboardException | NoCurrentCaseException ex) {
LOGGER.log(Level.SEVERE, "Unable to index blackboard artifact " + tifArtifact.getArtifactID(), ex); //NON-NLS
}
SleuthkitCase tskCase = bbArtifact.getSleuthkitCase();
AbstractFile abstractFile = bbArtifact.getSleuthkitCase().getAbstractFileById(bbArtifact.getObjectID());
org.sleuthkit.datamodel.Blackboard tskBlackboard = tskCase.getBlackboard();
// Create artifact if it doesn't already exist.
if (!tskBlackboard.artifactExists(abstractFile, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT, attributes)) {
BlackboardArtifact tifArtifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT);
tifArtifact.addAttributes(attributes);
// fire event to notify UI of this new artifact
IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent(MODULE_NAME, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT));
try {
// index the artifact for keyword search
Blackboard blackboard = Case.getCurrentCaseThrows().getServices().getBlackboard();
blackboard.indexArtifact(tifArtifact);
} catch (Blackboard.BlackboardException | NoCurrentCaseException ex) {
LOGGER.log(Level.SEVERE, "Unable to index blackboard artifact " + tifArtifact.getArtifactID(), ex); //NON-NLS
}
// fire event to notify UI of this new artifact
IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent(MODULE_NAME, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT));
}
} catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, "Failed to create BlackboardArtifact.", ex); // NON-NLS
} catch (IllegalStateException ex) {

View File

@ -18,6 +18,8 @@
*/
package org.sleuthkit.autopsy.centralrepository.ingestmodule;
import java.util.ArrayList;
import java.util.Collection;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
import java.util.List;
@ -51,19 +53,20 @@ import org.sleuthkit.datamodel.TskData;
import org.sleuthkit.autopsy.centralrepository.eventlisteners.IngestEventsListener;
import org.sleuthkit.autopsy.healthmonitor.HealthMonitor;
import org.sleuthkit.autopsy.healthmonitor.TimingMetric;
import org.sleuthkit.datamodel.SleuthkitCase;
/**
* Ingest module for inserting entries into the Central Repository database on
* ingest of a data source
*/
@Messages({"IngestModule.prevTaggedSet.text=Previously Tagged As Notable (Central Repository)",
"IngestModule.prevCaseComment.text=Previous Case: "})
final class IngestModule implements FileIngestModule {
@Messages({"CentralRepoIngestModule.prevTaggedSet.text=Previously Tagged As Notable (Central Repository)",
"CentralRepoIngestModule.prevCaseComment.text=Previous Case: "})
final class CentralRepoIngestModule implements FileIngestModule {
static final boolean DEFAULT_FLAG_TAGGED_NOTABLE_ITEMS = true;
static final boolean DEFAULT_FLAG_PREVIOUS_DEVICES = true;
private final static Logger logger = Logger.getLogger(IngestModule.class.getName());
private final static Logger logger = Logger.getLogger(CentralRepoIngestModule.class.getName());
private final IngestServices services = IngestServices.getInstance();
private static final IngestModuleReferenceCounter refCounter = new IngestModuleReferenceCounter();
private static final IngestModuleReferenceCounter warningMsgRefCounter = new IngestModuleReferenceCounter();
@ -80,7 +83,7 @@ final class IngestModule implements FileIngestModule {
*
* @param settings The ingest settings for the module instance.
*/
IngestModule(IngestSettings settings) {
CentralRepoIngestModule(IngestSettings settings) {
flagTaggedNotableItems = settings.isFlagTaggedNotableItems();
flagPreviouslySeenDevices = settings.isFlagPreviousDevices();
}
@ -207,8 +210,8 @@ final class IngestModule implements FileIngestModule {
// see ArtifactManagerTimeTester for details
@Messages({
"IngestModule.notfyBubble.title=Central Repository Not Initialized",
"IngestModule.errorMessage.isNotEnabled=Central repository settings are not initialized, cannot run Correlation Engine ingest module."
"CentralRepoIngestModule.notfyBubble.title=Central Repository Not Initialized",
"CentralRepoIngestModule.errorMessage.isNotEnabled=Central repository settings are not initialized, cannot run Correlation Engine ingest module."
})
@Override
public void startUp(IngestJobContext context) throws IngestModuleException {
@ -245,7 +248,7 @@ final class IngestModule implements FileIngestModule {
*/
if (RuntimeProperties.runningWithGUI()) {
if (1L == warningMsgRefCounter.incrementAndGet(jobId)) {
MessageNotifyUtil.Notify.warn(Bundle.IngestModule_notfyBubble_title(), Bundle.IngestModule_errorMessage_isNotEnabled());
MessageNotifyUtil.Notify.warn(Bundle.CentralRepoIngestModule_notfyBubble_title(), Bundle.CentralRepoIngestModule_errorMessage_isNotEnabled());
}
}
return;
@ -320,34 +323,49 @@ final class IngestModule implements FileIngestModule {
}
}
/**
* Post a new interesting artifact for the file marked bad.
*
* @param abstractFile The file from which to create an artifact.
* @param caseDisplayNames Case names to be added to a TSK_COMMON attribute.
*/
private void postCorrelatedBadFileToBlackboard(AbstractFile abstractFile, List<String> caseDisplayNames) {
try {
String MODULE_NAME = IngestModuleFactory.getModuleName();
BlackboardArtifact tifArtifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT);
BlackboardAttribute att = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME, MODULE_NAME,
Bundle.IngestModule_prevTaggedSet_text());
BlackboardAttribute att2 = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT, MODULE_NAME,
Bundle.IngestModule_prevCaseComment_text() + caseDisplayNames.stream().distinct().collect(Collectors.joining(",", "", "")));
tifArtifact.addAttribute(att);
tifArtifact.addAttribute(att2);
String MODULE_NAME = CentralRepoIngestModuleFactory.getModuleName();
try {
// index the artifact for keyword search
blackboard.indexArtifact(tifArtifact);
} catch (Blackboard.BlackboardException ex) {
logger.log(Level.SEVERE, "Unable to index blackboard artifact " + tifArtifact.getArtifactID(), ex); //NON-NLS
Collection<BlackboardAttribute> attributes = new ArrayList<>();
attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME, MODULE_NAME,
Bundle.CentralRepoIngestModule_prevTaggedSet_text()));
attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT, MODULE_NAME,
Bundle.CentralRepoIngestModule_prevCaseComment_text() + caseDisplayNames.stream().distinct().collect(Collectors.joining(",", "", ""))));
SleuthkitCase tskCase = Case.getCurrentCaseThrows().getSleuthkitCase();
org.sleuthkit.datamodel.Blackboard tskBlackboard = tskCase.getBlackboard();
// Create artifact if it doesn't already exist.
if (!tskBlackboard.artifactExists(abstractFile, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT, attributes)) {
BlackboardArtifact tifArtifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT);
tifArtifact.addAttributes(attributes);
try {
// index the artifact for keyword search
blackboard.indexArtifact(tifArtifact);
} catch (Blackboard.BlackboardException ex) {
logger.log(Level.SEVERE, "Unable to index blackboard artifact " + tifArtifact.getArtifactID(), ex); //NON-NLS
}
// send inbox message
sendBadFileInboxMessage(tifArtifact, abstractFile.getName(), abstractFile.getMd5Hash());
// fire event to notify UI of this new artifact
services.fireModuleDataEvent(new ModuleDataEvent(MODULE_NAME, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT));
}
// send inbox message
sendBadFileInboxMessage(tifArtifact, abstractFile.getName(), abstractFile.getMd5Hash());
// fire event to notify UI of this new artifact
services.fireModuleDataEvent(new ModuleDataEvent(MODULE_NAME, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT));
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Failed to create BlackboardArtifact.", ex); // NON-NLS
} catch (IllegalStateException ex) {
logger.log(Level.SEVERE, "Failed to create BlackboardAttribute.", ex); // NON-NLS
} catch (NoCurrentCaseException ex) {
logger.log(Level.SEVERE, "Exception while getting open case.", ex); // NON-NLS
}
}
@ -359,12 +377,12 @@ final class IngestModule implements FileIngestModule {
* @param name badFile's name
* @param md5Hash badFile's md5 hash
*/
@Messages({"IngestModule.postToBB.fileName=File Name",
"IngestModule.postToBB.md5Hash=MD5 Hash",
"IngestModule.postToBB.hashSetSource=Source of Hash",
"IngestModule.postToBB.eamHit=Central Repository",
@Messages({"CentralRepoIngestModule.postToBB.fileName=File Name",
"CentralRepoIngestModule.postToBB.md5Hash=MD5 Hash",
"CentralRepoIngestModule.postToBB.hashSetSource=Source of Hash",
"CentralRepoIngestModule.postToBB.eamHit=Central Repository",
"# {0} - Name of file that is Notable",
"IngestModule.postToBB.knownBadMsg=Notable: {0}"})
"CentralRepoIngestModule.postToBB.knownBadMsg=Notable: {0}"})
public void sendBadFileInboxMessage(BlackboardArtifact artifact, String name, String md5Hash) {
StringBuilder detailsSb = new StringBuilder();
//details
@ -372,7 +390,7 @@ final class IngestModule implements FileIngestModule {
//hit
detailsSb.append("<tr>"); //NON-NLS
detailsSb.append("<th>") //NON-NLS
.append(Bundle.IngestModule_postToBB_fileName())
.append(Bundle.CentralRepoIngestModule_postToBB_fileName())
.append("</th>"); //NON-NLS
detailsSb.append("<td>") //NON-NLS
.append(name)
@ -381,22 +399,22 @@ final class IngestModule implements FileIngestModule {
detailsSb.append("<tr>"); //NON-NLS
detailsSb.append("<th>") //NON-NLS
.append(Bundle.IngestModule_postToBB_md5Hash())
.append(Bundle.CentralRepoIngestModule_postToBB_md5Hash())
.append("</th>"); //NON-NLS
detailsSb.append("<td>").append(md5Hash).append("</td>"); //NON-NLS
detailsSb.append("</tr>"); //NON-NLS
detailsSb.append("<tr>"); //NON-NLS
detailsSb.append("<th>") //NON-NLS
.append(Bundle.IngestModule_postToBB_hashSetSource())
.append(Bundle.CentralRepoIngestModule_postToBB_hashSetSource())
.append("</th>"); //NON-NLS
detailsSb.append("<td>").append(Bundle.IngestModule_postToBB_eamHit()).append("</td>"); //NON-NLS
detailsSb.append("<td>").append(Bundle.CentralRepoIngestModule_postToBB_eamHit()).append("</td>"); //NON-NLS
detailsSb.append("</tr>"); //NON-NLS
detailsSb.append("</table>"); //NON-NLS
services.postMessage(IngestMessage.createDataMessage(IngestModuleFactory.getModuleName(),
Bundle.IngestModule_postToBB_knownBadMsg(name),
services.postMessage(IngestMessage.createDataMessage(CentralRepoIngestModuleFactory.getModuleName(),
Bundle.CentralRepoIngestModule_postToBB_knownBadMsg(name),
detailsSb.toString(),
name + md5Hash,
artifact));

View File

@ -33,9 +33,9 @@ import org.sleuthkit.autopsy.ingest.NoIngestModuleIngestJobSettings;
* Factory for Central Repository ingest modules
*/
@ServiceProvider(service = org.sleuthkit.autopsy.ingest.IngestModuleFactory.class)
@NbBundle.Messages({"IngestModuleFactory.ingestmodule.name=Correlation Engine",
"IngestModuleFactory.ingestmodule.desc=Saves properties to the central repository for later correlation"})
public class IngestModuleFactory extends IngestModuleFactoryAdapter {
@NbBundle.Messages({"CentralRepoIngestModuleFactory.ingestmodule.name=Correlation Engine",
"CentralRepoIngestModuleFactory.ingestmodule.desc=Saves properties to the central repository for later correlation"})
public class CentralRepoIngestModuleFactory extends IngestModuleFactoryAdapter {
/**
* Get the name of the module.
@ -43,7 +43,7 @@ public class IngestModuleFactory extends IngestModuleFactoryAdapter {
* @return The module name.
*/
public static String getModuleName() {
return Bundle.IngestModuleFactory_ingestmodule_name();
return Bundle.CentralRepoIngestModuleFactory_ingestmodule_name();
}
@Override
@ -53,7 +53,7 @@ public class IngestModuleFactory extends IngestModuleFactoryAdapter {
@Override
public String getModuleDescription() {
return Bundle.IngestModuleFactory_ingestmodule_desc();
return Bundle.CentralRepoIngestModuleFactory_ingestmodule_desc();
}
@Override
@ -69,13 +69,13 @@ public class IngestModuleFactory extends IngestModuleFactoryAdapter {
@Override
public FileIngestModule createFileIngestModule(IngestModuleIngestJobSettings settings) {
if (settings instanceof IngestSettings) {
return new IngestModule((IngestSettings) settings);
return new CentralRepoIngestModule((IngestSettings) settings);
}
/*
* Compatibility check for older versions.
*/
if (settings instanceof NoIngestModuleIngestJobSettings) {
return new IngestModule(new IngestSettings());
return new CentralRepoIngestModule(new IngestSettings());
}
throw new IllegalArgumentException("Expected settings argument to be an instance of IngestSettings");

View File

@ -34,8 +34,8 @@ final class IngestSettings implements IngestModuleIngestJobSettings {
* Instantiate the ingest job settings with default values.
*/
IngestSettings() {
this.flagTaggedNotableItems = IngestModule.DEFAULT_FLAG_TAGGED_NOTABLE_ITEMS;
this.flagPreviousDevices = IngestModule.DEFAULT_FLAG_PREVIOUS_DEVICES;
this.flagTaggedNotableItems = CentralRepoIngestModule.DEFAULT_FLAG_TAGGED_NOTABLE_ITEMS;
this.flagPreviousDevices = CentralRepoIngestModule.DEFAULT_FLAG_PREVIOUS_DEVICES;
}
/**

View File

@ -58,7 +58,7 @@
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<Component id="errorText" pref="300" max="32767" attributes="0"/>
<Component id="errorText" max="32767" attributes="0"/>
<EmptySpace min="-2" pref="65" max="-2" attributes="0"/>
<Component id="searchButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
@ -77,7 +77,7 @@
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="103" groupAlignment="1" max="-2" attributes="0">
<Component id="commonItemSearchDescription" alignment="0" max="32767" attributes="0"/>
<Component id="commonItemSearchDescription" alignment="0" pref="403" max="32767" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="20" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" max="-2" attributes="0">

View File

@ -18,6 +18,8 @@
*/
package org.sleuthkit.autopsy.commonfilesearch;
import org.sleuthkit.autopsy.guiutils.DataSourceComboBoxModel;
import org.sleuthkit.autopsy.guiutils.DataSourceLoader;
import java.awt.Dimension;
import java.sql.SQLException;
import java.util.ArrayList;
@ -48,7 +50,7 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationDataSource;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
import org.sleuthkit.autopsy.centralrepository.ingestmodule.IngestModuleFactory;
import org.sleuthkit.autopsy.centralrepository.ingestmodule.CentralRepoIngestModuleFactory;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataResultViewer;
import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent;
import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable;
@ -706,7 +708,7 @@ final class CommonAttributePanel extends javax.swing.JDialog implements Observer
}
//if the eamdb is enabled and an instance is able to be retrieved check if each data source has been processed into the cr
HashMap<DataSource, CorrelatedStatus> dataSourceCorrelationMap = new HashMap<>(); //keep track of the status of all data sources that have been ingested
String correlationEngineModuleName = IngestModuleFactory.getModuleName();
String correlationEngineModuleName = CentralRepoIngestModuleFactory.getModuleName();
SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase();
List<CorrelationDataSource> correlatedDataSources = EamDb.getInstance().getDataSources();
List<IngestJobInfo> ingestJobs = skCase.getIngestJobs();

View File

@ -19,6 +19,7 @@
*/
package org.sleuthkit.autopsy.commonfilesearch;
import org.sleuthkit.autopsy.guiutils.DataSourceComboBoxModel;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;

View File

@ -19,6 +19,7 @@
*/
package org.sleuthkit.autopsy.commonfilesearch;
import org.sleuthkit.autopsy.guiutils.DataSourceComboBoxModel;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

View File

@ -26,6 +26,8 @@ import org.openide.util.lookup.ServiceProvider;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer;
import org.sleuthkit.autopsy.datamodel.ContentUtils;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Image;
import org.sleuthkit.datamodel.DataSource;
import org.sleuthkit.datamodel.FsContent;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM;
@ -123,11 +125,18 @@ public class Metadata extends javax.swing.JPanel implements DataContentViewer {
@Messages({
"Metadata.tableRowTitle.mimeType=MIME Type",
"Metadata.nodeText.truncated=(results truncated)"})
"Metadata.nodeText.truncated=(results truncated)",
"Metadata.tableRowTitle.sha1=SHA1",
"Metadata.tableRowTitle.sha256=SHA256",
"Metadata.tableRowTitle.imageType=Type",
"Metadata.tableRowTitle.sectorSize=Sector Size",
"Metadata.tableRowTitle.timezone=Time Zone",
"Metadata.tableRowTitle.deviceId=Device ID"})
@Override
public void setNode(Node node) {
AbstractFile file = node.getLookup().lookup(AbstractFile.class);
if (file == null) {
Image image = node.getLookup().lookup((Image.class));
if (file == null && image == null) {
setText(NbBundle.getMessage(this.getClass(), "Metadata.nodeText.nonFilePassedIn"));
return;
}
@ -135,64 +144,100 @@ public class Metadata extends javax.swing.JPanel implements DataContentViewer {
StringBuilder sb = new StringBuilder();
startTable(sb);
try {
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.name"), file.getUniquePath());
} catch (TskCoreException ex) {
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.name"), file.getParentPath() + "/" + file.getName());
}
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.type"), file.getType().getName());
addRow(sb, Bundle.Metadata_tableRowTitle_mimeType(), file.getMIMEType());
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.size"), Long.toString(file.getSize()));
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.fileNameAlloc"), file.getDirFlagAsString());
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.metadataAlloc"), file.getMetaFlagsAsString());
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.modified"), ContentUtils.getStringTime(file.getMtime(), file));
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.accessed"), ContentUtils.getStringTime(file.getAtime(), file));
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.created"), ContentUtils.getStringTime(file.getCrtime(), file));
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.changed"), ContentUtils.getStringTime(file.getCtime(), file));
String md5 = file.getMd5Hash();
if (md5 == null) {
md5 = NbBundle.getMessage(this.getClass(), "Metadata.tableRowContent.md5notCalc");
}
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.md5"), md5);
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.hashLookupResults"), file.getKnown().toString());
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.internalid"), Long.toString(file.getId()));
if (file.getType().compareTo(TSK_DB_FILES_TYPE_ENUM.LOCAL) == 0) {
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.localPath"), file.getLocalAbsPath());
}
endTable(sb);
/*
* If we have a file system file, grab the more detailed metadata text
* too
*/
try {
if (file instanceof FsContent) {
FsContent fsFile = (FsContent) file;
sb.append("<hr /><pre>\n"); //NON-NLS
sb.append(NbBundle.getMessage(this.getClass(), "Metadata.nodeText.text"));
sb.append(" <br /><br />"); // NON-NLS
for (String str : fsFile.getMetaDataText()) {
sb.append(str).append("<br />"); //NON-NLS
/*
* Very long results can cause the UI to hang before displaying,
* so truncate the results if necessary.
*/
if(sb.length() > 50000){
sb.append(NbBundle.getMessage(this.getClass(), "Metadata.nodeText.truncated"));
break;
}
}
sb.append("</pre>\n"); //NON-NLS
if (file != null) {
try {
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.name"), file.getUniquePath());
} catch (TskCoreException ex) {
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.name"), file.getParentPath() + "/" + file.getName());
}
} catch (TskCoreException ex) {
sb.append(NbBundle.getMessage(this.getClass(), "Metadata.nodeText.exceptionNotice.text")).append(ex.getLocalizedMessage());
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.type"), file.getType().getName());
addRow(sb, Bundle.Metadata_tableRowTitle_mimeType(), file.getMIMEType());
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.size"), Long.toString(file.getSize()));
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.fileNameAlloc"), file.getDirFlagAsString());
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.metadataAlloc"), file.getMetaFlagsAsString());
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.modified"), ContentUtils.getStringTime(file.getMtime(), file));
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.accessed"), ContentUtils.getStringTime(file.getAtime(), file));
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.created"), ContentUtils.getStringTime(file.getCrtime(), file));
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.changed"), ContentUtils.getStringTime(file.getCtime(), file));
String md5 = file.getMd5Hash();
if (md5 == null) {
md5 = NbBundle.getMessage(this.getClass(), "Metadata.tableRowContent.md5notCalc");
}
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.md5"), md5);
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.hashLookupResults"), file.getKnown().toString());
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.internalid"), Long.toString(file.getId()));
if (file.getType().compareTo(TSK_DB_FILES_TYPE_ENUM.LOCAL) == 0) {
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.localPath"), file.getLocalAbsPath());
}
endTable(sb);
/*
* If we have a file system file, grab the more detailed metadata text
* too
*/
try {
if (file instanceof FsContent) {
FsContent fsFile = (FsContent) file;
sb.append("<hr /><pre>\n"); //NON-NLS
sb.append(NbBundle.getMessage(this.getClass(), "Metadata.nodeText.text"));
sb.append(" <br /><br />"); // NON-NLS
for (String str : fsFile.getMetaDataText()) {
sb.append(str).append("<br />"); //NON-NLS
/*
* Very long results can cause the UI to hang before displaying,
* so truncate the results if necessary.
*/
if(sb.length() > 50000){
sb.append(NbBundle.getMessage(this.getClass(), "Metadata.nodeText.truncated"));
break;
}
}
sb.append("</pre>\n"); //NON-NLS
}
} catch (TskCoreException ex) {
sb.append(NbBundle.getMessage(this.getClass(), "Metadata.nodeText.exceptionNotice.text")).append(ex.getLocalizedMessage());
}
} else {
try {
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.name"), image.getUniquePath());
} catch (TskCoreException ex) {
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.name"), image.getName());
}
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.imageType"), image.getType().getName());
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.size"), Long.toString(image.getSize()));
try {
String md5 = image.getMd5();
if (md5 == null || md5.isEmpty()) {
md5 = NbBundle.getMessage(this.getClass(), "Metadata.tableRowContent.md5notCalc");
}
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.md5"), md5);
String sha1 = image.getSha1();
if (sha1 == null || sha1.isEmpty()) {
sha1 = NbBundle.getMessage(this.getClass(), "Metadata.tableRowContent.md5notCalc");
}
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.sha1"), sha1);
String sha256 = image.getSha256();
if (sha256 == null || sha256.isEmpty()) {
sha256 = NbBundle.getMessage(this.getClass(), "Metadata.tableRowContent.md5notCalc");
}
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.sha256"), sha256);
} catch (TskCoreException ex) {
sb.append(NbBundle.getMessage(this.getClass(), "Metadata.nodeText.exceptionNotice.text")).append(ex.getLocalizedMessage());
}
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.sectorSize"), Long.toString(image.getSsize()));
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.timezone"), image.getTimeZone());
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.deviceId"), image.getDeviceId());
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.internalid"), Long.toString(image.getId()));
}
setText(sb.toString());
@ -227,8 +272,9 @@ public class Metadata extends javax.swing.JPanel implements DataContentViewer {
@Override
public boolean isSupported(Node node) {
Image image = node.getLookup().lookup(Image.class);
AbstractFile file = node.getLookup().lookup(AbstractFile.class);
return file != null;
return (file != null) || (image != null);
}
@Override

View File

@ -75,6 +75,8 @@ public final class UserPreferences {
public static final String SHOW_ONLY_CURRENT_USER_TAGS = "ShowOnlyCurrentUserTags";
public static final String HIDE_CENTRAL_REPO_COMMENTS_AND_OCCURRENCES = "HideCentralRepoCommentsAndOccurrences";
public static final String DISPLAY_TRANSLATED_NAMES = "DisplayTranslatedNames";
public static final String MAXIMUM_NUMBER_OF_RESULTS = "MaximumNumberOfResults";
private static final int DEFAULT_MAX_RESULTS = 20000;
// Prevent instantiation.
private UserPreferences() {
@ -471,4 +473,20 @@ public final class UserPreferences {
public static void setLogFileCount(int count) {
preferences.putInt(MAX_NUM_OF_LOG_FILE, count);
}
/**
* Set the maximum number of result rows to show in data result tables.
* @param max
*/
public static void setMaximumNumberOfResults(int max) {
preferences.putInt(MAXIMUM_NUMBER_OF_RESULTS, max);
}
/**
* Get the maximum number of result rows to show in data result tables.
* @return
*/
public static int getMaximumNumberOfResults() {
return preferences.getInt(MAXIMUM_NUMBER_OF_RESULTS, DEFAULT_MAX_RESULTS);
}
}

View File

@ -337,6 +337,11 @@
<attr name="instanceCreate" methodvalue="org.sleuthkit.autopsy.modules.stix.STIXReportModule.getDefault"/>
<attr name="position" intvalue="910"/>
</file>
<file name="org-sleuthkit-autopsy-modules-case_uco-ReportCaseUco.instance">
<attr name="instanceOf" stringvalue="org.sleuthkit.autopsy.report.GeneralReportModule"/>
<attr name="instanceCreate" methodvalue="org.sleuthkit.autopsy.modules.case_uco.ReportCaseUco.getDefault"/>
<attr name="position" intvalue="911"/>
</file>
<!--<folder name="JavaHelp">
<file name="casemodule-helpset.xml" url="casemodule-helpset.xml">
<attr name="position" intvalue="3075"/>

View File

@ -171,11 +171,13 @@ OptionsCategory_Name_View=View
OptionsCategory_Keywords_View=View
ViewPreferencesPanel.currentSessionSettingsPanel.border.title=Current Session Settings
ViewPreferencesPanel.hideRejectedResultsCheckbox.text=Hide rejected results
ViewPreferencesPanel.translateTextLabel.text=Translate text in the:
ViewPreferencesPanel.selectFileLabel.text=When selecting a file:
ViewPreferencesPanel.globalSettingsPanel.border.title=Global Settings
ViewPreferencesPanel.translateNamesInTableRadioButton.text=Table
ViewPreferencesPanel.deletedFilesLimitLabel.text=Limit number of deleted files displayed:
ViewPreferencesPanel.deletedFilesLimitCheckbox.text=Limit to 10,000
ViewPreferencesPanel.commentsOccurencesColumnWrapAroundText.text=to reduce loading times
ViewPreferencesPanel.translateTextLabel.text=Translate text in the:
ViewPreferencesPanel.maximumResultsLabel.toolTipText=Maximum numer of rows to display in result tables. 0 = unlimited
ViewPreferencesPanel.maximumResultsLabel.text=Maximum number of results to display:
ViewPreferencesPanel.commentsOccurencesColumnsCheckbox.text=C(omments) and O(ccurences) columns
ViewPreferencesPanel.centralRepoLabel.text=Do not use Central Repository for:
ViewPreferencesPanel.hideOtherUsersTagsLabel.text=Hide other users' tags in the:
@ -193,5 +195,3 @@ ViewPreferencesPanel.keepCurrentViewerRadioButton.toolTipText=For example, stay
ViewPreferencesPanel.keepCurrentViewerRadioButton.text=Stay on the same file viewer
ViewPreferencesPanel.useBestViewerRadioButton.toolTipText=For example, change from Hex to Media when a JPEG is selected.
ViewPreferencesPanel.useBestViewerRadioButton.text=Change to the most specific file viewer
ViewPreferencesPanel.selectFileLabel.text=When selecting a file:
ViewPreferencesPanel.commentsOccurencesColumnWrapAroundText.text=to reduce loading times

View File

@ -120,7 +120,6 @@ MediaViewImagePanel.externalViewerButton.text=\u5916\u90e8\u30d3\u30e5\u30fc\u30
DataResultPanel.matchLabel.text=\u7d50\u679c
DataResultPanel.numberOfChildNodesLabel.text=0
DataResultPanel.descriptionLabel.text=\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u30d1\u30b9
ViewPreferencesPanel.selectFileLabel.text=\u30d5\u30a1\u30a4\u30eb\u3092\u9078\u629e\u3059\u308b\u5834\u5408\uff1a
ViewPreferencesPanel.useLocalTimeRadioButton.text=\u30ed\u30fc\u30ab\u30eb\u30bf\u30a4\u30e0\u30be\u30fc\u30f3\u3092\u4f7f\u7528
ViewPreferencesPanel.displayTimeLabel.text=\u6642\u9593\u3092\u8868\u793a\u3059\u308b\u5834\u5408\uff1a
ViewPreferencesPanel.viewsHideKnownCheckbox.text=\u30d3\u30e5\u30fc\u30a8\u30ea\u30a2
@ -130,3 +129,4 @@ ViewPreferencesPanel.keepCurrentViewerRadioButton.toolTipText=\u4f8b\u3048\u3070
ViewPreferencesPanel.keepCurrentViewerRadioButton.text=\u305d\u306e\u307e\u307e\u540c\u3058\u30d5\u30a1\u30a4\u30eb\u30d3\u30e5\u30fc\u30a2\u3092\u4f7f\u7528
ViewPreferencesPanel.useBestViewerRadioButton.toolTipText=\u4f8b\u3048\u3070\u3001JPEG\u304c\u9078\u629e\u3055\u308c\u305f\u5834\u5408\u306b\u306fHEX\u304b\u3089\u30e1\u30c7\u30a3\u30a2\u306b\u5909\u66f4\u3059\u308b\u3002
ViewPreferencesPanel.useBestViewerRadioButton.text=\u6700\u3082\u5c02\u9580\u7684\u306a\u30d5\u30a1\u30a4\u30eb\u30d3\u30e5\u30fc\u30a2\u306b\u5909\u66f4
ViewPreferencesPanel.selectFileLabel.text=\u30d5\u30a1\u30a4\u30eb\u3092\u9078\u629e\u3059\u308b\u5834\u5408\uff1a

View File

@ -18,9 +18,14 @@
*/
package org.sleuthkit.autopsy.corecomponents;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import org.openide.nodes.Children;
import org.openide.nodes.FilterNode;
import org.openide.nodes.Node;
import org.openide.util.NbBundle;
import org.openide.windows.WindowManager;
import org.sleuthkit.autopsy.core.UserPreferences;
/**
* A <code>Children</code> implementation for a
@ -31,17 +36,21 @@ import org.openide.nodes.Node;
*/
class TableFilterChildren extends FilterNode.Children {
private int numberOfNodesCreated;
private static volatile boolean maxResultsDialogShown = false;
/**
* Creates a Children object for a TableFilterNode. A TableFilterNode
creates at most one layer of child nodes for the node it wraps. It is
designed to be used in the results view to ensure the individual viewers
display only the first layer of child nodes.
* creates at most one layer of child nodes for the node it wraps. It is
* designed to be used in the results view to ensure the individual viewers
* display only the first layer of child nodes.
*
* @param wrappedNode The node wrapped by the TableFilterNode.
* @param wrappedNode The node wrapped by the TableFilterNode.
* @param createChildren True if a children (child factory) object should be
* created for the wrapped node.
* created for the wrapped node.
*
* @return A children (child factory) object for a node wrapped by a TableFilterNode.
* @return A children (child factory) object for a node wrapped by a
* TableFilterNode.
*/
public static Children createInstance(Node wrappedNode, boolean createChildren) {
@ -54,20 +63,20 @@ class TableFilterChildren extends FilterNode.Children {
/**
* Constructs a children (child factory) implementation for a
* <code>TableFilterNode</code>. A
* <code>TableFilterNode</code> creates at most one layer of
* child nodes for the node it wraps. It is designed to be used for nodes
* displayed in Autopsy table views.
* <code>TableFilterNode</code>. A <code>TableFilterNode</code> creates at
* most one layer of child nodes for the node it wraps. It is designed to be
* used for nodes displayed in Autopsy table views.
*
* @param wrappedNode The node wrapped by the TableFilterNode.
*/
TableFilterChildren(Node wrappedNode) {
super(wrappedNode);
numberOfNodesCreated = 0;
}
/**
* Copies a TableFilterNode, with the create children
(child factory) flag set to false.
* Copies a TableFilterNode, with the create children (child factory) flag
* set to false.
*
* @param nodeToCopy The TableFilterNode to copy.
*
@ -87,7 +96,41 @@ class TableFilterChildren extends FilterNode.Children {
* @return
*/
@Override
@NbBundle.Messages({"# {0} - The results limit",
"TableFilterChildren.createNodes.limitReached.msg="
+ "The limit on the number of results to display has been reached."
+ " Only the first {0} results will be shown."
+ " The limit can be modified under Tools, Options, View."})
protected Node[] createNodes(Node key) {
return new Node[]{this.copyNode(key)};
int maxNodesToCreate = UserPreferences.getMaximumNumberOfResults();
if (maxNodesToCreate == 0 || numberOfNodesCreated < maxNodesToCreate) {
// We either haven't hit the limit yet, or we don't have a limit.
/**
* We only want to apply the limit to "our" nodes (i.e. not the
* wait node). If we don't do this the "Please wait..."
* node causes the number of results in the table to be off by one.
* Using the Bundle to get the value so that we are not tied to a
* particular locale.
*/
if (!key.getDisplayName().equalsIgnoreCase(NbBundle.getMessage(Node.class, "LBL_WAIT"))) {
numberOfNodesCreated++;
// If we have a limit and the creation of this node reaches it,
// tell the user if they haven't already been told.
if (numberOfNodesCreated == maxNodesToCreate && !maxResultsDialogShown) {
maxResultsDialogShown = true;
SwingUtilities.invokeLater(()
-> JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
Bundle.TableFilterChildren_createNodes_limitReached_msg(maxNodesToCreate))
);
}
}
return new Node[]{this.copyNode(key)};
} else {
return new Node[]{};
}
}
}

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.4" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<Properties>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[625, 465]"/>
@ -26,7 +26,7 @@
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="viewPreferencesScrollPane" alignment="0" max="32767" attributes="0"/>
<Component id="viewPreferencesScrollPane" alignment="0" pref="528" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
</Layout>
@ -92,9 +92,13 @@
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace min="10" pref="10" max="-2" attributes="0"/>
<Component id="hideOtherUsersTagsCheckbox" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<Component id="centralRepoLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="135" max="-2" attributes="0"/>
@ -149,16 +153,13 @@
</Group>
</Group>
</Group>
<Component id="deletedFilesLimitLabel" min="-2" pref="215" max="-2" attributes="0"/>
<Group type="102" attributes="0">
<EmptySpace min="10" pref="10" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="hideOtherUsersTagsCheckbox" min="-2" max="-2" attributes="0"/>
<Component id="deletedFilesLimitCheckbox" pref="567" max="32767" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<Component id="maximumResultsLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="maximumResultsSpinner" min="-2" pref="70" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@ -189,8 +190,11 @@
<Component id="commentsOccurencesColumnsCheckbox" min="-2" pref="18" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="commentsOccurencesColumnWrapAroundText" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="11" max="-2" attributes="0"/>
<Component id="deletedFilesLimitLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="6" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="maximumResultsLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="maximumResultsSpinner" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<Group type="102" alignment="0" attributes="0">
<Component id="selectFileLabel" min="-2" max="-2" attributes="0"/>
@ -212,9 +216,7 @@
<Component id="translateNamesInTableRadioButton" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Component id="deletedFilesLimitCheckbox" min="-2" pref="26" max="-2" attributes="0"/>
<EmptySpace pref="8" max="32767" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@ -369,20 +371,13 @@
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="commentsOccurencesColumnsCheckboxActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="deletedFilesLimitCheckbox">
<Component class="javax.swing.JLabel" name="maximumResultsLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="ViewPreferencesPanel.deletedFilesLimitCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="ViewPreferencesPanel.maximumResultsLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="deletedFilesLimitCheckboxActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="deletedFilesLimitLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="ViewPreferencesPanel.deletedFilesLimitLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="ViewPreferencesPanel.maximumResultsLabel.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
@ -432,6 +427,16 @@
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="translateNamesInTableRadioButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JSpinner" name="maximumResultsSpinner">
<Properties>
<Property name="model" type="javax.swing.SpinnerModel" editor="org.netbeans.modules.form.editors2.SpinnerModelEditor">
<SpinnerModel initial="20000" maximum="100000" minimum="0" numberType="java.lang.Integer" stepSize="10000" type="number"/>
</Property>
</Properties>
<Events>
<EventHandler event="stateChanged" listener="javax.swing.event.ChangeListener" parameters="javax.swing.event.ChangeEvent" handler="maximumResultsSpinnerStateChanged"/>
</Events>
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="currentCaseSettingsPanel">

View File

@ -29,7 +29,6 @@ import org.sleuthkit.autopsy.casemodule.CasePreferences;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbUtil;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.coreutils.TimeZoneUtils;
import org.sleuthkit.autopsy.deletedFiles.DeletedFilePreferences;
import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent;
import org.sleuthkit.autopsy.texttranslation.TextTranslationService;
@ -79,9 +78,9 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
commentsOccurencesColumnsCheckbox.setEnabled(EamDbUtil.useCentralRepo());
commentsOccurencesColumnWrapAroundText.setEnabled(EamDbUtil.useCentralRepo());
commentsOccurencesColumnsCheckbox.setSelected(UserPreferences.hideCentralRepoCommentsAndOccurrences());
maximumResultsSpinner.setValue(UserPreferences.getMaximumNumberOfResults());
hideOtherUsersTagsCheckbox.setSelected(UserPreferences.showOnlyCurrentUserTags());
deletedFilesLimitCheckbox.setSelected(DeletedFilePreferences.getDefault().getShouldLimitDeletedFiles());
translateNamesInTableRadioButton.setSelected(UserPreferences.displayTranslatedFileNames());
TextTranslationService tts = TextTranslationService.getInstance();
@ -116,12 +115,11 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
UserPreferences.setShowOnlyCurrentUserTags(hideOtherUsersTagsCheckbox.isSelected());
UserPreferences.setHideCentralRepoCommentsAndOccurrences(commentsOccurencesColumnsCheckbox.isSelected());
UserPreferences.setDisplayTranslatedFileNames(translateNamesInTableRadioButton.isSelected());
UserPreferences.setMaximumNumberOfResults((Integer)maximumResultsSpinner.getValue());
storeGroupItemsInTreeByDataSource();
DirectoryTreeTopComponent.getDefault().setShowRejectedResults(hideRejectedResultsCheckbox.isSelected() == false);
DeletedFilePreferences.getDefault().setShouldLimitDeletedFiles(deletedFilesLimitCheckbox.isSelected());
}
/**
@ -166,13 +164,13 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
hideOtherUsersTagsLabel = new javax.swing.JLabel();
centralRepoLabel = new javax.swing.JLabel();
commentsOccurencesColumnsCheckbox = new javax.swing.JCheckBox();
deletedFilesLimitCheckbox = new javax.swing.JCheckBox();
deletedFilesLimitLabel = new javax.swing.JLabel();
maximumResultsLabel = new javax.swing.JLabel();
jScrollPane1 = new javax.swing.JScrollPane();
timeZoneList = new javax.swing.JList<>();
translateTextLabel = new javax.swing.JLabel();
commentsOccurencesColumnWrapAroundText = new javax.swing.JLabel();
translateNamesInTableRadioButton = new javax.swing.JRadioButton();
maximumResultsSpinner = new javax.swing.JSpinner();
currentCaseSettingsPanel = new javax.swing.JPanel();
groupByDataSourceCheckbox = new javax.swing.JCheckBox();
currentSessionSettingsPanel = new javax.swing.JPanel();
@ -272,14 +270,8 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
}
});
org.openide.awt.Mnemonics.setLocalizedText(deletedFilesLimitCheckbox, org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.deletedFilesLimitCheckbox.text")); // NOI18N
deletedFilesLimitCheckbox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
deletedFilesLimitCheckboxActionPerformed(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(deletedFilesLimitLabel, org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.deletedFilesLimitLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(maximumResultsLabel, org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.maximumResultsLabel.text")); // NOI18N
maximumResultsLabel.setToolTipText(org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.maximumResultsLabel.toolTipText")); // NOI18N
timeZoneList.addListSelectionListener(new javax.swing.event.ListSelectionListener() {
public void valueChanged(javax.swing.event.ListSelectionEvent evt) {
@ -299,6 +291,13 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
}
});
maximumResultsSpinner.setModel(new javax.swing.SpinnerNumberModel(20000, 0, 100000, 10000));
maximumResultsSpinner.addChangeListener(new javax.swing.event.ChangeListener() {
public void stateChanged(javax.swing.event.ChangeEvent evt) {
maximumResultsSpinnerStateChanged(evt);
}
});
javax.swing.GroupLayout globalSettingsPanelLayout = new javax.swing.GroupLayout(globalSettingsPanel);
globalSettingsPanel.setLayout(globalSettingsPanelLayout);
globalSettingsPanelLayout.setHorizontalGroup(
@ -306,6 +305,9 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
.addGroup(globalSettingsPanelLayout.createSequentialGroup()
.addContainerGap()
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(globalSettingsPanelLayout.createSequentialGroup()
.addGap(10, 10, 10)
.addComponent(hideOtherUsersTagsCheckbox))
.addGroup(globalSettingsPanelLayout.createSequentialGroup()
.addComponent(centralRepoLabel)
.addGap(135, 135, 135)
@ -346,13 +348,11 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
.addComponent(useLocalTimeRadioButton)
.addComponent(useAnotherTimeRadioButton)
.addComponent(translateNamesInTableRadioButton)))))
.addComponent(deletedFilesLimitLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 215, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGroup(globalSettingsPanelLayout.createSequentialGroup()
.addGap(10, 10, 10)
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(hideOtherUsersTagsCheckbox)
.addComponent(deletedFilesLimitCheckbox, javax.swing.GroupLayout.DEFAULT_SIZE, 567, Short.MAX_VALUE))))
.addContainerGap())
.addComponent(maximumResultsLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(maximumResultsSpinner, javax.swing.GroupLayout.PREFERRED_SIZE, 70, javax.swing.GroupLayout.PREFERRED_SIZE)))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
globalSettingsPanelLayout.setVerticalGroup(
globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
@ -381,8 +381,10 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
.addComponent(commentsOccurencesColumnsCheckbox, javax.swing.GroupLayout.PREFERRED_SIZE, 18, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(commentsOccurencesColumnWrapAroundText)
.addGap(11, 11, 11)
.addComponent(deletedFilesLimitLabel))
.addGap(6, 6, 6)
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(maximumResultsLabel)
.addComponent(maximumResultsSpinner, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))
.addGroup(globalSettingsPanelLayout.createSequentialGroup()
.addComponent(selectFileLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
@ -401,9 +403,7 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
.addComponent(translateTextLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(translateNamesInTableRadioButton)))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(deletedFilesLimitCheckbox, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(8, Short.MAX_VALUE))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
currentCaseSettingsPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.currentCaseSettingsPanel.border.title"))); // NOI18N
@ -489,7 +489,7 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(viewPreferencesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(viewPreferencesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 528, Short.MAX_VALUE)
);
}// </editor-fold>//GEN-END:initComponents
@ -525,14 +525,6 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
}
}//GEN-LAST:event_timeZoneListValueChanged
private void deletedFilesLimitCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deletedFilesLimitCheckboxActionPerformed
if (immediateUpdates) {
DeletedFilePreferences.getDefault().setShouldLimitDeletedFiles(deletedFilesLimitCheckbox.isSelected());
} else {
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}
}//GEN-LAST:event_deletedFilesLimitCheckboxActionPerformed
private void commentsOccurencesColumnsCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_commentsOccurencesColumnsCheckboxActionPerformed
if (immediateUpdates) {
UserPreferences.setHideCentralRepoCommentsAndOccurrences(commentsOccurencesColumnsCheckbox.isSelected());
@ -623,6 +615,14 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
}
}//GEN-LAST:event_useBestViewerRadioButtonActionPerformed
private void maximumResultsSpinnerStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_maximumResultsSpinnerStateChanged
if (immediateUpdates) {
UserPreferences.setMaximumNumberOfResults((Integer)maximumResultsSpinner.getValue());
} else {
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}
}//GEN-LAST:event_maximumResultsSpinnerStateChanged
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JLabel centralRepoLabel;
@ -632,8 +632,6 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
private javax.swing.JPanel currentSessionSettingsPanel;
private javax.swing.JCheckBox dataSourcesHideKnownCheckbox;
private javax.swing.JCheckBox dataSourcesHideSlackCheckbox;
private javax.swing.JCheckBox deletedFilesLimitCheckbox;
private javax.swing.JLabel deletedFilesLimitLabel;
private javax.swing.JLabel displayTimeLabel;
private javax.swing.JPanel globalSettingsPanel;
private javax.swing.JCheckBox groupByDataSourceCheckbox;
@ -644,6 +642,8 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
private javax.swing.JLabel hideSlackFilesLabel;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JRadioButton keepCurrentViewerRadioButton;
private javax.swing.JLabel maximumResultsLabel;
private javax.swing.JSpinner maximumResultsSpinner;
private javax.swing.JLabel selectFileLabel;
private javax.swing.JList<String> timeZoneList;
private javax.swing.JRadioButton translateNamesInTableRadioButton;

View File

@ -29,8 +29,6 @@ import java.util.Observable;
import java.util.Observer;
import java.util.Set;
import java.util.logging.Level;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import org.openide.nodes.AbstractNode;
import org.openide.nodes.ChildFactory;
import org.openide.nodes.Children;
@ -38,14 +36,11 @@ import org.openide.nodes.Node;
import org.openide.nodes.Sheet;
import org.openide.util.NbBundle;
import org.openide.util.lookup.Lookups;
import org.openide.windows.WindowManager;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.CasePreferences;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.coreutils.Logger;
import static org.sleuthkit.autopsy.datamodel.Bundle.*;
import org.sleuthkit.autopsy.deletedFiles.DeletedFilePreferences;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Content;
@ -57,6 +52,7 @@ import org.sleuthkit.datamodel.LayoutFile;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData;
import org.sleuthkit.datamodel.VirtualDirectory;
/**
* deleted content view nodes
@ -404,25 +400,8 @@ public class DeletedContent implements AutopsyVisitableItem {
}
@Override
@NbBundle.Messages({"# {0} - The deleted files threshold",
"DeletedContent.createKeys.maxObjects.msg="
+ "There are more Deleted Files than can be displayed."
+ " Only the first {0} Deleted Files will be shown."})
protected boolean createKeys(List<AbstractFile> list) {
DeletedFilePreferences deletedPreferences = DeletedFilePreferences.getDefault();
List<AbstractFile> queryList = runFsQuery();
if (deletedPreferences.getShouldLimitDeletedFiles() && queryList.size() == deletedPreferences.getDeletedFilesLimit()) {
queryList.remove(queryList.size() - 1);
// only show the dialog once - not each time we refresh
if (maxFilesDialogShown == false) {
maxFilesDialogShown = true;
SwingUtilities.invokeLater(()
-> JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
DeletedContent_createKeys_maxObjects_msg(deletedPreferences.getDeletedFilesLimit() - 1))
);
}
}
list.addAll(queryList);
list.addAll(runFsQuery());
return true;
}
@ -467,9 +446,8 @@ public class DeletedContent implements AutopsyVisitableItem {
if (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)) {
query += " AND data_source_obj_id = " + filteringDSObjId;
}
DeletedFilePreferences deletedPreferences = DeletedFilePreferences.getDefault();
if (deletedPreferences.getShouldLimitDeletedFiles()) {
query += " LIMIT " + deletedPreferences.getDeletedFilesLimit(); //NON-NLS
if (UserPreferences.getMaximumNumberOfResults() != 0) {
query += " LIMIT " + UserPreferences.getMaximumNumberOfResults(); //NON-NLS
}
return query;
}
@ -531,6 +509,11 @@ public class DeletedContent implements AutopsyVisitableItem {
return new FileNode(f, false);
}
@Override
public FileNode visit(VirtualDirectory f) {
return new FileNode(f, false);
}
@Override
protected AbstractNode defaultVisit(Content di) {
throw new UnsupportedOperationException("Not supported for this type of Displayable Item: " + di.toString());

View File

@ -158,6 +158,14 @@ public class ExtractedContent implements AutopsyVisitableItem {
return filePath + "face.png"; //NON-NLS
} else if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_WIFI_NETWORK.getTypeID()) {
return filePath + "network-wifi.png"; //NON-NLS
} else if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_WIFI_NETWORK_ADAPTER.getTypeID()) {
return filePath + "network-wifi.png"; //NON-NLS
} else if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_SIM_ATTACHED.getTypeID()) {
return filePath + "sim_card.png"; //NON-NLS
} else if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_BLUETOOTH_ADAPTER.getTypeID()) {
return filePath + "Bluetooth.png"; //NON-NLS
} else if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_DEVICE_INFO.getTypeID()) {
return filePath + "devices.png"; //NON-NLS
}
return filePath + "artifact-icon.png"; //NON-NLS
}

View File

@ -125,9 +125,6 @@ public class ImageNode extends AbstractContentNode<Image> {
"ImageNode.createSheet.sectorSize.name=Sector Size (Bytes)",
"ImageNode.createSheet.sectorSize.displayName=Sector Size (Bytes)",
"ImageNode.createSheet.sectorSize.desc=Sector size of the image in bytes.",
"ImageNode.createSheet.md5.name=MD5 Hash",
"ImageNode.createSheet.md5.displayName=MD5 Hash",
"ImageNode.createSheet.md5.desc=MD5 Hash of the image",
"ImageNode.createSheet.timezone.name=Timezone",
"ImageNode.createSheet.timezone.displayName=Timezone",
"ImageNode.createSheet.timezone.desc=Timezone of the image",
@ -161,11 +158,6 @@ public class ImageNode extends AbstractContentNode<Image> {
Bundle.ImageNode_createSheet_sectorSize_desc(),
this.content.getSsize()));
sheetSet.put(new NodeProperty<>(Bundle.ImageNode_createSheet_md5_name(),
Bundle.ImageNode_createSheet_md5_displayName(),
Bundle.ImageNode_createSheet_md5_desc(),
this.content.getMd5()));
sheetSet.put(new NodeProperty<>(Bundle.ImageNode_createSheet_timezone_name(),
Bundle.ImageNode_createSheet_timezone_displayName(),
Bundle.ImageNode_createSheet_timezone_desc(),

View File

@ -858,14 +858,17 @@ public class KeywordHits implements AutopsyVisitableItem {
try {
BlackboardArtifact art = skCase.getBlackboardArtifact(artifactId);
BlackboardArtifactNode n = new BlackboardArtifactNode(art);
AbstractFile file;
try {
file = skCase.getAbstractFileById(art.getObjectID());
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "TskCoreException while constructing BlackboardArtifact Node from KeywordHitsKeywordChildren", ex); //NON-NLS
return n;
// The associated file should be available through the Lookup that
// gets created when the BlackboardArtifactNode is constructed.
AbstractFile file = n.getLookup().lookup(AbstractFile.class);
if (file == null) {
try {
file = skCase.getAbstractFileById(art.getObjectID());
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "TskCoreException while constructing BlackboardArtifact Node from KeywordHitsKeywordChildren", ex); //NON-NLS
return n;
}
}
/*
* It is possible to get a keyword hit on artifacts generated for
* the underlying image in which case MAC times are not

View File

@ -1,171 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.deletedFiles;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Properties;
import java.util.logging.Level;
import org.sleuthkit.autopsy.casemodule.CasePreferences;
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent;
/**
* Class to store settings related to the display of deleted files.
*/
public class DeletedFilePreferences {
private static final String SETTINGS_FILE = "DeletedFilePreferences.properties"; //NON-NLS
private static final String KEY_LIMIT_DELETED_FILES = "limitDeletedFiles"; //NON-NLS
private static final String KEY_LIMIT_VALUE = "limitValue";
private static final String VALUE_TRUE = "true"; //NON-NLS
private static final String VALUE_FALSE = "false"; //NON-NLS
private static final int DEFAULT_MAX_OBJECTS = 10001;
private static final Logger logger = Logger.getLogger(CasePreferences.class.getName());
private static DeletedFilePreferences defaultInstance;
private static boolean limitDeletedFiles = true;
private static int deletedFilesLimit = DEFAULT_MAX_OBJECTS;
/**
* Get the settings for the display of deleted files.
*
* @return defaultInstance with freshly loaded
*/
public static synchronized DeletedFilePreferences getDefault() {
if (defaultInstance == null) {
defaultInstance = new DeletedFilePreferences();
}
defaultInstance.loadFromStorage();
return defaultInstance;
}
/**
* Prevent instantiation.
*/
private DeletedFilePreferences() {
}
/**
* Get the 'limitDeletedFiles' value. This can be true or false. It will
* default to true if it was not saved correctly previously.s
*
* @return true if the number of deleted files displayed should be limied,
* false if it should not be limited.
*/
public boolean getShouldLimitDeletedFiles() {
return limitDeletedFiles;
}
/**
* Set the 'limitDeletedFiles' value to true or false.
*
* @param value true if the number of deleted files displayed should be
* limied, false if it should not be limited.
*/
public void setShouldLimitDeletedFiles(boolean value) {
limitDeletedFiles = value;
saveToStorage();
DirectoryTreeTopComponent.getDefault().refreshContentTreeSafe();
}
/**
* Get the 'limitValue' value. This is an interger value and will default to
* DEFAULT_MAX_OBJECTS if it was not previously saved correctly.
*
* @return an integer representing the max number of deleted files to display.
*/
public int getDeletedFilesLimit() {
return deletedFilesLimit;
}
/**
* Set the 'limitValue' for max number of deleted files to display.
*
* @param value an integer representing the max number of deleted files to display.
*/
public void setDeletedFilesLimit(int value) {
deletedFilesLimit = value;
saveToStorage();
DirectoryTreeTopComponent.getDefault().refreshContentTreeSafe();
}
/**
* Load deleted file preferences from the settings file.
*/
private void loadFromStorage() {
Path settingsFile = Paths.get(PlatformUtil.getUserConfigDirectory(), SETTINGS_FILE); //NON-NLS
if (settingsFile.toFile().exists()) {
// Read the settings
try (InputStream inputStream = Files.newInputStream(settingsFile)) {
Properties props = new Properties();
props.load(inputStream);
String limitDeletedFilesValue = props.getProperty(KEY_LIMIT_DELETED_FILES);
if (limitDeletedFilesValue != null) {
switch (limitDeletedFilesValue) {
case VALUE_TRUE:
limitDeletedFiles = true;
break;
case VALUE_FALSE:
limitDeletedFiles = false;
break;
default:
logger.log(Level.WARNING, String.format("Unexpected value '%s' for limit deleted files using value of true instead",
limitDeletedFilesValue));
limitDeletedFiles = true;
break;
}
}
String limitValue = props.getProperty(KEY_LIMIT_VALUE);
try {
if (limitValue != null) {
deletedFilesLimit = Integer.valueOf(limitValue);
}
} catch (NumberFormatException ex) {
logger.log(Level.INFO, String.format("Unexpected value '%s' for limit, expected an integer using default of 10,001 instead",
limitValue));
deletedFilesLimit = DEFAULT_MAX_OBJECTS;
}
} catch (IOException ex) {
logger.log(Level.SEVERE, "Error reading deletedFilesPreferences file", ex);
}
}
}
/**
* Store deleted file preferences in the settings file.
*/
private void saveToStorage() {
Path settingsFile = Paths.get(PlatformUtil.getUserConfigDirectory(), SETTINGS_FILE); //NON-NLS
Properties props = new Properties();
props.setProperty(KEY_LIMIT_DELETED_FILES, (limitDeletedFiles ? VALUE_TRUE : VALUE_FALSE));
props.setProperty(KEY_LIMIT_VALUE, String.valueOf(deletedFilesLimit));
try (OutputStream fos = Files.newOutputStream(settingsFile)) {
props.store(fos, ""); //NON-NLS
} catch (IOException ex) {
logger.log(Level.SEVERE, "Error writing deletedFilesPreferences file", ex);
}
}
}

View File

@ -173,6 +173,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
case UserPreferences.HIDE_CENTRAL_REPO_COMMENTS_AND_OCCURRENCES:
case UserPreferences.DISPLAY_TRANSLATED_NAMES:
case UserPreferences.KEEP_PREFERRED_VIEWER:
case UserPreferences.MAXIMUM_NUMBER_OF_RESULTS:
refreshContentTreeSafe();
break;
case UserPreferences.SHOW_ONLY_CURRENT_USER_TAGS:

View File

@ -17,7 +17,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.commonfilesearch;
package org.sleuthkit.autopsy.guiutils;
import javax.swing.AbstractListModel;
import javax.swing.ComboBoxModel;
@ -44,7 +44,7 @@ public class DataSourceComboBoxModel extends AbstractListModel<String> implement
*
* @param theDataSoureList names of data sources for user to pick from
*/
DataSourceComboBoxModel(String... theDataSoureList) {
public DataSourceComboBoxModel(String... theDataSoureList) {
dataSourceList = theDataSoureList.clone();
}

View File

@ -17,7 +17,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.commonfilesearch;
package org.sleuthkit.autopsy.guiutils;
import java.io.File;
import java.sql.ResultSet;

Binary file not shown.

After

Width:  |  Height:  |  Size: 483 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 306 B

View File

@ -440,7 +440,8 @@ public final class IngestJobSettings {
break;
case "EWF Verify": //NON-NLS
case "E01 Verify": //NON-NLS
moduleNames.add("E01 Verifier"); //NON-NLS
case "E01 Verifier": // NON-NLS
moduleNames.add("Data Source Integrity"); //NON-NLS
break;
case "Archive Extractor": //NON-NLS
moduleNames.add("Embedded File Extractor"); //NON-NLS

View File

@ -30,7 +30,7 @@ import org.openide.util.Lookup;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.examples.SampleIngestModuleFactory;
import org.sleuthkit.autopsy.modules.e01verify.E01VerifierModuleFactory;
import org.sleuthkit.autopsy.modules.dataSourceIntegrity.DataSourceIntegrityModuleFactory;
import org.sleuthkit.autopsy.modules.exif.ExifParserModuleFactory;
import org.sleuthkit.autopsy.modules.fileextmismatch.FileExtMismatchDetectorModuleFactory;
import org.sleuthkit.autopsy.modules.filetypeid.FileTypeIdModuleFactory;
@ -39,6 +39,8 @@ import org.sleuthkit.autopsy.modules.interestingitems.InterestingItemsIngestModu
import org.sleuthkit.autopsy.modules.photoreccarver.PhotoRecCarverIngestModuleFactory;
import org.sleuthkit.autopsy.modules.embeddedfileextractor.EmbeddedFileExtractorModuleFactory;
import org.sleuthkit.autopsy.modules.encryptiondetection.EncryptionDetectionModuleFactory;
import org.sleuthkit.autopsy.centralrepository.ingestmodule.CentralRepoIngestModuleFactory;
import org.sleuthkit.autopsy.modules.vmextractor.VMExtractorIngestModuleFactory;
import org.sleuthkit.autopsy.python.JythonModuleLoader;
/**
@ -55,15 +57,17 @@ final class IngestModuleFactoryLoader {
add("org.sleuthkit.autopsy.recentactivity.RecentActivityExtracterModuleFactory"); //NON-NLS
add(HashLookupModuleFactory.class.getCanonicalName());
add(FileTypeIdModuleFactory.class.getCanonicalName());
add(FileExtMismatchDetectorModuleFactory.class.getCanonicalName());
add(EmbeddedFileExtractorModuleFactory.class.getCanonicalName());
add(ExifParserModuleFactory.class.getCanonicalName());
add("org.sleuthkit.autopsy.keywordsearch.KeywordSearchModuleFactory"); //NON-NLS
add("org.sleuthkit.autopsy.thunderbirdparser.EmailParserModuleFactory"); //NON-NLS
add(FileExtMismatchDetectorModuleFactory.class.getCanonicalName());
add(E01VerifierModuleFactory.class.getCanonicalName());
add(EncryptionDetectionModuleFactory.class.getCanonicalName());
add(InterestingItemsIngestModuleFactory.class.getCanonicalName());
add(CentralRepoIngestModuleFactory.class.getCanonicalName());
add(PhotoRecCarverIngestModuleFactory.class.getCanonicalName());
add(VMExtractorIngestModuleFactory.class.getCanonicalName());
add(DataSourceIntegrityModuleFactory.class.getCanonicalName());
}
};
@ -75,7 +79,7 @@ final class IngestModuleFactoryLoader {
* removed between invocations.
*
* @return A list of objects that implement the IngestModuleFactory
* interface.
* interface.
*/
static List<IngestModuleFactory> getIngestModuleFactories() {
// A hash set of display names and a hash map of class names to

View File

@ -20,7 +20,7 @@ Contains only the core ingest modules that ship with Autopsy -->
</PIPELINE>
<PIPELINE type="ImageAnalysisStageTwo">
<MODULE>org.sleuthkit.autopsy.modules.e01verify.E01VerifierModuleFactory</MODULE>
<MODULE>org.sleuthkit.autopsy.modules.dataSourceIntegrity.DataSourceIntegrityModuleFactory</MODULE>
</PIPELINE>
</PIPELINE_CONFIG>

View File

@ -0,0 +1,4 @@
OpenIDE-Module-Name=CaseUcoModule
ReportCaseUco.getName.text=CASE-UCO
ReportCaseUco.getDesc.text=CASE-UCO format report with basic property fields for every file.
ReportCaseUcoConfigPanel.jLabelSelectDataSource.text=Select a data source for the CASE-UCO report

View File

@ -0,0 +1,458 @@
/*
*
* Autopsy Forensic Browser
*
* Copyright 2012-2018 Basis Technology Corp.
* Project Contact/Architect: 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.modules.case_uco;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.logging.Level;
import javax.swing.JPanel;
import com.fasterxml.jackson.core.JsonEncoding;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.util.DefaultIndenter;
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.SimpleTimeZone;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import org.sleuthkit.autopsy.datamodel.ContentUtils;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.report.GeneralReportModule;
import org.sleuthkit.autopsy.report.ReportProgressPanel;
import org.sleuthkit.autopsy.report.ReportProgressPanel.ReportStatus;
import org.sleuthkit.datamodel.*;
/**
* ReportCaseUco generates a report in the CASE-UCO format. It saves basic
file info like full caseDirPath, name, MIME type, times, and hash.
*/
class ReportCaseUco implements GeneralReportModule {
private static final Logger logger = Logger.getLogger(ReportCaseUco.class.getName());
private static ReportCaseUco instance = null;
private ReportCaseUcoConfigPanel configPanel;
private static final String REPORT_FILE_NAME = "CASE_UCO_output.json-ld";
// Hidden constructor for the report
private ReportCaseUco() {
}
// Get the default implementation of this report
public static synchronized ReportCaseUco getDefault() {
if (instance == null) {
instance = new ReportCaseUco();
}
return instance;
}
/**
* Generates a CASE-UCO format report.
*
* @param baseReportDir caseDirPath to save the report
* @param progressPanel panel to update the report's progress
*/
@NbBundle.Messages({
"ReportCaseUco.notInitialized=CASE-UCO settings panel has not been initialized",
"ReportCaseUco.noDataSourceSelected=No data source selected for CASE-UCO report",
"ReportCaseUco.noCaseOpen=Unable to open currect case",
"ReportCaseUco.unableToCreateDirectories=Unable to create directory for CASE-UCO report",
"ReportCaseUco.initializing=Creating directories...",
"ReportCaseUco.querying=Querying files...",
"ReportCaseUco.ingestWarning=Warning, this report will be created before ingest services completed",
"ReportCaseUco.processing=Saving files in CASE-UCO format...",
"ReportCaseUco.srcModuleName.text=CASE-UCO Report"
})
@Override
@SuppressWarnings("deprecation")
public void generateReport(String baseReportDir, ReportProgressPanel progressPanel) {
if (configPanel == null) {
logger.log(Level.SEVERE, "CASE-UCO settings panel has not been initialized"); //NON-NLS
MessageNotifyUtil.Message.error(Bundle.ReportCaseUco_notInitialized());
progressPanel.complete(ReportStatus.ERROR);
return;
}
Long selectedDataSourceId = configPanel.getSelectedDataSourceId();
if (selectedDataSourceId == ReportCaseUcoConfigPanel.NO_DATA_SOURCE_SELECTED) {
logger.log(Level.SEVERE, "No data source selected for CASE-UCO report"); //NON-NLS
MessageNotifyUtil.Message.error(Bundle.ReportCaseUco_noDataSourceSelected());
progressPanel.complete(ReportStatus.ERROR);
return;
}
// Start the progress bar and setup the report
progressPanel.setIndeterminate(false);
progressPanel.start();
progressPanel.updateStatusLabel(Bundle.ReportCaseUco_initializing());
// Create the JSON generator
JsonFactory jsonGeneratorFactory = new JsonFactory();
String reportPath = baseReportDir + getRelativeFilePath();
java.io.File reportFile = Paths.get(reportPath).toFile();
try {
Files.createDirectories(Paths.get(reportFile.getParent()));
} catch (IOException ex) {
logger.log(Level.SEVERE, "Unable to create directory for CASE-UCO report", ex); //NON-NLS
MessageNotifyUtil.Message.error(Bundle.ReportCaseUco_unableToCreateDirectories());
progressPanel.complete(ReportStatus.ERROR);
return;
}
// Check if ingest has finished
if (IngestManager.getInstance().isIngestRunning()) {
MessageNotifyUtil.Message.warn(Bundle.ReportCaseUco_ingestWarning());
}
JsonGenerator jsonGenerator = null;
SimpleTimeZone timeZone = new SimpleTimeZone(0, "GMT");
try {
jsonGenerator = jsonGeneratorFactory.createGenerator(reportFile, JsonEncoding.UTF8);
// instert \n after each field for more readable formatting
jsonGenerator.setPrettyPrinter(new DefaultPrettyPrinter().withObjectIndenter(new DefaultIndenter(" ", "\n")));
SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase();
progressPanel.updateStatusLabel(Bundle.ReportCaseUco_querying());
// create the required CASE-UCO entries at the beginning of the output file
initializeJsonOutputFile(jsonGenerator);
// create CASE-UCO entry for the Autopsy case
String caseTraceId = saveCaseInfo(skCase, jsonGenerator);
// create CASE-UCO data source entry
String dataSourceTraceId = saveDataSourceInfo(selectedDataSourceId, caseTraceId, skCase, jsonGenerator);
// Run getAllFilesQuery to get all files, exclude directories
final String getAllFilesQuery = "select obj_id, name, size, crtime, atime, mtime, md5, parent_path, mime_type, extension from tsk_files where "
+ "data_source_obj_id = " + Long.toString(selectedDataSourceId)
+ " AND ((meta_type = " + TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_UNDEF.getValue()
+ ") OR (meta_type = " + TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue()
+ ") OR (meta_type = " + TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT.getValue() + "))"; //NON-NLS
try (SleuthkitCase.CaseDbQuery queryResult = skCase.executeQuery(getAllFilesQuery)) {
ResultSet resultSet = queryResult.getResultSet();
progressPanel.updateStatusLabel(Bundle.ReportCaseUco_processing());
// Loop files and write info to CASE-UCO report
while (resultSet.next()) {
if (progressPanel.getStatus() == ReportStatus.CANCELED) {
break;
}
Long objectId = resultSet.getLong(1);
String fileName = resultSet.getString(2);
long size = resultSet.getLong("size");
String crtime = ContentUtils.getStringTimeISO8601(resultSet.getLong("crtime"), timeZone);
String atime = ContentUtils.getStringTimeISO8601(resultSet.getLong("atime"), timeZone);
String mtime = ContentUtils.getStringTimeISO8601(resultSet.getLong("mtime"), timeZone);
String md5Hash = resultSet.getString("md5");
String parent_path = resultSet.getString("parent_path");
String mime_type = resultSet.getString("mime_type");
String extension = resultSet.getString("extension");
saveFileInCaseUcoFormat(objectId, fileName, parent_path, md5Hash, mime_type, size, crtime, atime, mtime, extension, jsonGenerator, dataSourceTraceId);
}
}
// create the required CASE-UCO entries at the end of the output file
finilizeJsonOutputFile(jsonGenerator);
Case.getCurrentCaseThrows().addReport(reportPath, Bundle.ReportCaseUco_srcModuleName_text(), "");
progressPanel.complete(ReportStatus.COMPLETE);
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Failed to get list of files from case database", ex); //NON-NLS
progressPanel.complete(ReportStatus.ERROR);
} catch (IOException ex) {
logger.log(Level.SEVERE, "Failed to create JSON output for the CASE-UCO report", ex); //NON-NLS
progressPanel.complete(ReportStatus.ERROR);
} catch (SQLException ex) {
logger.log(Level.WARNING, "Unable to read result set", ex); //NON-NLS
progressPanel.complete(ReportStatus.ERROR);
} catch (NoCurrentCaseException ex) {
logger.log(Level.SEVERE, "No current case open", ex); //NON-NLS
progressPanel.complete(ReportStatus.ERROR);
} finally {
if (jsonGenerator != null) {
try {
jsonGenerator.close();
} catch (IOException ex) {
logger.log(Level.WARNING, "Failed to close JSON output file", ex); //NON-NLS
}
}
}
}
private void initializeJsonOutputFile(JsonGenerator catalog) throws IOException {
catalog.writeStartObject();
catalog.writeFieldName("@graph");
catalog.writeStartArray();
}
private void finilizeJsonOutputFile(JsonGenerator catalog) throws IOException {
catalog.writeEndArray();
catalog.writeEndObject();
}
private String saveCaseInfo(SleuthkitCase skCase, JsonGenerator catalog) throws TskCoreException, SQLException, IOException, NoCurrentCaseException {
// create a "trace" entry for the Autopsy case iteself
String uniqueCaseName;
String dbFileName;
TskData.DbType dbType = skCase.getDatabaseType();
if (dbType == TskData.DbType.SQLITE) {
uniqueCaseName = Case.getCurrentCaseThrows().getName();
dbFileName = skCase.getDatabaseName();
} else {
uniqueCaseName = skCase.getDatabaseName();
dbFileName = "";
}
String caseDirPath = skCase.getDbDirPath();
String caseTraceId = "case-" + uniqueCaseName;
catalog.writeStartObject();
catalog.writeStringField("@id", caseTraceId);
catalog.writeStringField("@type", "Trace");
catalog.writeFieldName("propertyBundle");
catalog.writeStartArray();
catalog.writeStartObject();
catalog.writeStringField("@type", "File");
if (dbType == TskData.DbType.SQLITE) {
catalog.writeStringField("filePath", caseDirPath + java.io.File.separator + dbFileName);
catalog.writeBooleanField("isDirectory", false);
} else {
catalog.writeStringField("filePath", caseDirPath);
catalog.writeBooleanField("isDirectory", true);
}
catalog.writeEndObject();
catalog.writeEndArray();
catalog.writeEndObject();
return caseTraceId;
}
private String saveDataSourceInfo(Long selectedDataSourceId, String caseTraceId, SleuthkitCase skCase, JsonGenerator jsonGenerator) throws TskCoreException, SQLException, IOException {
Long imageSize = (long) 0;
String imageName = "";
boolean isImageDataSource = false;
String getImageDataSourceQuery = "select size from tsk_image_info where obj_id = " + selectedDataSourceId;
try (SleuthkitCase.CaseDbQuery queryResult = skCase.executeQuery(getImageDataSourceQuery)) {
ResultSet resultSet = queryResult.getResultSet();
// check if we got a result
while (resultSet.next()) {
// we got a result so the data source was an image data source
imageSize = resultSet.getLong(1);
isImageDataSource = true;
break;
}
}
if (isImageDataSource) {
// get caseDirPath to image file
String getPathToDataSourceQuery = "select name from tsk_image_names where obj_id = " + selectedDataSourceId;
try (SleuthkitCase.CaseDbQuery queryResult = skCase.executeQuery(getPathToDataSourceQuery)) {
ResultSet resultSet = queryResult.getResultSet();
while (resultSet.next()) {
imageName = resultSet.getString(1);
break;
}
}
} else {
// logical file data source
String getLogicalDataSourceQuery = "select name from tsk_files where obj_id = " + selectedDataSourceId;
try (SleuthkitCase.CaseDbQuery queryResult = skCase.executeQuery(getLogicalDataSourceQuery)) {
ResultSet resultSet = queryResult.getResultSet();
while (resultSet.next()) {
imageName = resultSet.getString(1);
break;
}
}
}
return saveDataSourceInCaseUcoFormat(jsonGenerator, imageName, imageSize, selectedDataSourceId, caseTraceId);
}
private String saveDataSourceInCaseUcoFormat(JsonGenerator catalog, String imageName, Long imageSize, Long selectedDataSourceId, String caseTraceId) throws IOException {
// create a "trace" entry for the data source
String dataSourceTraceId = "data-source-"+selectedDataSourceId;
catalog.writeStartObject();
catalog.writeStringField("@id", dataSourceTraceId);
catalog.writeStringField("@type", "Trace");
catalog.writeFieldName("propertyBundle");
catalog.writeStartArray();
catalog.writeStartObject();
catalog.writeStringField("@type", "File");
catalog.writeStringField("filePath", imageName);
catalog.writeEndObject();
if (imageSize > 0) {
catalog.writeStartObject();
catalog.writeStringField("@type", "ContentData");
catalog.writeStringField("sizeInBytes", Long.toString(imageSize));
catalog.writeEndObject();
}
catalog.writeEndArray();
catalog.writeEndObject();
// create a "relationship" entry between the case and the data source
catalog.writeStartObject();
catalog.writeStringField("@id", "relationship-" + caseTraceId);
catalog.writeStringField("@type", "Relationship");
catalog.writeStringField("source", dataSourceTraceId);
catalog.writeStringField("target", caseTraceId);
catalog.writeStringField("kindOfRelationship", "contained-within");
catalog.writeBooleanField("isDirectional", true);
catalog.writeFieldName("propertyBundle");
catalog.writeStartArray();
catalog.writeStartObject();
catalog.writeStringField("@type", "PathRelation");
catalog.writeStringField("path", imageName);
catalog.writeEndObject();
catalog.writeEndArray();
catalog.writeEndObject();
return dataSourceTraceId;
}
private void saveFileInCaseUcoFormat(Long objectId, String fileName, String parent_path, String md5Hash, String mime_type, long size, String ctime,
String atime, String mtime, String extension, JsonGenerator catalog, String dataSourceTraceId) throws IOException {
String fileTraceId = "file-" + objectId;
// create a "trace" entry for the file
catalog.writeStartObject();
catalog.writeStringField("@id", fileTraceId);
catalog.writeStringField("@type", "Trace");
catalog.writeFieldName("propertyBundle");
catalog.writeStartArray();
catalog.writeStartObject();
catalog.writeStringField("@type", "File");
catalog.writeStringField("createdTime", ctime);
catalog.writeStringField("accessedTime", atime);
catalog.writeStringField("modifiedTime", mtime);
if (extension != null) {
catalog.writeStringField("extension", extension);
}
catalog.writeStringField("fileName", fileName);
if (parent_path != null) {
catalog.writeStringField("filePath", parent_path + fileName);
}
catalog.writeBooleanField("isDirectory", false);
catalog.writeStringField("sizeInBytes", Long.toString(size));
catalog.writeEndObject();
catalog.writeStartObject();
catalog.writeStringField("@type", "ContentData");
if (mime_type != null) {
catalog.writeStringField("mimeType", mime_type);
}
if (md5Hash != null) {
catalog.writeFieldName("hash");
catalog.writeStartArray();
catalog.writeStartObject();
catalog.writeStringField("@type", "Hash");
catalog.writeStringField("hashMethod", "SHA256");
catalog.writeStringField("hashValue", md5Hash);
catalog.writeEndObject();
catalog.writeEndArray();
}
catalog.writeStringField("sizeInBytes", Long.toString(size));
catalog.writeEndObject();
catalog.writeEndArray();
catalog.writeEndObject();
// create a "relationship" entry between the file and the data source
catalog.writeStartObject();
catalog.writeStringField("@id", "relationship-" + objectId);
catalog.writeStringField("@type", "Relationship");
catalog.writeStringField("source", fileTraceId);
catalog.writeStringField("target", dataSourceTraceId);
catalog.writeStringField("kindOfRelationship", "contained-within");
catalog.writeBooleanField("isDirectional", true);
catalog.writeFieldName("propertyBundle");
catalog.writeStartArray();
catalog.writeStartObject();
catalog.writeStringField("@type", "PathRelation");
if (parent_path != null) {
catalog.writeStringField("path", parent_path + fileName);
} else {
catalog.writeStringField("path", fileName);
}
catalog.writeEndObject();
catalog.writeEndArray();
catalog.writeEndObject();
}
@Override
public String getName() {
String name = NbBundle.getMessage(this.getClass(), "ReportCaseUco.getName.text");
return name;
}
@Override
public String getRelativeFilePath() {
return REPORT_FILE_NAME;
}
@Override
public String getDescription() {
String desc = NbBundle.getMessage(this.getClass(), "ReportCaseUco.getDesc.text");
return desc;
}
@Override
public JPanel getConfigurationPanel() {
try {
configPanel = new ReportCaseUcoConfigPanel();
} catch (NoCurrentCaseException | TskCoreException | SQLException ex) {
logger.log(Level.SEVERE, "Failed to initialize CASE-UCO settings panel", ex); //NON-NLS
MessageNotifyUtil.Message.error(Bundle.ReportCaseUco_notInitialized());
configPanel = null;
}
return configPanel;
}
}

View File

@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="21" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Component id="jLabelSelectDataSource" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
<Component id="selectDataSourceComboBox" pref="348" max="32767" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="11" max="-2" attributes="0"/>
<Component id="jLabelSelectDataSource" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="selectDataSourceComboBox" min="-2" max="-2" attributes="0"/>
<EmptySpace pref="130" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JComboBox" name="selectDataSourceComboBox">
<Properties>
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="dataSourcesList" type="code"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;String&gt;"/>
</AuxValues>
</Component>
<Component class="javax.swing.JLabel" name="jLabelSelectDataSource">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/modules/case_uco/Bundle.properties" key="ReportCaseUcoConfigPanel.jLabelSelectDataSource.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
</AuxValues>
</Component>
</SubComponents>
</Form>

View File

@ -0,0 +1,133 @@
/*
*
* Autopsy Forensic Browser
*
* Copyright 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.modules.case_uco;
import java.sql.SQLException;
import java.util.Map;
import java.util.Map.Entry;
import javax.swing.ComboBoxModel;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.guiutils.DataSourceLoader;
import org.sleuthkit.autopsy.guiutils.DataSourceComboBoxModel;
import org.sleuthkit.datamodel.TskCoreException;
/**
* UI controls for CASE-UCO report. It is a panel which provides the
* ability to select a single datasource from a dropdown list
* of sources in the current case.
*/
final class ReportCaseUcoConfigPanel extends javax.swing.JPanel {
private static final long serialVersionUID = 1L;
static final long NO_DATA_SOURCE_SELECTED = -1;
private ComboBoxModel<String> dataSourcesList = new DataSourceComboBoxModel();
private final Map<Long, String> dataSourceMap;
private final DataSourceLoader dataSourceLoader;
/**
* Creates new form ReportCaseUcoConfigPanel
*/
ReportCaseUcoConfigPanel() throws NoCurrentCaseException, TskCoreException, SQLException {
initComponents();
this.dataSourceLoader = new DataSourceLoader();
this.dataSourceMap = dataSourceLoader.getDataSourceMap();
String[] dataSourcesNames = new String[dataSourceMap.size()];
if (dataSourcesNames.length > 0) {
dataSourcesNames = dataSourceMap.values().toArray(dataSourcesNames);
setDatasourceComboboxModel(new DataSourceComboBoxModel(dataSourcesNames));
selectDataSourceComboBox.setEnabled(true);
selectDataSourceComboBox.setSelectedIndex(0);
}
}
/**
* Get the ID for the datasource selected in the combo box.
*
* @return the selected datasource ID or
ReportCaseUcoConfigPanel.NO_DATA_SOURCE_SELECTED if none is selected
*/
Long getSelectedDataSourceId() {
for (Entry<Long, String> entry : this.dataSourceMap.entrySet()) {
if (entry.getValue().equals(this.selectDataSourceComboBox.getSelectedItem())) {
return entry.getKey();
}
}
return ReportCaseUcoConfigPanel.NO_DATA_SOURCE_SELECTED;
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
selectDataSourceComboBox = new javax.swing.JComboBox<>();
jLabelSelectDataSource = new javax.swing.JLabel();
selectDataSourceComboBox.setModel(dataSourcesList);
selectDataSourceComboBox.setEnabled(false);
jLabelSelectDataSource.setText(org.openide.util.NbBundle.getMessage(ReportCaseUcoConfigPanel.class, "ReportCaseUcoConfigPanel.jLabelSelectDataSource.text")); // NOI18N
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(21, 21, 21)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(jLabelSelectDataSource)
.addGap(0, 0, Short.MAX_VALUE))
.addComponent(selectDataSourceComboBox, 0, 348, Short.MAX_VALUE))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(11, 11, 11)
.addComponent(jLabelSelectDataSource)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(selectDataSourceComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(130, Short.MAX_VALUE))
);
}// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JLabel jLabelSelectDataSource;
private javax.swing.JComboBox<String> selectDataSourceComboBox;
// End of variables declaration//GEN-END:variables
/**
* Set the datamodel for the combo box which displays the data sources in
* the current case
*
* @param dataSourceComboBoxModel the DataSourceComboBoxModel to use
*/
void setDatasourceComboboxModel(DataSourceComboBoxModel dataSourceComboBoxModel) {
this.dataSourcesList = dataSourceComboBoxModel;
this.selectDataSourceComboBox.setModel(dataSourcesList);
}
}

View File

@ -0,0 +1,19 @@
OpenIDE-Module-Name=ewfVerify
DataSourceIntegrityModuleFactory.moduleName.text=Data Source Integrity
DataSourceIntegrityModuleFactory.moduleDesc.text=Calculates and validates hashes of data sources.
DataSourceIntegrityIngestModule.process.errProcImg=Error processing {0}
DataSourceIntegrityIngestModule.process.skipNonEwf=Skipping non-disk image data source {0}
DataSourceIntegrityIngestModule.process.noStoredHash=Image {0} does not have stored hash.
DataSourceIntegrityIngestModule.process.startingImg=Starting {0}
DataSourceIntegrityIngestModule.process.errGetSizeOfImg=Error getting size of {0}. Image will not be processed.
DataSourceIntegrityIngestModule.process.errReadImgAtChunk=Error reading {0} at chunk {1}
DataSourceIntegrityIngestModule.shutDown.verified=\ verified
DataSourceIntegrityIngestModule.shutDown.notVerified=\ not verified
DataSourceIntegrityIngestModule.shutDown.verifyResultsHeader=<p>Data Source Verification Results for {0} </p>
DataSourceIntegrityIngestModule.shutDown.resultLi=<li>Result\:{0} </li>
DataSourceIntegrityIngestModule.shutDown.calcHashLi=<li>Calculated hash\: {0} </li>
DataSourceIntegrityIngestModule.shutDown.storedHashLi=<li>Stored hash\: {0} </li>
DataSourceIntegrityIngestSettingsPanel.computeHashesCheckbox.text=Calculate data source hashes if none are present
DataSourceIntegrityIngestSettingsPanel.jLabel1.text=Note that this module will not run on logical files
DataSourceIntegrityIngestSettingsPanel.jLabel3.text=Ingest Settings
DataSourceIntegrityIngestSettingsPanel.verifyHashesCheckbox.text=Verify existing data source hashes

View File

@ -0,0 +1,15 @@
OpenIDE-Module-Name=EWFVerify
DataSourceIntegrityIngestModule.process.errProcImg={0}\u3092\u51e6\u7406\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f
DataSourceIntegrityModuleFactory.moduleName.text=E01\u8a8d\u8a3c\u30c4\u30fc\u30eb
DataSourceIntegrityModuleFactory.moduleDesc.text=E01\u30d5\u30a1\u30a4\u30eb\u306e\u6574\u5408\u6027\u3092\u8a8d\u8a3c\u3057\u307e\u3059\u3002
DataSourceIntegrityIngestModule.process.skipNonEwf=E01\u30a4\u30e1\u30fc\u30b8\u3067\u306f\u306a\u3044{0}\u3092\u30b9\u30ad\u30c3\u30d7\u3057\u3066\u3044\u307e\u3059
DataSourceIntegrityIngestModule.process.noStoredHash=\u30a4\u30e1\u30fc\u30b8{0}\u306f\u4fdd\u5b58\u3055\u308c\u3066\u3044\u308b\u30cf\u30c3\u30b7\u30e5\u304c\u3042\u308a\u307e\u305b\u3093\u3002
DataSourceIntegrityIngestModule.process.startingImg={0}\u3092\u958b\u59cb\u4e2d
DataSourceIntegrityIngestModule.process.errGetSizeOfImg={0}\u306e\u30b5\u30a4\u30ba\u306e\u53d6\u5f97\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002\u30a4\u30e1\u30fc\u30b8\u306f\u51e6\u7406\u3055\u308c\u307e\u305b\u3093\u3002
DataSourceIntegrityIngestModule.process.errReadImgAtChunk={0}\u306e\u30c1\u30e3\u30f3\u30af{1}\u306e\u8aad\u307f\u53d6\u308a\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f
DataSourceIntegrityIngestModule.shutDown.calcHashLi=<li>\u8a08\u7b97\u3055\u308c\u305f\u30cf\u30c3\u30b7\u30e5\u5024\uff1a{0}</li>
DataSourceIntegrityIngestModule.shutDown.notVerified=\u8a8d\u8a3c\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f
DataSourceIntegrityIngestModule.shutDown.resultLi=<li>\u7d50\u679c\uff1a{0}</li>
DataSourceIntegrityIngestModule.shutDown.storedHashLi=<li>\u4fdd\u5b58\u3055\u308c\u305f\u30cf\u30c3\u30b7\u30e5\uff1a {0}</li>
DataSourceIntegrityIngestModule.shutDown.verifyResultsHeader=<p>{0}\u306eEWF\u30d9\u30ea\u30d5\u30a3\u30b1\u30fc\u30b7\u30e7\u30f3\u7d50\u679c</p>
EwfVerifyIDataSourceIntegrityIngestModulengestModule.shutDown.verified=\u8a8d\u8a3c\u3055\u308c\u307e\u3057\u305f

View File

@ -0,0 +1,362 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013-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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.modules.dataSourceIntegrity;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import javax.xml.bind.DatatypeConverter;
import java.util.Arrays;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.ingest.DataSourceIngestModule;
import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProgress;
import org.sleuthkit.autopsy.ingest.IngestJobContext;
import org.sleuthkit.autopsy.ingest.IngestMessage;
import org.sleuthkit.autopsy.ingest.IngestMessage.MessageType;
import org.sleuthkit.autopsy.ingest.IngestServices;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.Image;
import org.sleuthkit.datamodel.TskCoreException;
import org.openide.util.NbBundle;
/**
* Data source ingest module that verifies the integrity of an Expert Witness
* Format (EWF) E01 image file by generating a hash of the file and comparing it
* to the value stored in the image. Will also generate hashes for any image-type
* data source that has none.
*/
public class DataSourceIntegrityIngestModule implements DataSourceIngestModule {
private static final Logger logger = Logger.getLogger(DataSourceIntegrityIngestModule.class.getName());
private static final long DEFAULT_CHUNK_SIZE = 32 * 1024;
private static final IngestServices services = IngestServices.getInstance();
private final boolean computeHashes;
private final boolean verifyHashes;
private final List<HashData> hashDataList = new ArrayList<>();
private IngestJobContext context;
DataSourceIntegrityIngestModule(DataSourceIntegrityIngestSettings settings) {
computeHashes = settings.shouldComputeHashes();
verifyHashes = settings.shouldVerifyHashes();
}
@NbBundle.Messages({
"DataSourceIntegrityIngestModule.startup.noCheckboxesSelected=At least one of the checkboxes must be selected"
})
@Override
public void startUp(IngestJobContext context) throws IngestModuleException {
this.context = context;
// It's an error if the module is run without either option selected
if (!(computeHashes || verifyHashes)) {
throw new IngestModuleException(Bundle.DataSourceIntegrityIngestModule_startup_noCheckboxesSelected());
}
}
@NbBundle.Messages({
"# {0} - imageName",
"DataSourceIntegrityIngestModule.process.skipCompute=Not computing new hashes for {0} since the option was disabled",
"# {0} - imageName",
"DataSourceIntegrityIngestModule.process.skipVerify=Not verifying existing hashes for {0} since the option was disabled",
"# {0} - hashName",
"DataSourceIntegrityIngestModule.process.hashAlgorithmError=Error creating message digest for {0} algorithm",
"# {0} - hashName",
"DataSourceIntegrityIngestModule.process.hashMatch=<li>{0} hash verified </li>",
"# {0} - hashName",
"DataSourceIntegrityIngestModule.process.hashNonMatch=<li>{0} hash not verified </li>",
"# {0} - calculatedHashValue",
"# {1} - storedHashValue",
"DataSourceIntegrityIngestModule.process.hashList=<ul><li>Calculated hash: {0} </li><li>Stored hash: {1} </li></ul>",
"# {0} - hashName",
"# {1} - calculatedHashValue",
"DataSourceIntegrityIngestModule.process.calcHashWithType=<li>Calculated {0} hash: {1} </li>",
"# {0} - imageName",
"DataSourceIntegrityIngestModule.process.calculateHashDone=<p>Data Source Hash Calculation Results for {0} </p>",
"DataSourceIntegrityIngestModule.process.hashesCalculated= hashes calculated",
"# {0} - imageName",
"DataSourceIntegrityIngestModule.process.errorSavingHashes= Error saving hashes for image {0} to the database",
"# {0} - imageName",
"DataSourceIntegrityIngestModule.process.errorLoadingHashes= Error loading hashes for image {0} from the database",
})
@Override
public ProcessResult process(Content dataSource, DataSourceIngestModuleProgress statusHelper) {
String imgName = dataSource.getName();
// Skip non-images
if (!(dataSource instanceof Image)) {
logger.log(Level.INFO, "Skipping non-image {0}", imgName); //NON-NLS
services.postMessage(IngestMessage.createMessage(MessageType.INFO, DataSourceIntegrityModuleFactory.getModuleName(),
NbBundle.getMessage(this.getClass(),
"DataSourceIntegrityIngestModule.process.skipNonEwf",
imgName)));
return ProcessResult.OK;
}
Image img = (Image) dataSource;
// Make sure the image size we have is not zero
long size = img.getSize();
if (size == 0) {
logger.log(Level.WARNING, "Size of image {0} was 0 when queried.", imgName); //NON-NLS
services.postMessage(IngestMessage.createMessage(MessageType.ERROR, DataSourceIntegrityModuleFactory.getModuleName(),
NbBundle.getMessage(this.getClass(),
"DataSourceIntegrityIngestModule.process.errGetSizeOfImg",
imgName)));
}
// Determine which mode we're in.
// - If there are any preset hashes, then we'll verify them (assuming the verify checkbox is selected)
// - Otherwise we'll calculate and store all three hashes (assuming the compute checkbox is selected)
// First get a list of all stored hash types
try {
if (img.getMd5() != null && ! img.getMd5().isEmpty()) {
hashDataList.add(new HashData(HashType.MD5, img.getMd5()));
}
if (img.getSha1() != null && ! img.getSha1().isEmpty()) {
hashDataList.add(new HashData(HashType.SHA1, img.getSha1()));
}
if (img.getSha256() != null && ! img.getSha256().isEmpty()) {
hashDataList.add(new HashData(HashType.SHA256, img.getSha256()));
}
} catch (TskCoreException ex) {
String msg = Bundle.DataSourceIntegrityIngestModule_process_errorLoadingHashes(imgName);
services.postMessage(IngestMessage.createMessage(MessageType.ERROR, DataSourceIntegrityModuleFactory.getModuleName(), msg));
logger.log(Level.SEVERE, msg, ex);
return ProcessResult.ERROR;
}
// Figure out which mode we should be in
Mode mode;
if (hashDataList.isEmpty()) {
mode = Mode.COMPUTE;
} else {
mode = Mode.VERIFY;
}
// If that mode was not enabled by the user, exit
if (mode.equals(Mode.COMPUTE) && ! this.computeHashes) {
logger.log(Level.INFO, "Not computing hashes for {0} since the option was disabled", imgName); //NON-NLS
services.postMessage(IngestMessage.createMessage(MessageType.INFO, DataSourceIntegrityModuleFactory.getModuleName(),
Bundle.DataSourceIntegrityIngestModule_process_skipCompute(imgName)));
return ProcessResult.OK;
} else if (mode.equals(Mode.VERIFY) && ! this.verifyHashes) {
logger.log(Level.INFO, "Not verifying hashes for {0} since the option was disabled", imgName); //NON-NLS
services.postMessage(IngestMessage.createMessage(MessageType.INFO, DataSourceIntegrityModuleFactory.getModuleName(),
Bundle.DataSourceIntegrityIngestModule_process_skipVerify(imgName)));
return ProcessResult.OK;
}
// If we're in compute mode (i.e., the hash list is empty), add all hash algorithms
// to the list.
if (mode.equals(Mode.COMPUTE)) {
for(HashType type : HashType.values()) {
hashDataList.add(new HashData(type, ""));
}
}
// Set up the digests
for (HashData hashData:hashDataList) {
try {
hashData.digest = MessageDigest.getInstance(hashData.type.getName());
} catch (NoSuchAlgorithmException ex) {
String msg = Bundle.DataSourceIntegrityIngestModule_process_hashAlgorithmError(hashData.type.getName());
services.postMessage(IngestMessage.createMessage(MessageType.ERROR, DataSourceIntegrityModuleFactory.getModuleName(), msg));
logger.log(Level.SEVERE, msg, ex);
return ProcessResult.ERROR;
}
}
// Libewf uses a chunk size of 64 times the sector size, which is the
// motivation for using it here. For other images it shouldn't matter,
// so they can use this chunk size as well.
long chunkSize = 64 * img.getSsize();
chunkSize = (chunkSize == 0) ? DEFAULT_CHUNK_SIZE : chunkSize;
// Casting to double to capture decimals
int totalChunks = (int) Math.ceil((double) size / (double) chunkSize);
logger.log(Level.INFO, "Total chunks = {0}", totalChunks); //NON-NLS
if (mode.equals(Mode.VERIFY)) {
logger.log(Level.INFO, "Starting hash verification of {0}", img.getName()); //NON-NLS
} else {
logger.log(Level.INFO, "Starting hash calculation for {0}", img.getName()); //NON-NLS
}
services.postMessage(IngestMessage.createMessage(MessageType.INFO, DataSourceIntegrityModuleFactory.getModuleName(),
NbBundle.getMessage(this.getClass(),
"DataSourceIntegrityIngestModule.process.startingImg",
imgName)));
// Set up the progress bar
statusHelper.switchToDeterminate(totalChunks);
// Read in byte size chunks and update the hash value with the data.
byte[] data = new byte[(int) chunkSize];
int read;
for (int i = 0; i < totalChunks; i++) {
if (context.dataSourceIngestIsCancelled()) {
return ProcessResult.OK;
}
try {
read = img.read(data, i * chunkSize, chunkSize);
} catch (TskCoreException ex) {
String msg = NbBundle.getMessage(this.getClass(),
"DataSourceIntegrityIngestModule.process.errReadImgAtChunk", imgName, i);
services.postMessage(IngestMessage.createMessage(MessageType.ERROR, DataSourceIntegrityModuleFactory.getModuleName(), msg));
logger.log(Level.SEVERE, msg, ex);
return ProcessResult.ERROR;
}
// Only update with the read bytes.
if (read == chunkSize) {
for (HashData struct:hashDataList) {
struct.digest.update(data);
}
} else {
byte[] subData = Arrays.copyOfRange(data, 0, read);
for (HashData struct:hashDataList) {
struct.digest.update(subData);
}
}
statusHelper.progress(i);
}
// Produce the final hashes
for(HashData hashData:hashDataList) {
hashData.calculatedHash = DatatypeConverter.printHexBinary(hashData.digest.digest()).toLowerCase();
logger.log(Level.INFO, "Hash calculated from {0}: {1}", new Object[]{imgName, hashData.calculatedHash}); //NON-NLS
}
if (mode.equals(Mode.VERIFY)) {
// Check that each hash matches
boolean verified = true;
String detailedResults = NbBundle
.getMessage(this.getClass(), "DataSourceIntegrityIngestModule.shutDown.verifyResultsHeader", imgName);
String hashResults = "";
for (HashData hashData:hashDataList) {
if (hashData.storedHash.equals(hashData.calculatedHash)) {
hashResults += Bundle.DataSourceIntegrityIngestModule_process_hashMatch(hashData.type.name);
} else {
verified = false;
hashResults += Bundle.DataSourceIntegrityIngestModule_process_hashNonMatch(hashData.type.name);
}
hashResults += Bundle.DataSourceIntegrityIngestModule_process_hashList(hashData.calculatedHash, hashData.storedHash);
}
String verificationResultStr;
MessageType messageType;
if (verified) {
messageType = MessageType.INFO;
verificationResultStr = NbBundle.getMessage(this.getClass(), "DataSourceIntegrityIngestModule.shutDown.verified");
} else {
messageType = MessageType.WARNING;
verificationResultStr = NbBundle.getMessage(this.getClass(), "DataSourceIntegrityIngestModule.shutDown.notVerified");
}
detailedResults += NbBundle.getMessage(this.getClass(), "DataSourceIntegrityIngestModule.shutDown.resultLi", verificationResultStr);
detailedResults += hashResults;
services.postMessage(IngestMessage.createMessage(messageType, DataSourceIntegrityModuleFactory.getModuleName(),
imgName + verificationResultStr, detailedResults));
} else {
// Store the hashes in the database and update the image
try {
String results = Bundle.DataSourceIntegrityIngestModule_process_calculateHashDone(imgName);
for (HashData hashData:hashDataList) {
switch (hashData.type) {
case MD5:
img.setMD5(hashData.calculatedHash);
break;
case SHA1:
img.setSha1(hashData.calculatedHash);
break;
case SHA256:
img.setSha256(hashData.calculatedHash);
break;
default:
break;
}
results += Bundle.DataSourceIntegrityIngestModule_process_calcHashWithType(hashData.type.name, hashData.calculatedHash);
}
// Write the inbox message
services.postMessage(IngestMessage.createMessage(MessageType.INFO, DataSourceIntegrityModuleFactory.getModuleName(),
imgName + Bundle.DataSourceIntegrityIngestModule_process_hashesCalculated(), results));
} catch (TskCoreException ex) {
String msg = Bundle.DataSourceIntegrityIngestModule_process_errorSavingHashes(imgName);
services.postMessage(IngestMessage.createMessage(MessageType.ERROR, DataSourceIntegrityModuleFactory.getModuleName(), msg));
logger.log(Level.SEVERE, "Error saving hash for image " + imgName + " to database", ex);
return ProcessResult.ERROR;
}
}
return ProcessResult.OK;
}
/**
* Enum to track whether we're in computer or verify mode
*/
private enum Mode {
COMPUTE,
VERIFY;
}
/**
* Enum to hold the type of hash.
* The value in the "name" field should be compatible with MessageDigest
*/
private enum HashType {
MD5("MD5"),
SHA1("SHA-1"),
SHA256("SHA-256");
private final String name; // This should be the string expected by MessageDigest
HashType(String name) {
this.name = name;
}
String getName() {
return name;
}
}
/**
* Utility class to hold data for a specific hash algorithm.
*/
private class HashData {
private HashType type;
private MessageDigest digest;
private String storedHash;
private String calculatedHash;
HashData(HashType type, String storedHash) {
this.type = type;
this.storedHash = storedHash;
}
}
}

View File

@ -0,0 +1,96 @@
/*
* Central Repository
*
* Copyright 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.modules.dataSourceIntegrity;
import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings;
/**
* Ingest job settings for the E01 Verify module.
*/
final class DataSourceIntegrityIngestSettings implements IngestModuleIngestJobSettings {
private static final long serialVersionUID = 1L;
static final boolean DEFAULT_COMPUTE_HASHES = true;
static final boolean DEFAULT_VERIFY_HASHES = true;
private boolean computeHashes;
private boolean verifyHashes;
/**
* Instantiate the ingest job settings with default values.
*/
DataSourceIntegrityIngestSettings() {
this.computeHashes = DEFAULT_COMPUTE_HASHES;
this.verifyHashes = DEFAULT_VERIFY_HASHES;
}
/**
* Instantiate the ingest job settings.
*
* @param computeHashes Compute hashes if none are present
* @param verifyHashes Verify hashes if any are present
*/
DataSourceIntegrityIngestSettings(boolean computeHashes, boolean verifyHashes) {
this.computeHashes = computeHashes;
this.verifyHashes = verifyHashes;
}
@Override
public long getVersionNumber() {
return serialVersionUID;
}
/**
* Should hashes be computed if none are present?
*
* @return true if hashes should be computed, false otherwise
*/
boolean shouldComputeHashes() {
return computeHashes;
}
/**
* Set whether hashes should be computed.
*
* @param computeHashes true if hashes should be computed
*/
void setComputeHashes(boolean computeHashes) {
this.computeHashes = computeHashes;
}
/**
* Should hashes be verified if at least one is present?
*
* @return true if hashes should be verified, false otherwise
*/
boolean shouldVerifyHashes() {
return verifyHashes;
}
/**
* Set whether hashes should be verified.
*
* @param verifyHashes true if hashes should be verified
*/
void setVerifyHashes(boolean verifyHashes) {
this.verifyHashes = verifyHashes;
}
}

View File

@ -0,0 +1,83 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jLabel1" min="-2" max="-2" attributes="0"/>
<Component id="verifyHashesCheckbox" min="-2" max="-2" attributes="0"/>
<Component id="computeHashesCheckbox" min="-2" max="-2" attributes="0"/>
<Component id="jLabel3" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace pref="47" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="jLabel3" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="computeHashesCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="verifyHashesCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="jLabel1" min="-2" max="-2" attributes="0"/>
<EmptySpace pref="53" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JCheckBox" name="computeHashesCheckbox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/ingestmodule/Bundle.properties" key="DataSourceIntegrityIngestSettingsPanel.computeHashesCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="computeHashesCheckboxActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="verifyHashesCheckbox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/modules/dataSourceIntegrity/Bundle.properties" key="DataSourceIntegrityIngestSettingsPanel.verifyHashesCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="jLabel3">
<Properties>
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
<Font name="Tahoma" size="11" style="1"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/modules/dataSourceIntegrity/Bundle.properties" key="DataSourceIntegrityIngestSettingsPanel.jLabel3.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="jLabel1">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/modules/dataSourceIntegrity/Bundle.properties" key="DataSourceIntegrityIngestSettingsPanel.jLabel1.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Form>

View File

@ -0,0 +1,120 @@
/*
* Central Repository
*
* Copyright 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.modules.dataSourceIntegrity;
import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings;
import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettingsPanel;
/**
* Ingest job settings panel for the Correlation Engine module.
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
final class DataSourceIntegrityIngestSettingsPanel extends IngestModuleIngestJobSettingsPanel {
/**
* Creates new form DataSourceIntegrityIngestSettingsPanel
*/
public DataSourceIntegrityIngestSettingsPanel(DataSourceIntegrityIngestSettings settings) {
initComponents();
customizeComponents(settings);
}
/**
* Update components with values from the ingest job settings.
*
* @param settings The ingest job settings.
*/
private void customizeComponents(DataSourceIntegrityIngestSettings settings) {
computeHashesCheckbox.setSelected(settings.shouldComputeHashes());
verifyHashesCheckbox.setSelected(settings.shouldVerifyHashes());
}
@Override
public IngestModuleIngestJobSettings getSettings() {
return new DataSourceIntegrityIngestSettings(computeHashesCheckbox.isSelected(), verifyHashesCheckbox.isSelected());
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
computeHashesCheckbox = new javax.swing.JCheckBox();
verifyHashesCheckbox = new javax.swing.JCheckBox();
jLabel3 = new javax.swing.JLabel();
jLabel1 = new javax.swing.JLabel();
org.openide.awt.Mnemonics.setLocalizedText(computeHashesCheckbox, org.openide.util.NbBundle.getMessage(DataSourceIntegrityIngestSettingsPanel.class, "DataSourceIntegrityIngestSettingsPanel.computeHashesCheckbox.text")); // NOI18N
computeHashesCheckbox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
computeHashesCheckboxActionPerformed(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(verifyHashesCheckbox, org.openide.util.NbBundle.getMessage(DataSourceIntegrityIngestSettingsPanel.class, "DataSourceIntegrityIngestSettingsPanel.verifyHashesCheckbox.text")); // NOI18N
jLabel3.setFont(new java.awt.Font("Tahoma", 1, 11)); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(jLabel3, org.openide.util.NbBundle.getMessage(DataSourceIntegrityIngestSettingsPanel.class, "DataSourceIntegrityIngestSettingsPanel.jLabel3.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(DataSourceIntegrityIngestSettingsPanel.class, "DataSourceIntegrityIngestSettingsPanel.jLabel1.text")); // NOI18N
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jLabel1)
.addComponent(verifyHashesCheckbox)
.addComponent(computeHashesCheckbox)
.addComponent(jLabel3))
.addContainerGap(47, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(jLabel3)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(computeHashesCheckbox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(verifyHashesCheckbox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(jLabel1)
.addContainerGap(53, Short.MAX_VALUE))
);
}// </editor-fold>//GEN-END:initComponents
private void computeHashesCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_computeHashesCheckboxActionPerformed
// TODO add your handling code here:
}//GEN-LAST:event_computeHashesCheckboxActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JCheckBox computeHashesCheckbox;
private javax.swing.JLabel jLabel1;
private javax.swing.JLabel jLabel3;
private javax.swing.JCheckBox verifyHashesCheckbox;
// End of variables declaration//GEN-END:variables
}

View File

@ -0,0 +1,103 @@
/*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.modules.dataSourceIntegrity;
import org.openide.util.NbBundle;
import org.openide.util.lookup.ServiceProvider;
import org.sleuthkit.autopsy.coreutils.Version;
import org.sleuthkit.autopsy.ingest.IngestModuleFactoryAdapter;
import org.sleuthkit.autopsy.ingest.DataSourceIngestModule;
import org.sleuthkit.autopsy.ingest.IngestModuleFactory;
import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings;
import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettingsPanel;
import org.sleuthkit.autopsy.ingest.NoIngestModuleIngestJobSettings;
/**
* An factory that creates data source ingest modules that verify the integrity
* of Expert Witness Format (EWF), i.e., .e01 files .
*/
@ServiceProvider(service = IngestModuleFactory.class)
public class DataSourceIntegrityModuleFactory extends IngestModuleFactoryAdapter {
static String getModuleName() {
return NbBundle.getMessage(DataSourceIntegrityIngestModule.class,
"DataSourceIntegrityModuleFactory.moduleName.text");
}
@Override
public String getModuleDisplayName() {
return getModuleName();
}
@Override
public String getModuleDescription() {
return NbBundle.getMessage(DataSourceIntegrityIngestModule.class,
"DataSourceIntegrityModuleFactory.moduleDesc.text");
}
@Override
public String getModuleVersionNumber() {
return Version.getVersion();
}
@Override
public boolean isDataSourceIngestModuleFactory() {
return true;
}
@Override
public DataSourceIngestModule createDataSourceIngestModule(IngestModuleIngestJobSettings settings) {
if (settings instanceof DataSourceIntegrityIngestSettings) {
return new DataSourceIntegrityIngestModule((DataSourceIntegrityIngestSettings) settings);
}
/*
* Compatibility check for older versions.
*/
if (settings instanceof NoIngestModuleIngestJobSettings) {
return new DataSourceIntegrityIngestModule(new DataSourceIntegrityIngestSettings());
}
throw new IllegalArgumentException("Expected settings argument to be an instance of IngestSettings");
}
@Override
public IngestModuleIngestJobSettings getDefaultIngestJobSettings() {
return new DataSourceIntegrityIngestSettings();
}
@Override
public boolean hasIngestJobSettingsPanel() {
return true;
}
@Override
public IngestModuleIngestJobSettingsPanel getIngestJobSettingsPanel(IngestModuleIngestJobSettings settings) {
if (settings instanceof DataSourceIntegrityIngestSettings) {
return new DataSourceIntegrityIngestSettingsPanel((DataSourceIntegrityIngestSettings) settings);
}
/*
* Compatibility check for older versions.
*/
if (settings instanceof NoIngestModuleIngestJobSettings) {
return new DataSourceIntegrityIngestSettingsPanel(new DataSourceIntegrityIngestSettings());
}
throw new IllegalArgumentException("Expected settings argument to be an instance of IngestSettings");
}
}

View File

@ -1,15 +0,0 @@
OpenIDE-Module-Name=ewfVerify
EwfVerifyIngestModule.moduleName.text=E01 Verifier
EwfVerifyIngestModule.moduleDesc.text=Validates the integrity of E01 files.
EwfVerifyIngestModule.process.errProcImg=Error processing {0}
EwfVerifyIngestModule.process.skipNonEwf=Skipping non-E01 image {0}
EwfVerifyIngestModule.process.noStoredHash=Image {0} does not have stored hash.
EwfVerifyIngestModule.process.startingImg=Starting {0}
EwfVerifyIngestModule.process.errGetSizeOfImg=Error getting size of {0}. Image will not be processed.
EwfVerifyIngestModule.process.errReadImgAtChunk=Error reading {0} at chunk {1}
EwfVerifyIngestModule.shutDown.verified=\ verified
EwfVerifyIngestModule.shutDown.notVerified=\ not verified
EwfVerifyIngestModule.shutDown.verifyResultsHeader=<p>EWF Verification Results for {0}</p>
EwfVerifyIngestModule.shutDown.resultLi=<li>Result\:{0}</li>
EwfVerifyIngestModule.shutDown.calcHashLi=<li>Calculated hash\: {0}</li>
EwfVerifyIngestModule.shutDown.storedHashLi=<li>Stored hash\: {0}</li>

View File

@ -1,15 +0,0 @@
OpenIDE-Module-Name=EWFVerify
EwfVerifyIngestModule.process.errProcImg={0}\u3092\u51e6\u7406\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f
EwfVerifyIngestModule.moduleName.text=E01\u8a8d\u8a3c\u30c4\u30fc\u30eb
EwfVerifyIngestModule.moduleDesc.text=E01\u30d5\u30a1\u30a4\u30eb\u306e\u6574\u5408\u6027\u3092\u8a8d\u8a3c\u3057\u307e\u3059\u3002
EwfVerifyIngestModule.process.skipNonEwf=E01\u30a4\u30e1\u30fc\u30b8\u3067\u306f\u306a\u3044{0}\u3092\u30b9\u30ad\u30c3\u30d7\u3057\u3066\u3044\u307e\u3059
EwfVerifyIngestModule.process.noStoredHash=\u30a4\u30e1\u30fc\u30b8{0}\u306f\u4fdd\u5b58\u3055\u308c\u3066\u3044\u308b\u30cf\u30c3\u30b7\u30e5\u304c\u3042\u308a\u307e\u305b\u3093\u3002
EwfVerifyIngestModule.process.startingImg={0}\u3092\u958b\u59cb\u4e2d
EwfVerifyIngestModule.process.errGetSizeOfImg={0}\u306e\u30b5\u30a4\u30ba\u306e\u53d6\u5f97\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002\u30a4\u30e1\u30fc\u30b8\u306f\u51e6\u7406\u3055\u308c\u307e\u305b\u3093\u3002
EwfVerifyIngestModule.process.errReadImgAtChunk={0}\u306e\u30c1\u30e3\u30f3\u30af{1}\u306e\u8aad\u307f\u53d6\u308a\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f
EwfVerifyIngestModule.shutDown.calcHashLi=<li>\u8a08\u7b97\u3055\u308c\u305f\u30cf\u30c3\u30b7\u30e5\u5024\uff1a{0}</li>
EwfVerifyIngestModule.shutDown.notVerified=\u8a8d\u8a3c\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f
EwfVerifyIngestModule.shutDown.resultLi=<li>\u7d50\u679c\uff1a{0}</li>
EwfVerifyIngestModule.shutDown.storedHashLi=<li>\u4fdd\u5b58\u3055\u308c\u305f\u30cf\u30c3\u30b7\u30e5\uff1a {0}</li>
EwfVerifyIngestModule.shutDown.verifyResultsHeader=<p>{0}\u306eEWF\u30d9\u30ea\u30d5\u30a3\u30b1\u30fc\u30b7\u30e7\u30f3\u7d50\u679c</p>
EwfVerifyIngestModule.shutDown.verified=\u8a8d\u8a3c\u3055\u308c\u307e\u3057\u305f

View File

@ -1,66 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2014 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.modules.e01verify;
import org.openide.util.NbBundle;
import org.openide.util.lookup.ServiceProvider;
import org.sleuthkit.autopsy.coreutils.Version;
import org.sleuthkit.autopsy.ingest.IngestModuleFactoryAdapter;
import org.sleuthkit.autopsy.ingest.DataSourceIngestModule;
import org.sleuthkit.autopsy.ingest.IngestModuleFactory;
import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings;
/**
* An factory that creates data source ingest modules that verify the integrity
* of Expert Witness Format (EWF), i.e., .e01 files .
*/
@ServiceProvider(service = IngestModuleFactory.class)
public class E01VerifierModuleFactory extends IngestModuleFactoryAdapter {
static String getModuleName() {
return NbBundle.getMessage(E01VerifyIngestModule.class,
"EwfVerifyIngestModule.moduleName.text");
}
@Override
public String getModuleDisplayName() {
return getModuleName();
}
@Override
public String getModuleDescription() {
return NbBundle.getMessage(E01VerifyIngestModule.class,
"EwfVerifyIngestModule.moduleDesc.text");
}
@Override
public String getModuleVersionNumber() {
return Version.getVersion();
}
@Override
public boolean isDataSourceIngestModuleFactory() {
return true;
}
@Override
public DataSourceIngestModule createDataSourceIngestModule(IngestModuleIngestJobSettings ingestOptions) {
return new E01VerifyIngestModule();
}
}

View File

@ -1,189 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013-2014 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.modules.e01verify;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.logging.Level;
import javax.xml.bind.DatatypeConverter;
import org.openide.util.NbBundle;
import org.python.bouncycastle.util.Arrays;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.ingest.DataSourceIngestModule;
import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProgress;
import org.sleuthkit.autopsy.ingest.IngestJobContext;
import org.sleuthkit.autopsy.ingest.IngestMessage;
import org.sleuthkit.autopsy.ingest.IngestMessage.MessageType;
import org.sleuthkit.autopsy.ingest.IngestServices;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.Image;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData;
import org.openide.util.NbBundle;
/**
* Data source ingest module that verifies the integrity of an Expert Witness
* Format (EWF) E01 image file by generating a hash of the file and comparing it
* to the value stored in the image.
*/
@NbBundle.Messages({
"UnableToCalculateHashes=Unable to calculate MD5 hashes."
})
public class E01VerifyIngestModule implements DataSourceIngestModule {
private static final Logger logger = Logger.getLogger(E01VerifyIngestModule.class.getName());
private static final long DEFAULT_CHUNK_SIZE = 32 * 1024;
private static final IngestServices services = IngestServices.getInstance();
private MessageDigest messageDigest;
private boolean verified = false;
private String calculatedHash = "";
private String storedHash = "";
private IngestJobContext context;
E01VerifyIngestModule() {
}
@Override
public void startUp(IngestJobContext context) throws IngestModuleException {
this.context = context;
verified = false;
storedHash = "";
calculatedHash = "";
try {
messageDigest = MessageDigest.getInstance("MD5"); //NON-NLS
} catch (NoSuchAlgorithmException ex) {
throw new IngestModuleException(Bundle.UnableToCalculateHashes(), ex);
}
}
@Override
public ProcessResult process(Content dataSource, DataSourceIngestModuleProgress statusHelper) {
String imgName = dataSource.getName();
// Skip non-images
if (!(dataSource instanceof Image)) {
logger.log(Level.INFO, "Skipping non-image {0}", imgName); //NON-NLS
services.postMessage(IngestMessage.createMessage(MessageType.INFO, E01VerifierModuleFactory.getModuleName(),
NbBundle.getMessage(this.getClass(),
"EwfVerifyIngestModule.process.skipNonEwf",
imgName)));
return ProcessResult.OK;
}
Image img = (Image) dataSource;
// Skip images that are not E01
if (img.getType() != TskData.TSK_IMG_TYPE_ENUM.TSK_IMG_TYPE_EWF_EWF) {
logger.log(Level.INFO, "Skipping non-ewf image {0}", imgName); //NON-NLS
services.postMessage(IngestMessage.createMessage(MessageType.INFO, E01VerifierModuleFactory.getModuleName(),
NbBundle.getMessage(this.getClass(),
"EwfVerifyIngestModule.process.skipNonEwf",
imgName)));
return ProcessResult.OK;
}
// Report an error for null or empty MD5
if ((img.getMd5() == null) || img.getMd5().isEmpty()) {
services.postMessage(IngestMessage.createMessage(MessageType.ERROR, E01VerifierModuleFactory.getModuleName(),
NbBundle.getMessage(this.getClass(),
"EwfVerifyIngestModule.process.noStoredHash",
imgName)));
return ProcessResult.ERROR;
}
storedHash = img.getMd5().toLowerCase();
logger.log(Level.INFO, "Hash value stored in {0}: {1}", new Object[]{imgName, storedHash}); //NON-NLS
logger.log(Level.INFO, "Starting hash verification of {0}", img.getName()); //NON-NLS
services.postMessage(IngestMessage.createMessage(MessageType.INFO, E01VerifierModuleFactory.getModuleName(),
NbBundle.getMessage(this.getClass(),
"EwfVerifyIngestModule.process.startingImg",
imgName)));
long size = img.getSize();
if (size == 0) {
logger.log(Level.WARNING, "Size of image {0} was 0 when queried.", imgName); //NON-NLS
services.postMessage(IngestMessage.createMessage(MessageType.ERROR, E01VerifierModuleFactory.getModuleName(),
NbBundle.getMessage(this.getClass(),
"EwfVerifyIngestModule.process.errGetSizeOfImg",
imgName)));
}
// Libewf uses a sector size of 64 times the sector size, which is the
// motivation for using it here.
long chunkSize = 64 * img.getSsize();
chunkSize = (chunkSize == 0) ? DEFAULT_CHUNK_SIZE : chunkSize;
// Casting to double to capture decimals
int totalChunks = (int) Math.ceil((double) size / (double) chunkSize);
logger.log(Level.INFO, "Total chunks = {0}", totalChunks); //NON-NLS
int read;
byte[] data = new byte[(int) chunkSize];
statusHelper.switchToDeterminate(totalChunks);
// Read in byte size chunks and update the hash value with the data.
for (int i = 0; i < totalChunks; i++) {
if (context.dataSourceIngestIsCancelled()) {
return ProcessResult.OK;
}
try {
read = img.read(data, i * chunkSize, chunkSize);
} catch (TskCoreException ex) {
String msg = NbBundle.getMessage(this.getClass(),
"EwfVerifyIngestModule.process.errReadImgAtChunk", imgName, i);
services.postMessage(IngestMessage.createMessage(MessageType.ERROR, E01VerifierModuleFactory.getModuleName(), msg));
logger.log(Level.SEVERE, msg, ex);
return ProcessResult.ERROR;
}
// Only update with the read bytes.
if (read == chunkSize) {
messageDigest.update(data);
} else {
byte[] subData = Arrays.copyOfRange(data, 0, read);
messageDigest.update(subData);
}
statusHelper.progress(i);
}
// Finish generating the hash and get it as a string value
calculatedHash = DatatypeConverter.printHexBinary(messageDigest.digest()).toLowerCase();
verified = calculatedHash.equals(storedHash);
logger.log(Level.INFO, "Hash calculated from {0}: {1}", new Object[]{imgName, calculatedHash}); //NON-NLS
logger.log(Level.INFO, "complete() {0}", E01VerifierModuleFactory.getModuleName()); //NON-NLS
String msg;
if (verified) {
msg = NbBundle.getMessage(this.getClass(), "EwfVerifyIngestModule.shutDown.verified");
} else {
msg = NbBundle.getMessage(this.getClass(), "EwfVerifyIngestModule.shutDown.notVerified");
}
String extra = NbBundle
.getMessage(this.getClass(), "EwfVerifyIngestModule.shutDown.verifyResultsHeader", imgName);
extra += NbBundle.getMessage(this.getClass(), "EwfVerifyIngestModule.shutDown.resultLi", msg);
extra += NbBundle.getMessage(this.getClass(), "EwfVerifyIngestModule.shutDown.calcHashLi", calculatedHash);
extra += NbBundle.getMessage(this.getClass(), "EwfVerifyIngestModule.shutDown.storedHashLi", storedHash);
services.postMessage(IngestMessage.createMessage(MessageType.INFO, E01VerifierModuleFactory.getModuleName(), imgName + msg, extra));
logger.log(Level.INFO, "{0}{1}", new Object[]{imgName, msg});
return ProcessResult.OK;
}
}

View File

@ -23,6 +23,7 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
@ -66,6 +67,7 @@ import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.DerivedFile;
import org.sleuthkit.datamodel.EncodedFileOutputStream;
import org.sleuthkit.datamodel.ReadContentInputStream;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData;
@ -242,28 +244,41 @@ class SevenZipExtractor {
String msg = NbBundle.getMessage(SevenZipExtractor.class,
"EmbeddedFileExtractorIngestModule.ArchiveExtractor.isZipBombCheck.warnMsg", archiveFile.getName(), escapedFilePath);
try {
BlackboardArtifact artifact = rootArchive.getArchiveFile().newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT);
artifact.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME, EmbeddedFileExtractorModuleFactory.getModuleName(),
Collection<BlackboardAttribute> attributes = new ArrayList<>();
attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME, EmbeddedFileExtractorModuleFactory.getModuleName(),
"Possible Zip Bomb"));
artifact.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DESCRIPTION,
attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DESCRIPTION,
EmbeddedFileExtractorModuleFactory.getModuleName(),
Bundle.SevenZipExtractor_zipBombArtifactCreation_text(archiveFile.getName())));
artifact.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT,
attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT,
EmbeddedFileExtractorModuleFactory.getModuleName(),
details));
try {
// index the artifact for keyword search
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.SevenZipExtractor_indexError_message(), artifact.getDisplayName());
SleuthkitCase tskCase = Case.getCurrentCaseThrows().getSleuthkitCase();
org.sleuthkit.datamodel.Blackboard tskBlackboard = tskCase.getBlackboard();
// Create artifact if it doesn't already exist.
if (!tskBlackboard.artifactExists(archiveFile, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT, attributes)) {
BlackboardArtifact artifact = archiveFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT);
artifact.addAttributes(attributes);
try {
// index the artifact for keyword search
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.SevenZipExtractor_indexError_message(), artifact.getDisplayName());
}
services.postMessage(IngestMessage.createWarningMessage(EmbeddedFileExtractorModuleFactory.getModuleName(), msg, details));
services.fireModuleDataEvent(new ModuleDataEvent(EmbeddedFileExtractorModuleFactory.getModuleName(), BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT));
}
services.fireModuleDataEvent(new ModuleDataEvent(EmbeddedFileExtractorModuleFactory.getModuleName(), BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT));
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Error creating blackboard artifact for Zip Bomb Detection for file: " + escapedFilePath, ex); //NON-NLS
} catch (NoCurrentCaseException ex) {
logger.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS
}
services.postMessage(IngestMessage.createWarningMessage(EmbeddedFileExtractorModuleFactory.getModuleName(), msg, details));
}
/**

View File

@ -38,6 +38,7 @@ import java.util.List;
import java.util.TimeZone;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import org.apache.commons.lang3.StringUtils;
import org.openide.util.NbBundle;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.casemodule.Case;
@ -77,7 +78,6 @@ public final class ExifParserFileIngestModule implements FileIngestModule {
private static final Logger logger = Logger.getLogger(ExifParserFileIngestModule.class.getName());
private final IngestServices services = IngestServices.getInstance();
private final AtomicInteger filesProcessed = new AtomicInteger(0);
private final List<BlackboardArtifact> listOfFacesDetectedArtifacts = new ArrayList<>();
private long jobId;
private static final IngestModuleReferenceCounter refCounter = new IngestModuleReferenceCounter();
private FileTypeDetector fileTypeDetector;
@ -190,12 +190,12 @@ public final class ExifParserFileIngestModule implements FileIngestModule {
ExifIFD0Directory devDir = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class);
if (devDir != null) {
String model = devDir.getString(ExifIFD0Directory.TAG_MODEL);
if (model != null && !model.isEmpty()) {
if (StringUtils.isNotBlank(model)) {
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DEVICE_MODEL, ExifParserModuleFactory.getModuleName(), model));
}
String make = devDir.getString(ExifIFD0Directory.TAG_MAKE);
if (make != null && !make.isEmpty()) {
if (StringUtils.isNotBlank(make)) {
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DEVICE_MAKE, ExifParserModuleFactory.getModuleName(), make));
}
}

View File

@ -147,23 +147,29 @@ public class FileTypeIdIngestModule implements FileIngestModule {
*/
private void createInterestingFileHit(AbstractFile file, FileType fileType) {
try {
BlackboardArtifact artifact;
artifact = file.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT);
Collection<BlackboardAttribute> attributes = new ArrayList<>();
BlackboardAttribute setNameAttribute = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME, FileTypeIdModuleFactory.getModuleName(), fileType.getInterestingFilesSetName());
attributes.add(setNameAttribute);
BlackboardAttribute ruleNameAttribute = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CATEGORY, FileTypeIdModuleFactory.getModuleName(), fileType.getMimeType());
attributes.add(ruleNameAttribute);
artifact.addAttributes(attributes);
try {
Case.getCurrentCaseThrows().getServices().getBlackboard().indexArtifact(artifact);
} catch (Blackboard.BlackboardException ex) {
logger.log(Level.SEVERE, String.format("Unable to index TSK_INTERESTING_FILE_HIT blackboard artifact %d (file obj_id=%d)", artifact.getArtifactID(), file.getId()), ex); //NON-NLS
} catch (NoCurrentCaseException ex) {
logger.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS
attributes.add(new BlackboardAttribute(
BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME, FileTypeIdModuleFactory.getModuleName(), fileType.getInterestingFilesSetName()));
attributes.add(new BlackboardAttribute(
BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CATEGORY, FileTypeIdModuleFactory.getModuleName(), fileType.getMimeType()));
Case currentCase = Case.getCurrentCaseThrows();
org.sleuthkit.datamodel.Blackboard tskBlackboard = currentCase.getSleuthkitCase().getBlackboard();
// Create artifact if it doesn't already exist.
if (!tskBlackboard.artifactExists(file, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT, attributes)) {
BlackboardArtifact artifact = file.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT);
artifact.addAttributes(attributes);
try {
currentCase.getServices().getBlackboard().indexArtifact(artifact);
} catch (Blackboard.BlackboardException ex) {
logger.log(Level.SEVERE, String.format("Unable to index TSK_INTERESTING_FILE_HIT blackboard artifact %d (file obj_id=%d)", artifact.getArtifactID(), file.getId()), ex); //NON-NLS
}
}
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, String.format("Unable to create TSK_INTERESTING_FILE_HIT artifact for file (obj_id=%d)", file.getId()), ex); //NON-NLS
} catch (NoCurrentCaseException ex) {
logger.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS
}
}

View File

@ -106,12 +106,15 @@ final class FilesIdentifierIngestModule implements FileIngestModule {
@Override
@Messages({"FilesIdentifierIngestModule.indexError.message=Failed to index interesting file hit artifact for keyword search."})
public ProcessResult process(AbstractFile file) {
Case currentCase;
try {
blackboard = Case.getCurrentCaseThrows().getServices().getBlackboard();
currentCase = Case.getCurrentCaseThrows();
} catch (NoCurrentCaseException ex) {
logger.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS
return ProcessResult.ERROR;
}
blackboard = currentCase.getServices().getBlackboard();
// Skip slack space files.
if (file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.SLACK)) {
return ProcessResult.OK;
@ -126,7 +129,7 @@ final class FilesIdentifierIngestModule implements FileIngestModule {
// Post an interesting files set hit artifact to the
// blackboard.
String moduleName = InterestingItemsIngestModuleFactory.getModuleName();
BlackboardArtifact artifact = file.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT);
Collection<BlackboardAttribute> attributes = new ArrayList<>();
// Add a set name attribute to the artifact. This adds a
@ -142,28 +145,33 @@ final class FilesIdentifierIngestModule implements FileIngestModule {
BlackboardAttribute ruleNameAttribute = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CATEGORY, moduleName, ruleSatisfied);
attributes.add(ruleNameAttribute);
artifact.addAttributes(attributes);
try {
// index the artifact for keyword search
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.FilesIdentifierIngestModule_indexError_message(), artifact.getDisplayName());
org.sleuthkit.datamodel.Blackboard tskBlackboard = currentCase.getSleuthkitCase().getBlackboard();
// Create artifact if it doesn't already exist.
if (!tskBlackboard.artifactExists(file, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT, attributes)) {
BlackboardArtifact artifact = file.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT);
artifact.addAttributes(attributes);
try {
// index the artifact for keyword search
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.FilesIdentifierIngestModule_indexError_message(), artifact.getDisplayName());
}
services.fireModuleDataEvent(new ModuleDataEvent(moduleName, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT, Collections.singletonList(artifact)));
// make an ingest inbox message
StringBuilder detailsSb = new StringBuilder();
detailsSb.append("File: " + file.getParentPath() + file.getName() + "<br/>\n");
detailsSb.append("Rule Set: " + filesSet.getName());
services.postMessage(IngestMessage.createDataMessage(InterestingItemsIngestModuleFactory.getModuleName(),
"Interesting File Match: " + filesSet.getName() + "(" + file.getName() +")",
detailsSb.toString(),
file.getName(),
artifact));
}
services.fireModuleDataEvent(new ModuleDataEvent(moduleName, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT, Collections.singletonList(artifact)));
// make an ingest inbox message
StringBuilder detailsSb = new StringBuilder();
detailsSb.append("File: " + file.getParentPath() + file.getName() + "<br/>\n");
detailsSb.append("Rule Set: " + filesSet.getName());
services.postMessage(IngestMessage.createDataMessage(InterestingItemsIngestModuleFactory.getModuleName(),
"Interesting File Match: " + filesSet.getName() + "(" + file.getName() +")",
detailsSb.toString(),
file.getName(),
artifact));
} catch (TskCoreException ex) {
FilesIdentifierIngestModule.logger.log(Level.SEVERE, "Error posting to the blackboard", ex); //NOI18N NON-NLS
}

View File

@ -833,7 +833,7 @@ public final class FilesSet implements Serializable {
// If there is a leading ".", strip it since
// AbstractFile.getFileNameExtension() returns just the
// extension chars and not the dot.
super(extension.startsWith(".") ? extension.substring(1) : extension, false);
super(normalize(extension), false);
}
/**
@ -842,10 +842,10 @@ public final class FilesSet implements Serializable {
* @param extensions The file name extensions to be matched.
*/
public ExtensionCondition(List<String> extensions) {
// If there is a leading ".", strip it since
// If there is a leading "." in any list value, strip it since
// AbstractFile.getFileNameExtension() returns just the
// extension chars and not the dot.
super(extensions);
super(normalize(extensions));
}
/**
@ -863,6 +863,34 @@ public final class FilesSet implements Serializable {
return this.textMatches(file.getNameExtension());
}
/**
* Strip "." from the start of extensions in the provided list.
*
* @param extensions The list of extensions to be processed.
*
* @return A post-processed list of extensions.
*/
private static List<String> normalize(List<String> extensions) {
List<String> values = new ArrayList<>(extensions);
for (int i=0; i < values.size(); i++) {
values.set(i, normalize(values.get(i)));
}
return values;
}
/**
* Strip "." from the start of the provided extension.
*
* @param extension The extension to be processed.
*
* @return A post-processed extension.
*/
private static String normalize(String extension) {
return extension.startsWith(".") ? extension.substring(1) : extension;
}
}
/**
@ -986,19 +1014,7 @@ public final class FilesSet implements Serializable {
* match.
*/
CaseInsensitiveMultiValueStringComparisionMatcher(List<String> valuesToMatch) {
List<String> values = new ArrayList<>(valuesToMatch);
for (int i=0; i < values.size(); i++) {
// Remove leading and trailing whitespace.
String tempValue = values.get(i).trim();
// Strip "." from the start of the extension if it exists.
if (tempValue.startsWith(".")) {
tempValue = tempValue.substring(1);
}
values.set(i, tempValue);
}
this.valuesToMatch = values;
this.valuesToMatch = valuesToMatch;
}
@Override

View File

@ -485,7 +485,12 @@ final class FilesSetRulePanel extends javax.swing.JPanel {
if (this.fullNameRadioButton.isSelected()) {
condition = new FilesSet.Rule.FullNameCondition(this.nameTextField.getText());
} else {
condition = new FilesSet.Rule.ExtensionCondition(Arrays.asList(this.nameTextField.getText().split(",")));
List<String> extensions = Arrays.asList(this.nameTextField.getText().split(","));
for (int i=0; i < extensions.size(); i++) {
// Remove leading and trailing whitespace.
extensions.set(i, extensions.get(i).trim());
}
condition = new FilesSet.Rule.ExtensionCondition(extensions);
}
} else {
logger.log(Level.SEVERE, "Attempt to get name condition with illegal chars"); // NON-NLS

View File

@ -64,9 +64,9 @@ class StixArtifactData {
@Messages({"StixArtifactData.indexError.message=Failed to index STIX interesting file hit artifact for keyword search.",
"StixArtifactData.noOpenCase.errMsg=No open case available."})
public void createArtifact(String a_title) throws TskCoreException {
Blackboard blackboard;
Case currentCase;
try {
blackboard = Case.getCurrentCaseThrows().getServices().getBlackboard();
currentCase = Case.getCurrentCaseThrows();
} catch (NoCurrentCaseException ex) {
logger.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS
MessageNotifyUtil.Notify.error(Bundle.StixArtifactData_noOpenCase_errMsg(), ex.getLocalizedMessage());
@ -80,19 +80,25 @@ class StixArtifactData {
setName = "STIX Indicator - (no title)"; //NON-NLS
}
BlackboardArtifact bba = file.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT);
Collection<BlackboardAttribute> attributes = new ArrayList<>();
attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME, "Stix", setName)); //NON-NLS
attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TITLE, "Stix", observableId)); //NON-NLS
attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CATEGORY, "Stix", objType)); //NON-NLS
bba.addAttributes(attributes);
try {
// index the artifact for keyword search
blackboard.indexArtifact(bba);
} catch (Blackboard.BlackboardException ex) {
logger.log(Level.SEVERE, "Unable to index blackboard artifact " + bba.getArtifactID(), ex); //NON-NLS
MessageNotifyUtil.Notify.error(Bundle.StixArtifactData_indexError_message(), bba.getDisplayName());
org.sleuthkit.datamodel.Blackboard tskBlackboard = currentCase.getSleuthkitCase().getBlackboard();
// Create artifact if it doesn't already exist.
if (!tskBlackboard.artifactExists(file, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT, attributes)) {
BlackboardArtifact bba = file.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT);
bba.addAttributes(attributes);
try {
// index the artifact for keyword search
Blackboard blackboard = currentCase.getServices().getBlackboard();
blackboard.indexArtifact(bba);
} catch (Blackboard.BlackboardException ex) {
logger.log(Level.SEVERE, "Unable to index blackboard artifact " + bba.getArtifactID(), ex); //NON-NLS
MessageNotifyUtil.Notify.error(Bundle.StixArtifactData_indexError_message(), bba.getDisplayName());
}
}
}

View File

@ -91,6 +91,9 @@
<ResourceString bundle="org/sleuthkit/autopsy/othercasessearch/Bundle.properties" key="OtherCasesSearchDialog.correlationValueTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="keyReleased" listener="java.awt.event.KeyListener" parameters="java.awt.event.KeyEvent" handler="valueFieldKeyReleaseListener"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="searchButton">
<Properties>
@ -116,6 +119,9 @@
<StringArray count="0"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="correlationTypeComboBoxActionPerformed"/>
</Events>
<AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;String&gt;"/>
</AuxValues>

View File

@ -56,16 +56,22 @@ import org.sleuthkit.autopsy.datamodel.EmptyNode;
"OtherCasesSearchDialog.validation.invalidEmail=The supplied value is not a valid e-mail address.",
"OtherCasesSearchDialog.validation.invalidDomain=The supplied value is not a valid domain.",
"OtherCasesSearchDialog.validation.invalidPhone=The supplied value is not a valid phone number.",
"OtherCasesSearchDialog.validation.invalidSsid=The supplied value is not a valid wireless network.",
"OtherCasesSearchDialog.validation.invalidMac=The supplied value is not a valid MAC address.",
"OtherCasesSearchDialog.validation.invalidImei=The supplied value is not a valid IMEI number.",
"OtherCasesSearchDialog.validation.invalidImsi=The supplied value is not a valid IMSI number.",
"OtherCasesSearchDialog.validation.invalidIccid=The supplied value is not a valid ICCID number.",
"OtherCasesSearchDialog.validation.genericMessage=The supplied value is not valid.",
"# {0} - number of cases",
"OtherCasesSearchDialog.caseLabel.text=The current Central Repository contains {0} case(s)."
})
/**
* The Search Other Cases dialog allows users to search for specific
* types of correlation properties in the Central Repository.
* The Search Other Cases dialog allows users to search for specific types of
* correlation properties in the Central Repository.
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
final class OtherCasesSearchDialog extends javax.swing.JDialog {
private static final Logger logger = Logger.getLogger(OtherCasesSearchDialog.class.getName());
private static final long serialVersionUID = 1L;
@ -86,7 +92,7 @@ final class OtherCasesSearchDialog extends javax.swing.JDialog {
/**
* Perform the other cases search.
*
* @param type The correlation type.
* @param type The correlation type.
* @param value The value to be matched.
*/
private void search(CorrelationAttributeInstance.Type type, String value) {
@ -163,6 +169,11 @@ final class OtherCasesSearchDialog extends javax.swing.JDialog {
org.openide.awt.Mnemonics.setLocalizedText(correlationValueLabel, org.openide.util.NbBundle.getMessage(OtherCasesSearchDialog.class, "OtherCasesSearchDialog.correlationValueLabel.text")); // NOI18N
correlationValueTextField.setText(org.openide.util.NbBundle.getMessage(OtherCasesSearchDialog.class, "OtherCasesSearchDialog.correlationValueTextField.text")); // NOI18N
correlationValueTextField.addKeyListener(new java.awt.event.KeyAdapter() {
public void keyReleased(java.awt.event.KeyEvent evt) {
valueFieldKeyReleaseListener(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(searchButton, org.openide.util.NbBundle.getMessage(OtherCasesSearchDialog.class, "OtherCasesSearchDialog.searchButton.text")); // NOI18N
searchButton.addActionListener(new java.awt.event.ActionListener() {
@ -171,6 +182,12 @@ final class OtherCasesSearchDialog extends javax.swing.JDialog {
}
});
correlationTypeComboBox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
correlationTypeComboBoxActionPerformed(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(correlationTypeLabel, org.openide.util.NbBundle.getMessage(OtherCasesSearchDialog.class, "OtherCasesSearchDialog.correlationTypeLabel.text")); // NOI18N
errorLabel.setForeground(new java.awt.Color(255, 0, 0));
@ -254,6 +271,21 @@ final class OtherCasesSearchDialog extends javax.swing.JDialog {
case CorrelationAttributeInstance.PHONE_TYPE_ID:
validationMessage = Bundle.OtherCasesSearchDialog_validation_invalidPhone();
break;
case CorrelationAttributeInstance.SSID_TYPE_ID:
validationMessage = Bundle.OtherCasesSearchDialog_validation_invalidSsid();
break;
case CorrelationAttributeInstance.MAC_TYPE_ID:
validationMessage = Bundle.OtherCasesSearchDialog_validation_invalidMac();
break;
case CorrelationAttributeInstance.IMEI_TYPE_ID:
validationMessage = Bundle.OtherCasesSearchDialog_validation_invalidImei();
break;
case CorrelationAttributeInstance.IMSI_TYPE_ID:
validationMessage = Bundle.OtherCasesSearchDialog_validation_invalidImsi();
break;
case CorrelationAttributeInstance.ICCID_TYPE_ID:
validationMessage = Bundle.OtherCasesSearchDialog_validation_invalidIccid();
break;
default:
validationMessage = Bundle.OtherCasesSearchDialog_validation_genericMessage();
break;
@ -265,10 +297,20 @@ final class OtherCasesSearchDialog extends javax.swing.JDialog {
}
}//GEN-LAST:event_searchButtonActionPerformed
private void correlationTypeComboBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_correlationTypeComboBoxActionPerformed
//make error message go away when combo box is selected
errorLabel.setText("");
}//GEN-LAST:event_correlationTypeComboBoxActionPerformed
private void valueFieldKeyReleaseListener(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_valueFieldKeyReleaseListener
//make error message go away when the user enters anything in the value field
errorLabel.setText("");
}//GEN-LAST:event_valueFieldKeyReleaseListener
/**
* Validate the supplied input.
*
* @param type The correlation type.
* @param type The correlation type.
* @param value The value to be validated.
*
* @return True if the input is valid for the given type; otherwise false.
@ -348,7 +390,11 @@ final class OtherCasesSearchDialog extends javax.swing.JDialog {
"OtherCasesSearchDialog.correlationValueTextField.emailExample=Example: \"user@host.com\"",
"OtherCasesSearchDialog.correlationValueTextField.phoneExample=Example: \"(800)123-4567\"",
"OtherCasesSearchDialog.correlationValueTextField.usbExample=Example: \"4&1234567&0\"",
"OtherCasesSearchDialog.correlationValueTextField.ssidExample=Example: \"WirelessNetwork-5G\""
"OtherCasesSearchDialog.correlationValueTextField.ssidExample=Example: \"WirelessNetwork-5G\"",
"OtherCasesSearchDialog.correlationValueTextField.macExample=Example: \"0C-14-F2-01-AF-45\"",
"OtherCasesSearchDialog.correlationValueTextField.imeiExample=Example: \"351756061523999\"",
"OtherCasesSearchDialog.correlationValueTextField.imsiExample=Example: \"310150123456789\"",
"OtherCasesSearchDialog.correlationValueTextField.iccidExample=Example: \"89 91 19 1299 99 329451 0\""
})
/**
* Update the text prompt of the name text field based on the input type
@ -359,7 +405,7 @@ final class OtherCasesSearchDialog extends javax.swing.JDialog {
* Add text prompt to the text field.
*/
String text;
switch(selectedCorrelationType.getId()) {
switch (selectedCorrelationType.getId()) {
case CorrelationAttributeInstance.FILES_TYPE_ID:
text = Bundle.OtherCasesSearchDialog_correlationValueTextField_filesExample();
break;
@ -378,6 +424,18 @@ final class OtherCasesSearchDialog extends javax.swing.JDialog {
case CorrelationAttributeInstance.SSID_TYPE_ID:
text = Bundle.OtherCasesSearchDialog_correlationValueTextField_ssidExample();
break;
case CorrelationAttributeInstance.MAC_TYPE_ID:
text = Bundle.OtherCasesSearchDialog_correlationValueTextField_macExample();
break;
case CorrelationAttributeInstance.IMEI_TYPE_ID:
text = Bundle.OtherCasesSearchDialog_correlationValueTextField_imeiExample();
break;
case CorrelationAttributeInstance.IMSI_TYPE_ID:
text = Bundle.OtherCasesSearchDialog_correlationValueTextField_imsiExample();
break;
case CorrelationAttributeInstance.ICCID_TYPE_ID:
text = Bundle.OtherCasesSearchDialog_correlationValueTextField_iccidExample();
break;
default:
text = "";
break;

View File

@ -285,7 +285,19 @@ class ReportHTML implements TableReportModule {
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/accounts.png"); //NON-NLS
break;
case TSK_WIFI_NETWORK:
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/network-wifi.png"); //NON-NLS
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/images/network-wifi.png"); //NON-NLS
break;
case TSK_WIFI_NETWORK_ADAPTER:
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/images/network-wifi.png"); //NON-NLS
break;
case TSK_SIM_ATTACHED:
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/images/sim_card.png"); //NON-NLS
break;
case TSK_BLUETOOTH_ADAPTER:
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/images/Bluetooth.png"); //NON-NLS
break;
case TSK_DEVICE_INFO:
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/images/devices.png"); //NON-NLS
break;
default:
logger.log(Level.WARNING, "useDataTypeIcon: unhandled artifact type = {0}", dataType); //NON-NLS

View File

@ -56,11 +56,11 @@ import org.sleuthkit.autopsy.commonfilesearch.CaseDBCommonAttributeInstanceNode;
import org.sleuthkit.autopsy.commonfilesearch.CentralRepoCommonAttributeInstance;
import org.sleuthkit.autopsy.commonfilesearch.CentralRepoCommonAttributeInstanceNode;
import org.sleuthkit.autopsy.commonfilesearch.CommonAttributeSearchResults;
import org.sleuthkit.autopsy.commonfilesearch.DataSourceLoader;
import org.sleuthkit.autopsy.guiutils.DataSourceLoader;
import org.sleuthkit.autopsy.commonfilesearch.CommonAttributeValue;
import org.sleuthkit.autopsy.commonfilesearch.CommonAttributeValueList;
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode;
import org.sleuthkit.autopsy.modules.e01verify.E01VerifierModuleFactory;
import org.sleuthkit.autopsy.modules.dataSourceIntegrity.DataSourceIntegrityModuleFactory;
import org.sleuthkit.autopsy.modules.embeddedfileextractor.EmbeddedFileExtractorModuleFactory;
import org.sleuthkit.autopsy.modules.exif.ExifParserModuleFactory;
import org.sleuthkit.autopsy.modules.fileextmismatch.FileExtMismatchDetectorModuleFactory;
@ -183,8 +183,8 @@ class InterCaseTestUtils {
final IngestModuleTemplate hashLookupTemplate = IngestUtils.getIngestModuleTemplate(new HashLookupModuleFactory());
final IngestModuleTemplate vmExtractorTemplate = IngestUtils.getIngestModuleTemplate(new VMExtractorIngestModuleFactory());
final IngestModuleTemplate photoRecTemplate = IngestUtils.getIngestModuleTemplate(new PhotoRecCarverIngestModuleFactory());
final IngestModuleTemplate e01VerifierTemplate = IngestUtils.getIngestModuleTemplate(new E01VerifierModuleFactory());
final IngestModuleTemplate eamDbTemplate = IngestUtils.getIngestModuleTemplate(new org.sleuthkit.autopsy.centralrepository.ingestmodule.IngestModuleFactory());
final IngestModuleTemplate dataSourceIntegrityTemplate = IngestUtils.getIngestModuleTemplate(new DataSourceIntegrityModuleFactory());
final IngestModuleTemplate eamDbTemplate = IngestUtils.getIngestModuleTemplate(new org.sleuthkit.autopsy.centralrepository.ingestmodule.CentralRepoIngestModuleFactory());
final IngestModuleTemplate fileExtMismatchDetectorTemplate = IngestUtils.getIngestModuleTemplate(new FileExtMismatchDetectorModuleFactory());
//TODO we need to figure out how to get ahold of these objects because they are required for properly filling the CR with test data
// final IngestModuleTemplate objectDetectorTemplate = IngestUtils.getIngestModuleTemplate(new org.sleuthkit.autopsy.experimental.objectdetection.ObjectDetectionModuleFactory());
@ -217,10 +217,10 @@ class InterCaseTestUtils {
kitchenSink.add(hashLookupTemplate);
kitchenSink.add(vmExtractorTemplate);
kitchenSink.add(photoRecTemplate);
kitchenSink.add(e01VerifierTemplate);
kitchenSink.add(dataSourceIntegrityTemplate);
kitchenSink.add(eamDbTemplate);
kitchenSink.add(fileExtMismatchDetectorTemplate);
//TODO this list should probably be populated by way of loading the appropriate modules based on finding all of the @ServiceProvider(service = IngestModuleFactory.class) types
//TODO this list should probably be populated by way of loading the appropriate modules based on finding all of the @ServiceProvider(service = CentralRepoIngestModuleFactory.class) types
// kitchenSink.add(objectDetectorTemplate);
// kitchenSink.add(emailParserTemplate);
// kitchenSink.add(recentActivityTemplate);

View File

@ -36,7 +36,7 @@ import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
import org.sleuthkit.autopsy.commonfilesearch.AbstractCommonAttributeInstance;
import org.sleuthkit.autopsy.commonfilesearch.CommonAttributeSearchResults;
import org.sleuthkit.autopsy.commonfilesearch.DataSourceLoader;
import org.sleuthkit.autopsy.guiutils.DataSourceLoader;
import org.sleuthkit.autopsy.commonfilesearch.CommonAttributeValue;
import org.sleuthkit.autopsy.commonfilesearch.CommonAttributeValueList;
import org.sleuthkit.autopsy.coreutils.TimeStampUtils;

View File

@ -24,6 +24,7 @@ import java.io.File;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@ -374,25 +375,32 @@ class VolatilityProcessor {
continue;
}
try {
BlackboardArtifact volArtifact = resolvedFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT);
BlackboardAttribute att1 = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME, VOLATILITY, Bundle.VolatilityProcessor_artifactAttribute_interestingFileSet(pluginName));
volArtifact.addAttribute(att1);
Collection<BlackboardAttribute> attributes = new ArrayList<>();
attributes.add(new BlackboardAttribute(
BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME, VOLATILITY, Bundle.VolatilityProcessor_artifactAttribute_interestingFileSet(pluginName)));
try {
// index the artifact for keyword search
blackboard.indexArtifact(volArtifact);
} catch (Blackboard.BlackboardException ex) {
errorMsgs.add(Bundle.VolatilityProcessor_errorMessage_failedToIndexArtifact(pluginName));
/*
* Log the exception as well as add it to the error
* messages, to ensure that the stack trace is not
* lost.
*/
logger.log(Level.SEVERE, String.format("Failed to index artifact (artifactId=%d) for for output of %s plugin", volArtifact.getArtifactID(), pluginName), ex);
org.sleuthkit.datamodel.Blackboard tskBlackboard = currentCase.getSleuthkitCase().getBlackboard();
// Create artifact if it doesn't already exist.
if (!tskBlackboard.artifactExists(resolvedFile, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT, attributes)) {
BlackboardArtifact volArtifact = resolvedFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT);
volArtifact.addAttributes(attributes);
try {
// index the artifact for keyword search
blackboard.indexArtifact(volArtifact);
} catch (Blackboard.BlackboardException ex) {
errorMsgs.add(Bundle.VolatilityProcessor_errorMessage_failedToIndexArtifact(pluginName));
/*
* Log the exception as well as add it to the error
* messages, to ensure that the stack trace is not
* lost.
*/
logger.log(Level.SEVERE, String.format("Failed to index artifact (artifactId=%d) for for output of %s plugin", volArtifact.getArtifactID(), pluginName), ex);
}
// fire event to notify UI of this new artifact
services.fireModuleDataEvent(new ModuleDataEvent(VOLATILITY, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT));
}
// fire event to notify UI of this new artifact
services.fireModuleDataEvent(new ModuleDataEvent(VOLATILITY, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT));
} catch (TskCoreException ex) {
throw new VolatilityProcessorException(Bundle.VolatilityProcessor_exceptionMessage_errorCreatingArtifact(pluginName), ex);
}

View File

@ -7,7 +7,7 @@ nbplatform.active.dir=${suite.dir}/netbeans-plat/${netbeans-plat-version}
harness.dir=${nbplatform.active.dir}/harness
bootstrap.url=http://bits.netbeans.org/dev/nbms-and-javadoc/lastSuccessfulBuild/artifact/nbbuild/netbeans/harness/tasks.jar
# Where we get the platform from. To see what versions are available, open URL in browser up to the .../updates part of the URL
autoupdate.catalog.url=http://updates.netbeans.org/netbeans/updates/${netbeans-plat-version}/uc/final/distribution/catalog.xml.gz
autoupdate.catalog.url=https://updates.netbeans.org/netbeans/updates/${netbeans-plat-version}/uc/final/distribution/catalog.xml.gz
cluster.path=\
${nbplatform.active.dir}/harness:\
${nbplatform.active.dir}/java:\

View File

@ -8,7 +8,7 @@ nbplatform.active.dir=${suite.dir}/netbeans-plat/${netbeans-plat-version}
harness.dir=${nbplatform.active.dir}/harness
bootstrap.url=http://bits.netbeans.org/dev/nbms-and-javadoc/lastSuccessfulBuild/artifact/nbbuild/netbeans/harness/tasks.jar
# Where we get the platform from. To see what versions are available, open URL in browser up to the .../updates part of the URL
autoupdate.catalog.url=http://updates.netbeans.org/netbeans/updates/${netbeans-plat-version}/uc/final/distribution/catalog.xml.gz
autoupdate.catalog.url=https://updates.netbeans.org/netbeans/updates/${netbeans-plat-version}/uc/final/distribution/catalog.xml.gz
cluster.path=\
${nbplatform.active.dir}/harness:\
${nbplatform.active.dir}/java:\

View File

@ -7,7 +7,7 @@ nbplatform.active.dir=${suite.dir}/netbeans-plat/${netbeans-plat-version}
harness.dir=${nbplatform.active.dir}/harness
bootstrap.url=http://bits.netbeans.org/dev/nbms-and-javadoc/lastSuccessfulBuild/artifact/nbbuild/netbeans/harness/tasks.jar
# Where we get the platform from. To see what versions are available, open URL in browser up to the .../updates part of the URL
autoupdate.catalog.url=http://updates.netbeans.org/netbeans/updates/${netbeans-plat-version}/uc/final/distribution/catalog.xml.gz
autoupdate.catalog.url=https://updates.netbeans.org/netbeans/updates/${netbeans-plat-version}/uc/final/distribution/catalog.xml.gz
cluster.path=\
${nbplatform.active.dir}/harness:\
${nbplatform.active.dir}/java:\