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

@ -31,6 +31,8 @@
<dependency conf="core->default" org="org.jsoup" name="jsoup" rev="1.10.3"/> <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.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"/> <dependency conf="core->default" org="commons-validator" name="commons-validator" rev="1.6"/>

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-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.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.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-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.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 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> <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> <binary-origin>release/modules/ext/curator-client-2.8.0.jar</binary-origin>
</class-path-extension> </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> <class-path-extension>
<runtime-relative-path>ext/cxf-rt-frontend-jaxrs-3.0.16.jar</runtime-relative-path> <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> <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. * 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(CaseCloseAction.class).setEnabled(true);
CallableSystemAction.get(CasePropertiesAction.class).setEnabled(true); CallableSystemAction.get(CasePropertiesAction.class).setEnabled(true);
CallableSystemAction.get(CaseDeleteAction.class).setEnabled(true); CallableSystemAction.get(CaseDeleteAction.class).setEnabled(true);

View File

@ -1,16 +1,16 @@
/* /*
* *
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2018 Basis Technology Corp. * Copyright 2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -25,36 +25,41 @@ import org.apache.commons.validator.routines.DomainValidator;
import org.apache.commons.validator.routines.EmailValidator; 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 { 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... * 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. * data is a valid string of the format expected given the attributeType.
* *
* @param attributeType correlation type of data * @param attributeType correlation type of data
* @param data data to normalize * @param data data to normalize
* *
* @return normalized data * @return normalized data
*/ */
public static String normalize(CorrelationAttributeInstance.Type attributeType, String data) throws CorrelationAttributeNormalizationException { public static String normalize(CorrelationAttributeInstance.Type attributeType, String data) throws CorrelationAttributeNormalizationException {
if(attributeType == null){ if (attributeType == null) {
throw new CorrelationAttributeNormalizationException("Attribute type was null."); throw new CorrelationAttributeNormalizationException("Attribute type was null.");
} }
if(data == null){ if (data == null) {
throw new CorrelationAttributeNormalizationException("Data was null."); throw new CorrelationAttributeNormalizationException("Data was null.");
} }
String trimmedData = data.trim(); String trimmedData = data.trim();
switch(attributeType.getId()){ switch (attributeType.getId()) {
case CorrelationAttributeInstance.FILES_TYPE_ID: case CorrelationAttributeInstance.FILES_TYPE_ID:
return normalizeMd5(trimmedData); return normalizeMd5(trimmedData);
case CorrelationAttributeInstance.DOMAIN_TYPE_ID: case CorrelationAttributeInstance.DOMAIN_TYPE_ID:
@ -66,38 +71,39 @@ final public class CorrelationAttributeNormalizer {
case CorrelationAttributeInstance.USBID_TYPE_ID: case CorrelationAttributeInstance.USBID_TYPE_ID:
return normalizeUsbId(trimmedData); return normalizeUsbId(trimmedData);
case CorrelationAttributeInstance.SSID_TYPE_ID: case CorrelationAttributeInstance.SSID_TYPE_ID:
return trimmedData; return verifySsid(trimmedData);
case CorrelationAttributeInstance.MAC_TYPE_ID: case CorrelationAttributeInstance.MAC_TYPE_ID:
return trimmedData; return normalizeMac(trimmedData);
case CorrelationAttributeInstance.IMEI_TYPE_ID: case CorrelationAttributeInstance.IMEI_TYPE_ID:
return trimmedData; return normalizeImei(trimmedData);
case CorrelationAttributeInstance.IMSI_TYPE_ID: case CorrelationAttributeInstance.IMSI_TYPE_ID:
return trimmedData; return normalizeImsi(trimmedData);
case CorrelationAttributeInstance.ICCID_TYPE_ID: case CorrelationAttributeInstance.ICCID_TYPE_ID:
return trimmedData; return normalizeIccid(trimmedData);
default: default:
final String errorMessage = String.format( final String errorMessage = String.format(
"Validator function not found for attribute type: %s", "Validator function not found for attribute type: %s",
attributeType.getDisplayName()); attributeType.getDisplayName());
throw new CorrelationAttributeNormalizationException(errorMessage); throw new CorrelationAttributeNormalizationException(errorMessage);
} }
} }
/** /**
* Validate the data. Converts text to lower case, and ensures that the * Validate the data. Converts text to lower case, and ensures that the data
* data is a valid string of the format expected given the attributeType. * is a valid string of the format expected given the attributeType.
* *
* @param attributeTypeId correlation type of data * @param attributeTypeId correlation type of data
* @param data data to normalize * @param data data to normalize
* *
* @return normalized data * @return normalized data
*/ */
public static String normalize(int attributeTypeId, String data) throws CorrelationAttributeNormalizationException { public static String normalize(int attributeTypeId, String data) throws CorrelationAttributeNormalizationException {
try { try {
List<CorrelationAttributeInstance.Type> defaultTypes = CorrelationAttributeInstance.getDefaultCorrelationTypes(); List<CorrelationAttributeInstance.Type> defaultTypes = CorrelationAttributeInstance.getDefaultCorrelationTypes();
Optional<CorrelationAttributeInstance.Type> typeOption = defaultTypes.stream().filter(attributeType -> attributeType.getId() == attributeTypeId).findAny(); Optional<CorrelationAttributeInstance.Type> typeOption = defaultTypes.stream().filter(attributeType -> attributeType.getId() == attributeTypeId).findAny();
if(typeOption.isPresent()){ if (typeOption.isPresent()) {
CorrelationAttributeInstance.Type type = typeOption.get(); CorrelationAttributeInstance.Type type = typeOption.get();
return CorrelationAttributeNormalizer.normalize(type, data); return CorrelationAttributeNormalizer.normalize(type, data);
} else { } else {
@ -114,7 +120,7 @@ final public class CorrelationAttributeNormalizer {
private static String normalizeMd5(String data) throws CorrelationAttributeNormalizationException { private static String normalizeMd5(String data) throws CorrelationAttributeNormalizationException {
final String validMd5Regex = "^[a-f0-9]{32}$"; final String validMd5Regex = "^[a-f0-9]{32}$";
final String dataLowered = data.toLowerCase(); final String dataLowered = data.toLowerCase();
if(dataLowered.matches(validMd5Regex)){ if (dataLowered.matches(validMd5Regex)) {
return dataLowered; return dataLowered;
} else { } else {
throw new CorrelationAttributeNormalizationException(String.format("Data purporting to be an MD5 was found not to comform to expected format: %s", data)); 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 { private static String normalizeDomain(String data) throws CorrelationAttributeNormalizationException {
DomainValidator validator = DomainValidator.getInstance(true); DomainValidator validator = DomainValidator.getInstance(true);
if(validator.isValid(data)){ if (validator.isValid(data)) {
return data.toLowerCase(); return data.toLowerCase();
} else { } 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])$"; 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; return data;
} else { } else {
throw new CorrelationAttributeNormalizationException(String.format("Data was expected to be a valid domain: %s", data)); 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 { private static String normalizeEmail(String data) throws CorrelationAttributeNormalizationException {
EmailValidator validator = EmailValidator.getInstance(true, true); EmailValidator validator = EmailValidator.getInstance(true, true);
if(validator.isValid(data)){ if (validator.isValid(data)) {
return data.toLowerCase(); return data.toLowerCase();
} else { } else {
throw new CorrelationAttributeNormalizationException(String.format("Data was expected to be a valid email address: %s", data)); 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. * Verify it is only numbers and '+'. Strip spaces, dashes, and parentheses.
*/ */
private static String normalizePhone(String data) throws CorrelationAttributeNormalizationException { 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\\+]", ""); String phoneNumber = data.replaceAll("[^0-9\\+]", "");
return phoneNumber; return phoneNumber;
} else { } else {
@ -169,4 +177,137 @@ final public class CorrelationAttributeNormalizer {
//TODO replace with correct usb id validation at a later date //TODO replace with correct usb id validation at a later date
return data; 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.datamodel.TskCoreException;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb;
import org.sleuthkit.autopsy.coreutils.ThreadUtils; import org.sleuthkit.autopsy.coreutils.ThreadUtils;
import org.sleuthkit.datamodel.SleuthkitCase;
/** /**
* Listen for ingest events and update entries in the Central Repository * 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) { static private void postCorrelatedBadArtifactToBlackboard(BlackboardArtifact bbArtifact, List<String> caseDisplayNames) {
try { try {
AbstractFile af = bbArtifact.getSleuthkitCase().getAbstractFileById(bbArtifact.getObjectID());
Collection<BlackboardAttribute> attributes = new ArrayList<>();
String MODULE_NAME = Bundle.IngestEventsListener_ingestmodule_name(); 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, Collection<BlackboardAttribute> attributes = new ArrayList<>();
Bundle.IngestEventsListener_prevTaggedSet_text()); attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME, MODULE_NAME,
BlackboardAttribute att2 = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT, MODULE_NAME, Bundle.IngestEventsListener_prevTaggedSet_text()));
Bundle.IngestEventsListener_prevCaseComment_text() + caseDisplayNames.stream().distinct().collect(Collectors.joining(",", "", ""))); attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT, MODULE_NAME,
attributes.add(att); Bundle.IngestEventsListener_prevCaseComment_text() + caseDisplayNames.stream().distinct().collect(Collectors.joining(",", "", ""))));
attributes.add(att2);
attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT, MODULE_NAME, bbArtifact.getArtifactID())); attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT, MODULE_NAME, bbArtifact.getArtifactID()));
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);
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
}
tifArtifact.addAttributes(attributes); // fire event to notify UI of this new artifact
try { IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent(MODULE_NAME, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT));
// 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) { } catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, "Failed to create BlackboardArtifact.", ex); // NON-NLS LOGGER.log(Level.SEVERE, "Failed to create BlackboardArtifact.", ex); // NON-NLS
} catch (IllegalStateException ex) { } catch (IllegalStateException ex) {
@ -211,26 +217,33 @@ public class IngestEventsListener {
static private void postCorrelatedPreviousArtifactToBlackboard(BlackboardArtifact bbArtifact) { static private void postCorrelatedPreviousArtifactToBlackboard(BlackboardArtifact bbArtifact) {
try { try {
AbstractFile af = bbArtifact.getSleuthkitCase().getAbstractFileById(bbArtifact.getObjectID());
Collection<BlackboardAttribute> attributes = new ArrayList<>();
String MODULE_NAME = Bundle.IngestEventsListener_ingestmodule_name(); 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, BlackboardAttribute att = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME, MODULE_NAME,
Bundle.IngestEventsListener_prevExists_text()); Bundle.IngestEventsListener_prevExists_text());
attributes.add(att); attributes.add(att);
attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT, MODULE_NAME, bbArtifact.getArtifactID())); attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT, MODULE_NAME, bbArtifact.getArtifactID()));
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);
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
}
tifArtifact.addAttributes(attributes); // fire event to notify UI of this new artifact
try { IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent(MODULE_NAME, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT));
// 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) { } catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, "Failed to create BlackboardArtifact.", ex); // NON-NLS LOGGER.log(Level.SEVERE, "Failed to create BlackboardArtifact.", ex); // NON-NLS
} catch (IllegalStateException ex) { } catch (IllegalStateException ex) {

View File

@ -18,6 +18,8 @@
*/ */
package org.sleuthkit.autopsy.centralrepository.ingestmodule; 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.CorrelationCase;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
import java.util.List; import java.util.List;
@ -51,19 +53,20 @@ import org.sleuthkit.datamodel.TskData;
import org.sleuthkit.autopsy.centralrepository.eventlisteners.IngestEventsListener; import org.sleuthkit.autopsy.centralrepository.eventlisteners.IngestEventsListener;
import org.sleuthkit.autopsy.healthmonitor.HealthMonitor; import org.sleuthkit.autopsy.healthmonitor.HealthMonitor;
import org.sleuthkit.autopsy.healthmonitor.TimingMetric; import org.sleuthkit.autopsy.healthmonitor.TimingMetric;
import org.sleuthkit.datamodel.SleuthkitCase;
/** /**
* Ingest module for inserting entries into the Central Repository database on * Ingest module for inserting entries into the Central Repository database on
* ingest of a data source * ingest of a data source
*/ */
@Messages({"IngestModule.prevTaggedSet.text=Previously Tagged As Notable (Central Repository)", @Messages({"CentralRepoIngestModule.prevTaggedSet.text=Previously Tagged As Notable (Central Repository)",
"IngestModule.prevCaseComment.text=Previous Case: "}) "CentralRepoIngestModule.prevCaseComment.text=Previous Case: "})
final class IngestModule implements FileIngestModule { final class CentralRepoIngestModule implements FileIngestModule {
static final boolean DEFAULT_FLAG_TAGGED_NOTABLE_ITEMS = true; static final boolean DEFAULT_FLAG_TAGGED_NOTABLE_ITEMS = true;
static final boolean DEFAULT_FLAG_PREVIOUS_DEVICES = 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 final IngestServices services = IngestServices.getInstance();
private static final IngestModuleReferenceCounter refCounter = new IngestModuleReferenceCounter(); private static final IngestModuleReferenceCounter refCounter = new IngestModuleReferenceCounter();
private static final IngestModuleReferenceCounter warningMsgRefCounter = 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. * @param settings The ingest settings for the module instance.
*/ */
IngestModule(IngestSettings settings) { CentralRepoIngestModule(IngestSettings settings) {
flagTaggedNotableItems = settings.isFlagTaggedNotableItems(); flagTaggedNotableItems = settings.isFlagTaggedNotableItems();
flagPreviouslySeenDevices = settings.isFlagPreviousDevices(); flagPreviouslySeenDevices = settings.isFlagPreviousDevices();
} }
@ -207,8 +210,8 @@ final class IngestModule implements FileIngestModule {
// see ArtifactManagerTimeTester for details // see ArtifactManagerTimeTester for details
@Messages({ @Messages({
"IngestModule.notfyBubble.title=Central Repository Not Initialized", "CentralRepoIngestModule.notfyBubble.title=Central Repository Not Initialized",
"IngestModule.errorMessage.isNotEnabled=Central repository settings are not initialized, cannot run Correlation Engine ingest module." "CentralRepoIngestModule.errorMessage.isNotEnabled=Central repository settings are not initialized, cannot run Correlation Engine ingest module."
}) })
@Override @Override
public void startUp(IngestJobContext context) throws IngestModuleException { public void startUp(IngestJobContext context) throws IngestModuleException {
@ -245,7 +248,7 @@ final class IngestModule implements FileIngestModule {
*/ */
if (RuntimeProperties.runningWithGUI()) { if (RuntimeProperties.runningWithGUI()) {
if (1L == warningMsgRefCounter.incrementAndGet(jobId)) { 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; 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) { private void postCorrelatedBadFileToBlackboard(AbstractFile abstractFile, List<String> caseDisplayNames) {
try { try {
String MODULE_NAME = IngestModuleFactory.getModuleName(); String MODULE_NAME = CentralRepoIngestModuleFactory.getModuleName();
BlackboardArtifact tifArtifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT);
BlackboardAttribute att = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME, MODULE_NAME, Collection<BlackboardAttribute> attributes = new ArrayList<>();
Bundle.IngestModule_prevTaggedSet_text()); attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME, MODULE_NAME,
BlackboardAttribute att2 = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT, MODULE_NAME, Bundle.CentralRepoIngestModule_prevTaggedSet_text()));
Bundle.IngestModule_prevCaseComment_text() + caseDisplayNames.stream().distinct().collect(Collectors.joining(",", "", ""))); attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT, MODULE_NAME,
tifArtifact.addAttribute(att); Bundle.CentralRepoIngestModule_prevCaseComment_text() + caseDisplayNames.stream().distinct().collect(Collectors.joining(",", "", ""))));
tifArtifact.addAttribute(att2);
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 { try {
// index the artifact for keyword search // index the artifact for keyword search
blackboard.indexArtifact(tifArtifact); blackboard.indexArtifact(tifArtifact);
} catch (Blackboard.BlackboardException ex) { } catch (Blackboard.BlackboardException ex) {
logger.log(Level.SEVERE, "Unable to index blackboard artifact " + tifArtifact.getArtifactID(), ex); //NON-NLS 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) { } catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Failed to create BlackboardArtifact.", ex); // NON-NLS logger.log(Level.SEVERE, "Failed to create BlackboardArtifact.", ex); // NON-NLS
} catch (IllegalStateException ex) { } catch (IllegalStateException ex) {
logger.log(Level.SEVERE, "Failed to create BlackboardAttribute.", ex); // NON-NLS 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 name badFile's name
* @param md5Hash badFile's md5 hash * @param md5Hash badFile's md5 hash
*/ */
@Messages({"IngestModule.postToBB.fileName=File Name", @Messages({"CentralRepoIngestModule.postToBB.fileName=File Name",
"IngestModule.postToBB.md5Hash=MD5 Hash", "CentralRepoIngestModule.postToBB.md5Hash=MD5 Hash",
"IngestModule.postToBB.hashSetSource=Source of Hash", "CentralRepoIngestModule.postToBB.hashSetSource=Source of Hash",
"IngestModule.postToBB.eamHit=Central Repository", "CentralRepoIngestModule.postToBB.eamHit=Central Repository",
"# {0} - Name of file that is Notable", "# {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) { public void sendBadFileInboxMessage(BlackboardArtifact artifact, String name, String md5Hash) {
StringBuilder detailsSb = new StringBuilder(); StringBuilder detailsSb = new StringBuilder();
//details //details
@ -372,7 +390,7 @@ final class IngestModule implements FileIngestModule {
//hit //hit
detailsSb.append("<tr>"); //NON-NLS detailsSb.append("<tr>"); //NON-NLS
detailsSb.append("<th>") //NON-NLS detailsSb.append("<th>") //NON-NLS
.append(Bundle.IngestModule_postToBB_fileName()) .append(Bundle.CentralRepoIngestModule_postToBB_fileName())
.append("</th>"); //NON-NLS .append("</th>"); //NON-NLS
detailsSb.append("<td>") //NON-NLS detailsSb.append("<td>") //NON-NLS
.append(name) .append(name)
@ -381,22 +399,22 @@ final class IngestModule implements FileIngestModule {
detailsSb.append("<tr>"); //NON-NLS detailsSb.append("<tr>"); //NON-NLS
detailsSb.append("<th>") //NON-NLS detailsSb.append("<th>") //NON-NLS
.append(Bundle.IngestModule_postToBB_md5Hash()) .append(Bundle.CentralRepoIngestModule_postToBB_md5Hash())
.append("</th>"); //NON-NLS .append("</th>"); //NON-NLS
detailsSb.append("<td>").append(md5Hash).append("</td>"); //NON-NLS detailsSb.append("<td>").append(md5Hash).append("</td>"); //NON-NLS
detailsSb.append("</tr>"); //NON-NLS detailsSb.append("</tr>"); //NON-NLS
detailsSb.append("<tr>"); //NON-NLS detailsSb.append("<tr>"); //NON-NLS
detailsSb.append("<th>") //NON-NLS detailsSb.append("<th>") //NON-NLS
.append(Bundle.IngestModule_postToBB_hashSetSource()) .append(Bundle.CentralRepoIngestModule_postToBB_hashSetSource())
.append("</th>"); //NON-NLS .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("</tr>"); //NON-NLS
detailsSb.append("</table>"); //NON-NLS detailsSb.append("</table>"); //NON-NLS
services.postMessage(IngestMessage.createDataMessage(IngestModuleFactory.getModuleName(), services.postMessage(IngestMessage.createDataMessage(CentralRepoIngestModuleFactory.getModuleName(),
Bundle.IngestModule_postToBB_knownBadMsg(name), Bundle.CentralRepoIngestModule_postToBB_knownBadMsg(name),
detailsSb.toString(), detailsSb.toString(),
name + md5Hash, name + md5Hash,
artifact)); artifact));

View File

@ -33,9 +33,9 @@ import org.sleuthkit.autopsy.ingest.NoIngestModuleIngestJobSettings;
* Factory for Central Repository ingest modules * Factory for Central Repository ingest modules
*/ */
@ServiceProvider(service = org.sleuthkit.autopsy.ingest.IngestModuleFactory.class) @ServiceProvider(service = org.sleuthkit.autopsy.ingest.IngestModuleFactory.class)
@NbBundle.Messages({"IngestModuleFactory.ingestmodule.name=Correlation Engine", @NbBundle.Messages({"CentralRepoIngestModuleFactory.ingestmodule.name=Correlation Engine",
"IngestModuleFactory.ingestmodule.desc=Saves properties to the central repository for later correlation"}) "CentralRepoIngestModuleFactory.ingestmodule.desc=Saves properties to the central repository for later correlation"})
public class IngestModuleFactory extends IngestModuleFactoryAdapter { public class CentralRepoIngestModuleFactory extends IngestModuleFactoryAdapter {
/** /**
* Get the name of the module. * Get the name of the module.
@ -43,7 +43,7 @@ public class IngestModuleFactory extends IngestModuleFactoryAdapter {
* @return The module name. * @return The module name.
*/ */
public static String getModuleName() { public static String getModuleName() {
return Bundle.IngestModuleFactory_ingestmodule_name(); return Bundle.CentralRepoIngestModuleFactory_ingestmodule_name();
} }
@Override @Override
@ -53,7 +53,7 @@ public class IngestModuleFactory extends IngestModuleFactoryAdapter {
@Override @Override
public String getModuleDescription() { public String getModuleDescription() {
return Bundle.IngestModuleFactory_ingestmodule_desc(); return Bundle.CentralRepoIngestModuleFactory_ingestmodule_desc();
} }
@Override @Override
@ -69,13 +69,13 @@ public class IngestModuleFactory extends IngestModuleFactoryAdapter {
@Override @Override
public FileIngestModule createFileIngestModule(IngestModuleIngestJobSettings settings) { public FileIngestModule createFileIngestModule(IngestModuleIngestJobSettings settings) {
if (settings instanceof IngestSettings) { if (settings instanceof IngestSettings) {
return new IngestModule((IngestSettings) settings); return new CentralRepoIngestModule((IngestSettings) settings);
} }
/* /*
* Compatibility check for older versions. * Compatibility check for older versions.
*/ */
if (settings instanceof NoIngestModuleIngestJobSettings) { 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"); 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. * Instantiate the ingest job settings with default values.
*/ */
IngestSettings() { IngestSettings() {
this.flagTaggedNotableItems = IngestModule.DEFAULT_FLAG_TAGGED_NOTABLE_ITEMS; this.flagTaggedNotableItems = CentralRepoIngestModule.DEFAULT_FLAG_TAGGED_NOTABLE_ITEMS;
this.flagPreviousDevices = IngestModule.DEFAULT_FLAG_PREVIOUS_DEVICES; this.flagPreviousDevices = CentralRepoIngestModule.DEFAULT_FLAG_PREVIOUS_DEVICES;
} }
/** /**

View File

@ -58,7 +58,7 @@
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" 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"/> <EmptySpace min="-2" pref="65" max="-2" attributes="0"/>
<Component id="searchButton" min="-2" max="-2" attributes="0"/> <Component id="searchButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
@ -77,7 +77,7 @@
<Group type="102" attributes="0"> <Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Group type="103" groupAlignment="1" max="-2" 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"> <Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="20" max="-2" attributes="0"/> <EmptySpace min="-2" pref="20" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" max="-2" attributes="0"> <Group type="103" groupAlignment="0" max="-2" attributes="0">

View File

@ -18,6 +18,8 @@
*/ */
package org.sleuthkit.autopsy.commonfilesearch; package org.sleuthkit.autopsy.commonfilesearch;
import org.sleuthkit.autopsy.guiutils.DataSourceComboBoxModel;
import org.sleuthkit.autopsy.guiutils.DataSourceLoader;
import java.awt.Dimension; import java.awt.Dimension;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList; 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.CorrelationDataSource;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException; 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.corecomponentinterfaces.DataResultViewer;
import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent; import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent;
import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable; 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 //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 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(); SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase();
List<CorrelationDataSource> correlatedDataSources = EamDb.getInstance().getDataSources(); List<CorrelationDataSource> correlatedDataSources = EamDb.getInstance().getDataSources();
List<IngestJobInfo> ingestJobs = skCase.getIngestJobs(); List<IngestJobInfo> ingestJobs = skCase.getIngestJobs();

View File

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

View File

@ -19,6 +19,7 @@
*/ */
package org.sleuthkit.autopsy.commonfilesearch; package org.sleuthkit.autopsy.commonfilesearch;
import org.sleuthkit.autopsy.guiutils.DataSourceComboBoxModel;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; 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.corecomponentinterfaces.DataContentViewer;
import org.sleuthkit.autopsy.datamodel.ContentUtils; import org.sleuthkit.autopsy.datamodel.ContentUtils;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Image;
import org.sleuthkit.datamodel.DataSource;
import org.sleuthkit.datamodel.FsContent; import org.sleuthkit.datamodel.FsContent;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM; import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM;
@ -123,11 +125,18 @@ public class Metadata extends javax.swing.JPanel implements DataContentViewer {
@Messages({ @Messages({
"Metadata.tableRowTitle.mimeType=MIME Type", "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 @Override
public void setNode(Node node) { public void setNode(Node node) {
AbstractFile file = node.getLookup().lookup(AbstractFile.class); 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")); setText(NbBundle.getMessage(this.getClass(), "Metadata.nodeText.nonFilePassedIn"));
return; return;
} }
@ -135,64 +144,100 @@ public class Metadata extends javax.swing.JPanel implements DataContentViewer {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
startTable(sb); startTable(sb);
try { if (file != null) {
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.name"), file.getUniquePath()); try {
} catch (TskCoreException ex) { addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.name"), file.getUniquePath());
addRow(sb, NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.name"), file.getParentPath() + "/" + file.getName()); } 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
} }
} 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()); setText(sb.toString());
@ -227,8 +272,9 @@ public class Metadata extends javax.swing.JPanel implements DataContentViewer {
@Override @Override
public boolean isSupported(Node node) { public boolean isSupported(Node node) {
Image image = node.getLookup().lookup(Image.class);
AbstractFile file = node.getLookup().lookup(AbstractFile.class); AbstractFile file = node.getLookup().lookup(AbstractFile.class);
return file != null; return (file != null) || (image != null);
} }
@Override @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 SHOW_ONLY_CURRENT_USER_TAGS = "ShowOnlyCurrentUserTags";
public static final String HIDE_CENTRAL_REPO_COMMENTS_AND_OCCURRENCES = "HideCentralRepoCommentsAndOccurrences"; public static final String HIDE_CENTRAL_REPO_COMMENTS_AND_OCCURRENCES = "HideCentralRepoCommentsAndOccurrences";
public static final String DISPLAY_TRANSLATED_NAMES = "DisplayTranslatedNames"; 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. // Prevent instantiation.
private UserPreferences() { private UserPreferences() {
@ -471,4 +473,20 @@ public final class UserPreferences {
public static void setLogFileCount(int count) { public static void setLogFileCount(int count) {
preferences.putInt(MAX_NUM_OF_LOG_FILE, 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="instanceCreate" methodvalue="org.sleuthkit.autopsy.modules.stix.STIXReportModule.getDefault"/>
<attr name="position" intvalue="910"/> <attr name="position" intvalue="910"/>
</file> </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"> <!--<folder name="JavaHelp">
<file name="casemodule-helpset.xml" url="casemodule-helpset.xml"> <file name="casemodule-helpset.xml" url="casemodule-helpset.xml">
<attr name="position" intvalue="3075"/> <attr name="position" intvalue="3075"/>

View File

@ -171,11 +171,13 @@ OptionsCategory_Name_View=View
OptionsCategory_Keywords_View=View OptionsCategory_Keywords_View=View
ViewPreferencesPanel.currentSessionSettingsPanel.border.title=Current Session Settings ViewPreferencesPanel.currentSessionSettingsPanel.border.title=Current Session Settings
ViewPreferencesPanel.hideRejectedResultsCheckbox.text=Hide rejected results 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.globalSettingsPanel.border.title=Global Settings
ViewPreferencesPanel.translateNamesInTableRadioButton.text=Table ViewPreferencesPanel.translateNamesInTableRadioButton.text=Table
ViewPreferencesPanel.deletedFilesLimitLabel.text=Limit number of deleted files displayed: ViewPreferencesPanel.commentsOccurencesColumnWrapAroundText.text=to reduce loading times
ViewPreferencesPanel.deletedFilesLimitCheckbox.text=Limit to 10,000 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.commentsOccurencesColumnsCheckbox.text=C(omments) and O(ccurences) columns
ViewPreferencesPanel.centralRepoLabel.text=Do not use Central Repository for: ViewPreferencesPanel.centralRepoLabel.text=Do not use Central Repository for:
ViewPreferencesPanel.hideOtherUsersTagsLabel.text=Hide other users' tags in the: 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.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.toolTipText=For example, change from Hex to Media when a JPEG is selected.
ViewPreferencesPanel.useBestViewerRadioButton.text=Change to the most specific file viewer 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.matchLabel.text=\u7d50\u679c
DataResultPanel.numberOfChildNodesLabel.text=0 DataResultPanel.numberOfChildNodesLabel.text=0
DataResultPanel.descriptionLabel.text=\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u30d1\u30b9 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.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.displayTimeLabel.text=\u6642\u9593\u3092\u8868\u793a\u3059\u308b\u5834\u5408\uff1a
ViewPreferencesPanel.viewsHideKnownCheckbox.text=\u30d3\u30e5\u30fc\u30a8\u30ea\u30a2 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.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.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.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; package org.sleuthkit.autopsy.corecomponents;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import org.openide.nodes.Children; import org.openide.nodes.Children;
import org.openide.nodes.FilterNode; import org.openide.nodes.FilterNode;
import org.openide.nodes.Node; 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 * A <code>Children</code> implementation for a
@ -31,17 +36,21 @@ import org.openide.nodes.Node;
*/ */
class TableFilterChildren extends FilterNode.Children { class TableFilterChildren extends FilterNode.Children {
private int numberOfNodesCreated;
private static volatile boolean maxResultsDialogShown = false;
/** /**
* Creates a Children object for a TableFilterNode. A TableFilterNode * Creates a Children object for a TableFilterNode. A TableFilterNode
creates at most one layer of child nodes for the node it wraps. It is * 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 * designed to be used in the results view to ensure the individual viewers
display only the first layer of child nodes. * 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 * @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) { public static Children createInstance(Node wrappedNode, boolean createChildren) {
@ -53,21 +62,21 @@ class TableFilterChildren extends FilterNode.Children {
} }
/** /**
* Constructs a children (child factory) implementation for a * Constructs a children (child factory) implementation for a
* <code>TableFilterNode</code>. A * <code>TableFilterNode</code>. A <code>TableFilterNode</code> creates at
* <code>TableFilterNode</code> creates at most one layer of * most one layer of child nodes for the node it wraps. It is designed to be
* child nodes for the node it wraps. It is designed to be used for nodes * used for nodes displayed in Autopsy table views.
* displayed in Autopsy table views.
* *
* @param wrappedNode The node wrapped by the TableFilterNode. * @param wrappedNode The node wrapped by the TableFilterNode.
*/ */
TableFilterChildren(Node wrappedNode) { TableFilterChildren(Node wrappedNode) {
super(wrappedNode); super(wrappedNode);
numberOfNodesCreated = 0;
} }
/** /**
* Copies a TableFilterNode, with the create children * Copies a TableFilterNode, with the create children (child factory) flag
(child factory) flag set to false. * set to false.
* *
* @param nodeToCopy The TableFilterNode to copy. * @param nodeToCopy The TableFilterNode to copy.
* *
@ -87,7 +96,41 @@ class TableFilterChildren extends FilterNode.Children {
* @return * @return
*/ */
@Override @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) { 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" ?> <?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> <Properties>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor"> <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[625, 465]"/> <Dimension value="[625, 465]"/>
@ -26,7 +26,7 @@
</DimensionLayout> </DimensionLayout>
<DimensionLayout dim="1"> <DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0"> <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> </Group>
</DimensionLayout> </DimensionLayout>
</Layout> </Layout>
@ -92,9 +92,13 @@
<Layout> <Layout>
<DimensionLayout dim="0"> <DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="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"/> <EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" 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"> <Group type="102" alignment="0" attributes="0">
<Component id="centralRepoLabel" min="-2" max="-2" attributes="0"/> <Component id="centralRepoLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="135" max="-2" attributes="0"/> <EmptySpace min="-2" pref="135" max="-2" attributes="0"/>
@ -149,16 +153,13 @@
</Group> </Group>
</Group> </Group>
</Group> </Group>
<Component id="deletedFilesLimitLabel" min="-2" pref="215" max="-2" attributes="0"/> <Group type="102" alignment="0" attributes="0">
<Group type="102" attributes="0"> <Component id="maximumResultsLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="10" pref="10" max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0"> <Component id="maximumResultsSpinner" min="-2" pref="70" max="-2" attributes="0"/>
<Component id="hideOtherUsersTagsCheckbox" min="-2" max="-2" attributes="0"/>
<Component id="deletedFilesLimitCheckbox" pref="567" max="32767" attributes="0"/>
</Group>
</Group> </Group>
</Group> </Group>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="32767" attributes="0"/>
</Group> </Group>
</Group> </Group>
</DimensionLayout> </DimensionLayout>
@ -189,8 +190,11 @@
<Component id="commentsOccurencesColumnsCheckbox" min="-2" pref="18" max="-2" attributes="0"/> <Component id="commentsOccurencesColumnsCheckbox" min="-2" pref="18" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Component id="commentsOccurencesColumnWrapAroundText" min="-2" max="-2" attributes="0"/> <Component id="commentsOccurencesColumnWrapAroundText" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="11" max="-2" attributes="0"/> <EmptySpace min="-2" pref="6" max="-2" attributes="0"/>
<Component id="deletedFilesLimitLabel" min="-2" 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>
<Group type="102" alignment="0" attributes="0"> <Group type="102" alignment="0" attributes="0">
<Component id="selectFileLabel" min="-2" max="-2" attributes="0"/> <Component id="selectFileLabel" min="-2" max="-2" attributes="0"/>
@ -212,9 +216,7 @@
<Component id="translateNamesInTableRadioButton" min="-2" max="-2" attributes="0"/> <Component id="translateNamesInTableRadioButton" min="-2" max="-2" attributes="0"/>
</Group> </Group>
</Group> </Group>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="32767" attributes="0"/>
<Component id="deletedFilesLimitCheckbox" min="-2" pref="26" max="-2" attributes="0"/>
<EmptySpace pref="8" max="32767" attributes="0"/>
</Group> </Group>
</Group> </Group>
</DimensionLayout> </DimensionLayout>
@ -369,20 +371,13 @@
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="commentsOccurencesColumnsCheckboxActionPerformed"/> <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="commentsOccurencesColumnsCheckboxActionPerformed"/>
</Events> </Events>
</Component> </Component>
<Component class="javax.swing.JCheckBox" name="deletedFilesLimitCheckbox"> <Component class="javax.swing.JLabel" name="maximumResultsLabel">
<Properties> <Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> <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> </Property>
</Properties> <Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<Events> <ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="ViewPreferencesPanel.maximumResultsLabel.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<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> </Property>
</Properties> </Properties>
</Component> </Component>
@ -432,6 +427,16 @@
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="translateNamesInTableRadioButtonActionPerformed"/> <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="translateNamesInTableRadioButtonActionPerformed"/>
</Events> </Events>
</Component> </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> </SubComponents>
</Container> </Container>
<Container class="javax.swing.JPanel" name="currentCaseSettingsPanel"> <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.centralrepository.datamodel.EamDbUtil;
import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.coreutils.TimeZoneUtils; import org.sleuthkit.autopsy.coreutils.TimeZoneUtils;
import org.sleuthkit.autopsy.deletedFiles.DeletedFilePreferences;
import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent; import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent;
import org.sleuthkit.autopsy.texttranslation.TextTranslationService; import org.sleuthkit.autopsy.texttranslation.TextTranslationService;
@ -79,9 +78,9 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
commentsOccurencesColumnsCheckbox.setEnabled(EamDbUtil.useCentralRepo()); commentsOccurencesColumnsCheckbox.setEnabled(EamDbUtil.useCentralRepo());
commentsOccurencesColumnWrapAroundText.setEnabled(EamDbUtil.useCentralRepo()); commentsOccurencesColumnWrapAroundText.setEnabled(EamDbUtil.useCentralRepo());
commentsOccurencesColumnsCheckbox.setSelected(UserPreferences.hideCentralRepoCommentsAndOccurrences()); commentsOccurencesColumnsCheckbox.setSelected(UserPreferences.hideCentralRepoCommentsAndOccurrences());
maximumResultsSpinner.setValue(UserPreferences.getMaximumNumberOfResults());
hideOtherUsersTagsCheckbox.setSelected(UserPreferences.showOnlyCurrentUserTags()); hideOtherUsersTagsCheckbox.setSelected(UserPreferences.showOnlyCurrentUserTags());
deletedFilesLimitCheckbox.setSelected(DeletedFilePreferences.getDefault().getShouldLimitDeletedFiles());
translateNamesInTableRadioButton.setSelected(UserPreferences.displayTranslatedFileNames()); translateNamesInTableRadioButton.setSelected(UserPreferences.displayTranslatedFileNames());
TextTranslationService tts = TextTranslationService.getInstance(); TextTranslationService tts = TextTranslationService.getInstance();
@ -116,12 +115,11 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
UserPreferences.setShowOnlyCurrentUserTags(hideOtherUsersTagsCheckbox.isSelected()); UserPreferences.setShowOnlyCurrentUserTags(hideOtherUsersTagsCheckbox.isSelected());
UserPreferences.setHideCentralRepoCommentsAndOccurrences(commentsOccurencesColumnsCheckbox.isSelected()); UserPreferences.setHideCentralRepoCommentsAndOccurrences(commentsOccurencesColumnsCheckbox.isSelected());
UserPreferences.setDisplayTranslatedFileNames(translateNamesInTableRadioButton.isSelected()); UserPreferences.setDisplayTranslatedFileNames(translateNamesInTableRadioButton.isSelected());
UserPreferences.setMaximumNumberOfResults((Integer)maximumResultsSpinner.getValue());
storeGroupItemsInTreeByDataSource(); storeGroupItemsInTreeByDataSource();
DirectoryTreeTopComponent.getDefault().setShowRejectedResults(hideRejectedResultsCheckbox.isSelected() == false); 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(); hideOtherUsersTagsLabel = new javax.swing.JLabel();
centralRepoLabel = new javax.swing.JLabel(); centralRepoLabel = new javax.swing.JLabel();
commentsOccurencesColumnsCheckbox = new javax.swing.JCheckBox(); commentsOccurencesColumnsCheckbox = new javax.swing.JCheckBox();
deletedFilesLimitCheckbox = new javax.swing.JCheckBox(); maximumResultsLabel = new javax.swing.JLabel();
deletedFilesLimitLabel = new javax.swing.JLabel();
jScrollPane1 = new javax.swing.JScrollPane(); jScrollPane1 = new javax.swing.JScrollPane();
timeZoneList = new javax.swing.JList<>(); timeZoneList = new javax.swing.JList<>();
translateTextLabel = new javax.swing.JLabel(); translateTextLabel = new javax.swing.JLabel();
commentsOccurencesColumnWrapAroundText = new javax.swing.JLabel(); commentsOccurencesColumnWrapAroundText = new javax.swing.JLabel();
translateNamesInTableRadioButton = new javax.swing.JRadioButton(); translateNamesInTableRadioButton = new javax.swing.JRadioButton();
maximumResultsSpinner = new javax.swing.JSpinner();
currentCaseSettingsPanel = new javax.swing.JPanel(); currentCaseSettingsPanel = new javax.swing.JPanel();
groupByDataSourceCheckbox = new javax.swing.JCheckBox(); groupByDataSourceCheckbox = new javax.swing.JCheckBox();
currentSessionSettingsPanel = new javax.swing.JPanel(); 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 org.openide.awt.Mnemonics.setLocalizedText(maximumResultsLabel, org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.maximumResultsLabel.text")); // NOI18N
deletedFilesLimitCheckbox.addActionListener(new java.awt.event.ActionListener() { maximumResultsLabel.setToolTipText(org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.maximumResultsLabel.toolTipText")); // NOI18N
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
timeZoneList.addListSelectionListener(new javax.swing.event.ListSelectionListener() { timeZoneList.addListSelectionListener(new javax.swing.event.ListSelectionListener() {
public void valueChanged(javax.swing.event.ListSelectionEvent evt) { 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); javax.swing.GroupLayout globalSettingsPanelLayout = new javax.swing.GroupLayout(globalSettingsPanel);
globalSettingsPanel.setLayout(globalSettingsPanelLayout); globalSettingsPanel.setLayout(globalSettingsPanelLayout);
globalSettingsPanelLayout.setHorizontalGroup( globalSettingsPanelLayout.setHorizontalGroup(
@ -306,6 +305,9 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
.addGroup(globalSettingsPanelLayout.createSequentialGroup() .addGroup(globalSettingsPanelLayout.createSequentialGroup()
.addContainerGap() .addContainerGap()
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(globalSettingsPanelLayout.createSequentialGroup()
.addGap(10, 10, 10)
.addComponent(hideOtherUsersTagsCheckbox))
.addGroup(globalSettingsPanelLayout.createSequentialGroup() .addGroup(globalSettingsPanelLayout.createSequentialGroup()
.addComponent(centralRepoLabel) .addComponent(centralRepoLabel)
.addGap(135, 135, 135) .addGap(135, 135, 135)
@ -346,13 +348,11 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
.addComponent(useLocalTimeRadioButton) .addComponent(useLocalTimeRadioButton)
.addComponent(useAnotherTimeRadioButton) .addComponent(useAnotherTimeRadioButton)
.addComponent(translateNamesInTableRadioButton))))) .addComponent(translateNamesInTableRadioButton)))))
.addComponent(deletedFilesLimitLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 215, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGroup(globalSettingsPanelLayout.createSequentialGroup() .addGroup(globalSettingsPanelLayout.createSequentialGroup()
.addGap(10, 10, 10) .addComponent(maximumResultsLabel)
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(hideOtherUsersTagsCheckbox) .addComponent(maximumResultsSpinner, javax.swing.GroupLayout.PREFERRED_SIZE, 70, javax.swing.GroupLayout.PREFERRED_SIZE)))
.addComponent(deletedFilesLimitCheckbox, javax.swing.GroupLayout.DEFAULT_SIZE, 567, Short.MAX_VALUE)))) .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addContainerGap())
); );
globalSettingsPanelLayout.setVerticalGroup( globalSettingsPanelLayout.setVerticalGroup(
globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 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) .addComponent(commentsOccurencesColumnsCheckbox, javax.swing.GroupLayout.PREFERRED_SIZE, 18, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(commentsOccurencesColumnWrapAroundText) .addComponent(commentsOccurencesColumnWrapAroundText)
.addGap(11, 11, 11) .addGap(6, 6, 6)
.addComponent(deletedFilesLimitLabel)) .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() .addGroup(globalSettingsPanelLayout.createSequentialGroup()
.addComponent(selectFileLabel) .addComponent(selectFileLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
@ -401,9 +403,7 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
.addComponent(translateTextLabel) .addComponent(translateTextLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(translateNamesInTableRadioButton))) .addComponent(translateNamesInTableRadioButton)))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addComponent(deletedFilesLimitCheckbox, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(8, Short.MAX_VALUE))
); );
currentCaseSettingsPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.currentCaseSettingsPanel.border.title"))); // NOI18N 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.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 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 }// </editor-fold>//GEN-END:initComponents
@ -525,14 +525,6 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
} }
}//GEN-LAST:event_timeZoneListValueChanged }//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 private void commentsOccurencesColumnsCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_commentsOccurencesColumnsCheckboxActionPerformed
if (immediateUpdates) { if (immediateUpdates) {
UserPreferences.setHideCentralRepoCommentsAndOccurrences(commentsOccurencesColumnsCheckbox.isSelected()); UserPreferences.setHideCentralRepoCommentsAndOccurrences(commentsOccurencesColumnsCheckbox.isSelected());
@ -623,6 +615,14 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
} }
}//GEN-LAST:event_useBestViewerRadioButtonActionPerformed }//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 // Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JLabel centralRepoLabel; private javax.swing.JLabel centralRepoLabel;
@ -632,8 +632,6 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
private javax.swing.JPanel currentSessionSettingsPanel; private javax.swing.JPanel currentSessionSettingsPanel;
private javax.swing.JCheckBox dataSourcesHideKnownCheckbox; private javax.swing.JCheckBox dataSourcesHideKnownCheckbox;
private javax.swing.JCheckBox dataSourcesHideSlackCheckbox; private javax.swing.JCheckBox dataSourcesHideSlackCheckbox;
private javax.swing.JCheckBox deletedFilesLimitCheckbox;
private javax.swing.JLabel deletedFilesLimitLabel;
private javax.swing.JLabel displayTimeLabel; private javax.swing.JLabel displayTimeLabel;
private javax.swing.JPanel globalSettingsPanel; private javax.swing.JPanel globalSettingsPanel;
private javax.swing.JCheckBox groupByDataSourceCheckbox; private javax.swing.JCheckBox groupByDataSourceCheckbox;
@ -644,6 +642,8 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
private javax.swing.JLabel hideSlackFilesLabel; private javax.swing.JLabel hideSlackFilesLabel;
private javax.swing.JScrollPane jScrollPane1; private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JRadioButton keepCurrentViewerRadioButton; private javax.swing.JRadioButton keepCurrentViewerRadioButton;
private javax.swing.JLabel maximumResultsLabel;
private javax.swing.JSpinner maximumResultsSpinner;
private javax.swing.JLabel selectFileLabel; private javax.swing.JLabel selectFileLabel;
private javax.swing.JList<String> timeZoneList; private javax.swing.JList<String> timeZoneList;
private javax.swing.JRadioButton translateNamesInTableRadioButton; private javax.swing.JRadioButton translateNamesInTableRadioButton;

View File

@ -29,8 +29,6 @@ import java.util.Observable;
import java.util.Observer; import java.util.Observer;
import java.util.Set; import java.util.Set;
import java.util.logging.Level; import java.util.logging.Level;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import org.openide.nodes.AbstractNode; import org.openide.nodes.AbstractNode;
import org.openide.nodes.ChildFactory; import org.openide.nodes.ChildFactory;
import org.openide.nodes.Children; import org.openide.nodes.Children;
@ -38,14 +36,11 @@ import org.openide.nodes.Node;
import org.openide.nodes.Sheet; import org.openide.nodes.Sheet;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.openide.util.lookup.Lookups; import org.openide.util.lookup.Lookups;
import org.openide.windows.WindowManager;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.CasePreferences; import org.sleuthkit.autopsy.casemodule.CasePreferences;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.coreutils.Logger; 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.autopsy.ingest.IngestManager;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Content;
@ -57,6 +52,7 @@ import org.sleuthkit.datamodel.LayoutFile;
import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskData;
import org.sleuthkit.datamodel.VirtualDirectory;
/** /**
* deleted content view nodes * deleted content view nodes
@ -404,25 +400,8 @@ public class DeletedContent implements AutopsyVisitableItem {
} }
@Override @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) { protected boolean createKeys(List<AbstractFile> list) {
DeletedFilePreferences deletedPreferences = DeletedFilePreferences.getDefault(); list.addAll(runFsQuery());
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);
return true; return true;
} }
@ -467,9 +446,8 @@ public class DeletedContent implements AutopsyVisitableItem {
if (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)) { if (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)) {
query += " AND data_source_obj_id = " + filteringDSObjId; query += " AND data_source_obj_id = " + filteringDSObjId;
} }
DeletedFilePreferences deletedPreferences = DeletedFilePreferences.getDefault(); if (UserPreferences.getMaximumNumberOfResults() != 0) {
if (deletedPreferences.getShouldLimitDeletedFiles()) { query += " LIMIT " + UserPreferences.getMaximumNumberOfResults(); //NON-NLS
query += " LIMIT " + deletedPreferences.getDeletedFilesLimit(); //NON-NLS
} }
return query; return query;
} }
@ -531,6 +509,11 @@ public class DeletedContent implements AutopsyVisitableItem {
return new FileNode(f, false); return new FileNode(f, false);
} }
@Override
public FileNode visit(VirtualDirectory f) {
return new FileNode(f, false);
}
@Override @Override
protected AbstractNode defaultVisit(Content di) { protected AbstractNode defaultVisit(Content di) {
throw new UnsupportedOperationException("Not supported for this type of Displayable Item: " + di.toString()); 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 return filePath + "face.png"; //NON-NLS
} else if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_WIFI_NETWORK.getTypeID()) { } else if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_WIFI_NETWORK.getTypeID()) {
return filePath + "network-wifi.png"; //NON-NLS 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 return filePath + "artifact-icon.png"; //NON-NLS
} }

View File

@ -124,10 +124,7 @@ public class ImageNode extends AbstractContentNode<Image> {
"ImageNode.createSheet.type.text=Image", "ImageNode.createSheet.type.text=Image",
"ImageNode.createSheet.sectorSize.name=Sector Size (Bytes)", "ImageNode.createSheet.sectorSize.name=Sector Size (Bytes)",
"ImageNode.createSheet.sectorSize.displayName=Sector Size (Bytes)", "ImageNode.createSheet.sectorSize.displayName=Sector Size (Bytes)",
"ImageNode.createSheet.sectorSize.desc=Sector size of the image in 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.name=Timezone",
"ImageNode.createSheet.timezone.displayName=Timezone", "ImageNode.createSheet.timezone.displayName=Timezone",
"ImageNode.createSheet.timezone.desc=Timezone of the image", "ImageNode.createSheet.timezone.desc=Timezone of the image",
@ -161,11 +158,6 @@ public class ImageNode extends AbstractContentNode<Image> {
Bundle.ImageNode_createSheet_sectorSize_desc(), Bundle.ImageNode_createSheet_sectorSize_desc(),
this.content.getSsize())); 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(), sheetSet.put(new NodeProperty<>(Bundle.ImageNode_createSheet_timezone_name(),
Bundle.ImageNode_createSheet_timezone_displayName(), Bundle.ImageNode_createSheet_timezone_displayName(),
Bundle.ImageNode_createSheet_timezone_desc(), Bundle.ImageNode_createSheet_timezone_desc(),

View File

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

View File

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

View File

@ -17,7 +17,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.sleuthkit.autopsy.commonfilesearch; package org.sleuthkit.autopsy.guiutils;
import java.io.File; import java.io.File;
import java.sql.ResultSet; 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; break;
case "EWF Verify": //NON-NLS case "EWF Verify": //NON-NLS
case "E01 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; break;
case "Archive Extractor": //NON-NLS case "Archive Extractor": //NON-NLS
moduleNames.add("Embedded File 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.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.examples.SampleIngestModuleFactory; 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.exif.ExifParserModuleFactory;
import org.sleuthkit.autopsy.modules.fileextmismatch.FileExtMismatchDetectorModuleFactory; import org.sleuthkit.autopsy.modules.fileextmismatch.FileExtMismatchDetectorModuleFactory;
import org.sleuthkit.autopsy.modules.filetypeid.FileTypeIdModuleFactory; 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.photoreccarver.PhotoRecCarverIngestModuleFactory;
import org.sleuthkit.autopsy.modules.embeddedfileextractor.EmbeddedFileExtractorModuleFactory; import org.sleuthkit.autopsy.modules.embeddedfileextractor.EmbeddedFileExtractorModuleFactory;
import org.sleuthkit.autopsy.modules.encryptiondetection.EncryptionDetectionModuleFactory; 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; import org.sleuthkit.autopsy.python.JythonModuleLoader;
/** /**
@ -55,15 +57,17 @@ final class IngestModuleFactoryLoader {
add("org.sleuthkit.autopsy.recentactivity.RecentActivityExtracterModuleFactory"); //NON-NLS add("org.sleuthkit.autopsy.recentactivity.RecentActivityExtracterModuleFactory"); //NON-NLS
add(HashLookupModuleFactory.class.getCanonicalName()); add(HashLookupModuleFactory.class.getCanonicalName());
add(FileTypeIdModuleFactory.class.getCanonicalName()); add(FileTypeIdModuleFactory.class.getCanonicalName());
add(FileExtMismatchDetectorModuleFactory.class.getCanonicalName());
add(EmbeddedFileExtractorModuleFactory.class.getCanonicalName()); add(EmbeddedFileExtractorModuleFactory.class.getCanonicalName());
add(ExifParserModuleFactory.class.getCanonicalName()); add(ExifParserModuleFactory.class.getCanonicalName());
add("org.sleuthkit.autopsy.keywordsearch.KeywordSearchModuleFactory"); //NON-NLS add("org.sleuthkit.autopsy.keywordsearch.KeywordSearchModuleFactory"); //NON-NLS
add("org.sleuthkit.autopsy.thunderbirdparser.EmailParserModuleFactory"); //NON-NLS add("org.sleuthkit.autopsy.thunderbirdparser.EmailParserModuleFactory"); //NON-NLS
add(FileExtMismatchDetectorModuleFactory.class.getCanonicalName());
add(E01VerifierModuleFactory.class.getCanonicalName());
add(EncryptionDetectionModuleFactory.class.getCanonicalName()); add(EncryptionDetectionModuleFactory.class.getCanonicalName());
add(InterestingItemsIngestModuleFactory.class.getCanonicalName()); add(InterestingItemsIngestModuleFactory.class.getCanonicalName());
add(CentralRepoIngestModuleFactory.class.getCanonicalName());
add(PhotoRecCarverIngestModuleFactory.class.getCanonicalName()); add(PhotoRecCarverIngestModuleFactory.class.getCanonicalName());
add(VMExtractorIngestModuleFactory.class.getCanonicalName());
add(DataSourceIntegrityModuleFactory.class.getCanonicalName());
} }
}; };
@ -75,7 +79,7 @@ final class IngestModuleFactoryLoader {
* removed between invocations. * removed between invocations.
* *
* @return A list of objects that implement the IngestModuleFactory * @return A list of objects that implement the IngestModuleFactory
* interface. * interface.
*/ */
static List<IngestModuleFactory> getIngestModuleFactories() { static List<IngestModuleFactory> getIngestModuleFactories() {
// A hash set of display names and a hash map of class names to // 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>
<PIPELINE type="ImageAnalysisStageTwo"> <PIPELINE type="ImageAnalysisStageTwo">
<MODULE>org.sleuthkit.autopsy.modules.e01verify.E01VerifierModuleFactory</MODULE> <MODULE>org.sleuthkit.autopsy.modules.dataSourceIntegrity.DataSourceIntegrityModuleFactory</MODULE>
</PIPELINE> </PIPELINE>
</PIPELINE_CONFIG> </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.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
@ -66,6 +67,7 @@ import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.DerivedFile; import org.sleuthkit.datamodel.DerivedFile;
import org.sleuthkit.datamodel.EncodedFileOutputStream; import org.sleuthkit.datamodel.EncodedFileOutputStream;
import org.sleuthkit.datamodel.ReadContentInputStream; import org.sleuthkit.datamodel.ReadContentInputStream;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskData;
@ -242,28 +244,41 @@ class SevenZipExtractor {
String msg = NbBundle.getMessage(SevenZipExtractor.class, String msg = NbBundle.getMessage(SevenZipExtractor.class,
"EmbeddedFileExtractorIngestModule.ArchiveExtractor.isZipBombCheck.warnMsg", archiveFile.getName(), escapedFilePath); "EmbeddedFileExtractorIngestModule.ArchiveExtractor.isZipBombCheck.warnMsg", archiveFile.getName(), escapedFilePath);
try { try {
BlackboardArtifact artifact = rootArchive.getArchiveFile().newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT); Collection<BlackboardAttribute> attributes = new ArrayList<>();
artifact.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME, EmbeddedFileExtractorModuleFactory.getModuleName(), attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME, EmbeddedFileExtractorModuleFactory.getModuleName(),
"Possible Zip Bomb")); "Possible Zip Bomb"));
artifact.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DESCRIPTION, attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DESCRIPTION,
EmbeddedFileExtractorModuleFactory.getModuleName(), EmbeddedFileExtractorModuleFactory.getModuleName(),
Bundle.SevenZipExtractor_zipBombArtifactCreation_text(archiveFile.getName()))); 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(), EmbeddedFileExtractorModuleFactory.getModuleName(),
details)); details));
try {
// index the artifact for keyword search SleuthkitCase tskCase = Case.getCurrentCaseThrows().getSleuthkitCase();
blackboard.indexArtifact(artifact); org.sleuthkit.datamodel.Blackboard tskBlackboard = tskCase.getBlackboard();
} catch (Blackboard.BlackboardException ex) { // Create artifact if it doesn't already exist.
logger.log(Level.SEVERE, "Unable to index blackboard artifact " + artifact.getArtifactID(), ex); //NON-NLS if (!tskBlackboard.artifactExists(archiveFile, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT, attributes)) {
MessageNotifyUtil.Notify.error( BlackboardArtifact artifact = archiveFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT);
Bundle.SevenZipExtractor_indexError_message(), artifact.getDisplayName()); 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) { } catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Error creating blackboard artifact for Zip Bomb Detection for file: " + escapedFilePath, ex); //NON-NLS 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.TimeZone;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level; import java.util.logging.Level;
import org.apache.commons.lang3.StringUtils;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.openide.util.NbBundle.Messages; import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.casemodule.Case; 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 static final Logger logger = Logger.getLogger(ExifParserFileIngestModule.class.getName());
private final IngestServices services = IngestServices.getInstance(); private final IngestServices services = IngestServices.getInstance();
private final AtomicInteger filesProcessed = new AtomicInteger(0); private final AtomicInteger filesProcessed = new AtomicInteger(0);
private final List<BlackboardArtifact> listOfFacesDetectedArtifacts = new ArrayList<>();
private long jobId; private long jobId;
private static final IngestModuleReferenceCounter refCounter = new IngestModuleReferenceCounter(); private static final IngestModuleReferenceCounter refCounter = new IngestModuleReferenceCounter();
private FileTypeDetector fileTypeDetector; private FileTypeDetector fileTypeDetector;
@ -190,12 +190,12 @@ public final class ExifParserFileIngestModule implements FileIngestModule {
ExifIFD0Directory devDir = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class); ExifIFD0Directory devDir = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class);
if (devDir != null) { if (devDir != null) {
String model = devDir.getString(ExifIFD0Directory.TAG_MODEL); 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)); attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DEVICE_MODEL, ExifParserModuleFactory.getModuleName(), model));
} }
String make = devDir.getString(ExifIFD0Directory.TAG_MAKE); 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)); 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) { private void createInterestingFileHit(AbstractFile file, FileType fileType) {
try { try {
BlackboardArtifact artifact;
artifact = file.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT);
Collection<BlackboardAttribute> attributes = new ArrayList<>(); Collection<BlackboardAttribute> attributes = new ArrayList<>();
BlackboardAttribute setNameAttribute = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME, FileTypeIdModuleFactory.getModuleName(), fileType.getInterestingFilesSetName()); attributes.add(new BlackboardAttribute(
attributes.add(setNameAttribute); BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME, FileTypeIdModuleFactory.getModuleName(), fileType.getInterestingFilesSetName()));
BlackboardAttribute ruleNameAttribute = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CATEGORY, FileTypeIdModuleFactory.getModuleName(), fileType.getMimeType()); attributes.add(new BlackboardAttribute(
attributes.add(ruleNameAttribute); BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CATEGORY, FileTypeIdModuleFactory.getModuleName(), fileType.getMimeType()));
artifact.addAttributes(attributes);
try { Case currentCase = Case.getCurrentCaseThrows();
Case.getCurrentCaseThrows().getServices().getBlackboard().indexArtifact(artifact); org.sleuthkit.datamodel.Blackboard tskBlackboard = currentCase.getSleuthkitCase().getBlackboard();
} catch (Blackboard.BlackboardException ex) { // Create artifact if it doesn't already exist.
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 if (!tskBlackboard.artifactExists(file, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT, attributes)) {
} catch (NoCurrentCaseException ex) { BlackboardArtifact artifact = file.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT);
logger.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS 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) { } 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 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 @Override
@Messages({"FilesIdentifierIngestModule.indexError.message=Failed to index interesting file hit artifact for keyword search."}) @Messages({"FilesIdentifierIngestModule.indexError.message=Failed to index interesting file hit artifact for keyword search."})
public ProcessResult process(AbstractFile file) { public ProcessResult process(AbstractFile file) {
Case currentCase;
try { try {
blackboard = Case.getCurrentCaseThrows().getServices().getBlackboard(); currentCase = Case.getCurrentCaseThrows();
} catch (NoCurrentCaseException ex) { } catch (NoCurrentCaseException ex) {
logger.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS logger.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS
return ProcessResult.ERROR; return ProcessResult.ERROR;
} }
blackboard = currentCase.getServices().getBlackboard();
// Skip slack space files. // Skip slack space files.
if (file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.SLACK)) { if (file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.SLACK)) {
return ProcessResult.OK; return ProcessResult.OK;
@ -126,7 +129,7 @@ final class FilesIdentifierIngestModule implements FileIngestModule {
// Post an interesting files set hit artifact to the // Post an interesting files set hit artifact to the
// blackboard. // blackboard.
String moduleName = InterestingItemsIngestModuleFactory.getModuleName(); String moduleName = InterestingItemsIngestModuleFactory.getModuleName();
BlackboardArtifact artifact = file.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT);
Collection<BlackboardAttribute> attributes = new ArrayList<>(); Collection<BlackboardAttribute> attributes = new ArrayList<>();
// Add a set name attribute to the artifact. This adds a // Add a set name attribute to the artifact. This adds a
@ -141,29 +144,34 @@ final class FilesIdentifierIngestModule implements FileIngestModule {
// interesting files set membership rule that was satisfied. // interesting files set membership rule that was satisfied.
BlackboardAttribute ruleNameAttribute = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CATEGORY, moduleName, ruleSatisfied); BlackboardAttribute ruleNameAttribute = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CATEGORY, moduleName, ruleSatisfied);
attributes.add(ruleNameAttribute); attributes.add(ruleNameAttribute);
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());
}
artifact.addAttributes(attributes); services.fireModuleDataEvent(new ModuleDataEvent(moduleName, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT, Collections.singletonList(artifact)));
try {
// index the artifact for keyword search // make an ingest inbox message
blackboard.indexArtifact(artifact); StringBuilder detailsSb = new StringBuilder();
} catch (Blackboard.BlackboardException ex) { detailsSb.append("File: " + file.getParentPath() + file.getName() + "<br/>\n");
logger.log(Level.SEVERE, "Unable to index blackboard artifact " + artifact.getArtifactID(), ex); //NON-NLS detailsSb.append("Rule Set: " + filesSet.getName());
MessageNotifyUtil.Notify.error(Bundle.FilesIdentifierIngestModule_indexError_message(), artifact.getDisplayName());
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) { } catch (TskCoreException ex) {
FilesIdentifierIngestModule.logger.log(Level.SEVERE, "Error posting to the blackboard", ex); //NOI18N NON-NLS 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 // If there is a leading ".", strip it since
// AbstractFile.getFileNameExtension() returns just the // AbstractFile.getFileNameExtension() returns just the
// extension chars and not the dot. // 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. * @param extensions The file name extensions to be matched.
*/ */
public ExtensionCondition(List<String> extensions) { 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 // AbstractFile.getFileNameExtension() returns just the
// extension chars and not the dot. // extension chars and not the dot.
super(extensions); super(normalize(extensions));
} }
/** /**
@ -862,6 +862,34 @@ public final class FilesSet implements Serializable {
public boolean passes(AbstractFile file) { public boolean passes(AbstractFile file) {
return this.textMatches(file.getNameExtension()); 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. * match.
*/ */
CaseInsensitiveMultiValueStringComparisionMatcher(List<String> valuesToMatch) { CaseInsensitiveMultiValueStringComparisionMatcher(List<String> valuesToMatch) {
List<String> values = new ArrayList<>(valuesToMatch); this.valuesToMatch = 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;
} }
@Override @Override

View File

@ -485,7 +485,12 @@ final class FilesSetRulePanel extends javax.swing.JPanel {
if (this.fullNameRadioButton.isSelected()) { if (this.fullNameRadioButton.isSelected()) {
condition = new FilesSet.Rule.FullNameCondition(this.nameTextField.getText()); condition = new FilesSet.Rule.FullNameCondition(this.nameTextField.getText());
} else { } 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 { } else {
logger.log(Level.SEVERE, "Attempt to get name condition with illegal chars"); // NON-NLS logger.log(Level.SEVERE, "Attempt to get name condition with illegal chars"); // NON-NLS

View File

@ -64,15 +64,15 @@ class StixArtifactData {
@Messages({"StixArtifactData.indexError.message=Failed to index STIX interesting file hit artifact for keyword search.", @Messages({"StixArtifactData.indexError.message=Failed to index STIX interesting file hit artifact for keyword search.",
"StixArtifactData.noOpenCase.errMsg=No open case available."}) "StixArtifactData.noOpenCase.errMsg=No open case available."})
public void createArtifact(String a_title) throws TskCoreException { public void createArtifact(String a_title) throws TskCoreException {
Blackboard blackboard; Case currentCase;
try { try {
blackboard = Case.getCurrentCaseThrows().getServices().getBlackboard(); currentCase = Case.getCurrentCaseThrows();
} catch (NoCurrentCaseException ex) { } catch (NoCurrentCaseException ex) {
logger.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS logger.log(Level.SEVERE, "Exception while getting open case.", ex); //NON-NLS
MessageNotifyUtil.Notify.error(Bundle.StixArtifactData_noOpenCase_errMsg(), ex.getLocalizedMessage()); MessageNotifyUtil.Notify.error(Bundle.StixArtifactData_noOpenCase_errMsg(), ex.getLocalizedMessage());
return; return;
} }
String setName; String setName;
if (a_title != null) { if (a_title != null) {
setName = "STIX Indicator - " + a_title; //NON-NLS setName = "STIX Indicator - " + a_title; //NON-NLS
@ -80,19 +80,25 @@ class StixArtifactData {
setName = "STIX Indicator - (no title)"; //NON-NLS setName = "STIX Indicator - (no title)"; //NON-NLS
} }
BlackboardArtifact bba = file.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT);
Collection<BlackboardAttribute> attributes = new ArrayList<>(); 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_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_TITLE, "Stix", observableId)); //NON-NLS
attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CATEGORY, "Stix", objType)); //NON-NLS attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CATEGORY, "Stix", objType)); //NON-NLS
bba.addAttributes(attributes); org.sleuthkit.datamodel.Blackboard tskBlackboard = currentCase.getSleuthkitCase().getBlackboard();
try { // Create artifact if it doesn't already exist.
// index the artifact for keyword search if (!tskBlackboard.artifactExists(file, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT, attributes)) {
blackboard.indexArtifact(bba); BlackboardArtifact bba = file.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT);
} catch (Blackboard.BlackboardException ex) { bba.addAttributes(attributes);
logger.log(Level.SEVERE, "Unable to index blackboard artifact " + bba.getArtifactID(), ex); //NON-NLS
MessageNotifyUtil.Notify.error(Bundle.StixArtifactData_indexError_message(), bba.getDisplayName()); 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;)"/> <ResourceString bundle="org/sleuthkit/autopsy/othercasessearch/Bundle.properties" key="OtherCasesSearchDialog.correlationValueTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property> </Property>
</Properties> </Properties>
<Events>
<EventHandler event="keyReleased" listener="java.awt.event.KeyListener" parameters="java.awt.event.KeyEvent" handler="valueFieldKeyReleaseListener"/>
</Events>
</Component> </Component>
<Component class="javax.swing.JButton" name="searchButton"> <Component class="javax.swing.JButton" name="searchButton">
<Properties> <Properties>
@ -116,6 +119,9 @@
<StringArray count="0"/> <StringArray count="0"/>
</Property> </Property>
</Properties> </Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="correlationTypeComboBoxActionPerformed"/>
</Events>
<AuxValues> <AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;String&gt;"/> <AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;String&gt;"/>
</AuxValues> </AuxValues>

View File

@ -56,19 +56,25 @@ import org.sleuthkit.autopsy.datamodel.EmptyNode;
"OtherCasesSearchDialog.validation.invalidEmail=The supplied value is not a valid e-mail address.", "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.invalidDomain=The supplied value is not a valid domain.",
"OtherCasesSearchDialog.validation.invalidPhone=The supplied value is not a valid phone number.", "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.", "OtherCasesSearchDialog.validation.genericMessage=The supplied value is not valid.",
"# {0} - number of cases", "# {0} - number of cases",
"OtherCasesSearchDialog.caseLabel.text=The current Central Repository contains {0} case(s)." "OtherCasesSearchDialog.caseLabel.text=The current Central Repository contains {0} case(s)."
}) })
/** /**
* The Search Other Cases dialog allows users to search for specific * The Search Other Cases dialog allows users to search for specific types of
* types of correlation properties in the Central Repository. * correlation properties in the Central Repository.
*/ */
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives @SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
final class OtherCasesSearchDialog extends javax.swing.JDialog { final class OtherCasesSearchDialog extends javax.swing.JDialog {
private static final Logger logger = Logger.getLogger(OtherCasesSearchDialog.class.getName()); private static final Logger logger = Logger.getLogger(OtherCasesSearchDialog.class.getName());
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private final List<CorrelationAttributeInstance.Type> correlationTypes; private final List<CorrelationAttributeInstance.Type> correlationTypes;
private CorrelationAttributeInstance.Type selectedCorrelationType; private CorrelationAttributeInstance.Type selectedCorrelationType;
private TextPrompt correlationValueTextFieldPrompt; private TextPrompt correlationValueTextFieldPrompt;
@ -82,20 +88,20 @@ final class OtherCasesSearchDialog extends javax.swing.JDialog {
initComponents(); initComponents();
customizeComponents(); customizeComponents();
} }
/** /**
* Perform the other cases search. * Perform the other cases search.
* *
* @param type The correlation type. * @param type The correlation type.
* @param value The value to be matched. * @param value The value to be matched.
*/ */
private void search(CorrelationAttributeInstance.Type type, String value) { private void search(CorrelationAttributeInstance.Type type, String value) {
new SwingWorker<List<CorrelationAttributeInstance>, Void>() { new SwingWorker<List<CorrelationAttributeInstance>, Void>() {
@Override @Override
protected List<CorrelationAttributeInstance> doInBackground() { protected List<CorrelationAttributeInstance> doInBackground() {
List<CorrelationAttributeInstance> correlationInstances = new ArrayList<>(); List<CorrelationAttributeInstance> correlationInstances = new ArrayList<>();
try { try {
correlationInstances = EamDb.getInstance().getArtifactInstancesByTypeValue(type, value); correlationInstances = EamDb.getInstance().getArtifactInstancesByTypeValue(type, value);
} catch (EamDbException ex) { } catch (EamDbException ex) {
@ -115,10 +121,10 @@ final class OtherCasesSearchDialog extends javax.swing.JDialog {
DataResultViewerTable table = new DataResultViewerTable(); DataResultViewerTable table = new DataResultViewerTable();
Collection<DataResultViewer> viewers = new ArrayList<>(1); Collection<DataResultViewer> viewers = new ArrayList<>(1);
viewers.add(table); viewers.add(table);
OtherCasesSearchNode searchNode = new OtherCasesSearchNode(correlationInstances); OtherCasesSearchNode searchNode = new OtherCasesSearchNode(correlationInstances);
TableFilterNode tableFilterNode = new TableFilterNode(searchNode, true, searchNode.getName()); TableFilterNode tableFilterNode = new TableFilterNode(searchNode, true, searchNode.getName());
String resultsText = String.format("%s (%s; \"%s\")", String resultsText = String.format("%s (%s; \"%s\")",
Bundle.OtherCasesSearchDialog_resultsTitle_text(), type.getDisplayName(), value); Bundle.OtherCasesSearchDialog_resultsTitle_text(), type.getDisplayName(), value);
final TopComponent searchResultWin; final TopComponent searchResultWin;
@ -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 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.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 org.openide.awt.Mnemonics.setLocalizedText(searchButton, org.openide.util.NbBundle.getMessage(OtherCasesSearchDialog.class, "OtherCasesSearchDialog.searchButton.text")); // NOI18N
searchButton.addActionListener(new java.awt.event.ActionListener() { 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 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)); errorLabel.setForeground(new java.awt.Color(255, 0, 0));
@ -235,7 +252,7 @@ final class OtherCasesSearchDialog extends javax.swing.JDialog {
private void searchButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_searchButtonActionPerformed private void searchButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_searchButtonActionPerformed
CorrelationAttributeInstance.Type correlationType = selectedCorrelationType; CorrelationAttributeInstance.Type correlationType = selectedCorrelationType;
String correlationValue = correlationValueTextField.getText().trim(); String correlationValue = correlationValueTextField.getText().trim();
if (validateInputs(correlationType, correlationValue)) { if (validateInputs(correlationType, correlationValue)) {
search(correlationType, correlationValue); search(correlationType, correlationValue);
dispose(); dispose();
@ -254,23 +271,48 @@ final class OtherCasesSearchDialog extends javax.swing.JDialog {
case CorrelationAttributeInstance.PHONE_TYPE_ID: case CorrelationAttributeInstance.PHONE_TYPE_ID:
validationMessage = Bundle.OtherCasesSearchDialog_validation_invalidPhone(); validationMessage = Bundle.OtherCasesSearchDialog_validation_invalidPhone();
break; 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: default:
validationMessage = Bundle.OtherCasesSearchDialog_validation_genericMessage(); validationMessage = Bundle.OtherCasesSearchDialog_validation_genericMessage();
break; break;
} }
errorLabel.setText(validationMessage); errorLabel.setText(validationMessage);
searchButton.setEnabled(false); searchButton.setEnabled(false);
correlationValueTextField.grabFocus(); correlationValueTextField.grabFocus();
} }
}//GEN-LAST:event_searchButtonActionPerformed }//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. * Validate the supplied input.
* *
* @param type The correlation type. * @param type The correlation type.
* @param value The value to be validated. * @param value The value to be validated.
* *
* @return True if the input is valid for the given type; otherwise false. * @return True if the input is valid for the given type; otherwise false.
*/ */
private boolean validateInputs(CorrelationAttributeInstance.Type type, String value) { private boolean validateInputs(CorrelationAttributeInstance.Type type, String value) {
@ -280,16 +322,16 @@ final class OtherCasesSearchDialog extends javax.swing.JDialog {
// No need to log this. // No need to log this.
return false; return false;
} }
return true; return true;
} }
/** /**
* Further customize the components beyond the standard initialization. * Further customize the components beyond the standard initialization.
*/ */
private void customizeComponents() { private void customizeComponents() {
searchButton.setEnabled(false); searchButton.setEnabled(false);
/* /*
* Add correlation types to the combo-box. * Add correlation types to the combo-box.
*/ */
@ -307,7 +349,7 @@ final class OtherCasesSearchDialog extends javax.swing.JDialog {
correlationTypeComboBox.addItem(type.getDisplayName()); correlationTypeComboBox.addItem(type.getDisplayName());
} }
correlationTypeComboBox.setSelectedIndex(0); correlationTypeComboBox.setSelectedIndex(0);
correlationTypeComboBox.addItemListener(new ItemListener() { correlationTypeComboBox.addItemListener(new ItemListener() {
@Override @Override
public void itemStateChanged(ItemEvent e) { public void itemStateChanged(ItemEvent e) {
@ -316,9 +358,9 @@ final class OtherCasesSearchDialog extends javax.swing.JDialog {
updateSearchButton(); updateSearchButton();
} }
}); });
updateSelectedType(); updateSelectedType();
/* /*
* Create listener for text input. * Create listener for text input.
*/ */
@ -338,17 +380,21 @@ final class OtherCasesSearchDialog extends javax.swing.JDialog {
updateSearchButton(); updateSearchButton();
} }
}); });
updateCorrelationValueTextFieldPrompt(); updateCorrelationValueTextFieldPrompt();
} }
@Messages({ @Messages({
"OtherCasesSearchDialog.correlationValueTextField.filesExample=Example: \"f0e1d2c3b4a5968778695a4b3c2d1e0f\"", "OtherCasesSearchDialog.correlationValueTextField.filesExample=Example: \"f0e1d2c3b4a5968778695a4b3c2d1e0f\"",
"OtherCasesSearchDialog.correlationValueTextField.domainExample=Example: \"domain.com\"", "OtherCasesSearchDialog.correlationValueTextField.domainExample=Example: \"domain.com\"",
"OtherCasesSearchDialog.correlationValueTextField.emailExample=Example: \"user@host.com\"", "OtherCasesSearchDialog.correlationValueTextField.emailExample=Example: \"user@host.com\"",
"OtherCasesSearchDialog.correlationValueTextField.phoneExample=Example: \"(800)123-4567\"", "OtherCasesSearchDialog.correlationValueTextField.phoneExample=Example: \"(800)123-4567\"",
"OtherCasesSearchDialog.correlationValueTextField.usbExample=Example: \"4&1234567&0\"", "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 * 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. * Add text prompt to the text field.
*/ */
String text; String text;
switch(selectedCorrelationType.getId()) { switch (selectedCorrelationType.getId()) {
case CorrelationAttributeInstance.FILES_TYPE_ID: case CorrelationAttributeInstance.FILES_TYPE_ID:
text = Bundle.OtherCasesSearchDialog_correlationValueTextField_filesExample(); text = Bundle.OtherCasesSearchDialog_correlationValueTextField_filesExample();
break; break;
@ -378,22 +424,34 @@ final class OtherCasesSearchDialog extends javax.swing.JDialog {
case CorrelationAttributeInstance.SSID_TYPE_ID: case CorrelationAttributeInstance.SSID_TYPE_ID:
text = Bundle.OtherCasesSearchDialog_correlationValueTextField_ssidExample(); text = Bundle.OtherCasesSearchDialog_correlationValueTextField_ssidExample();
break; 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: default:
text = ""; text = "";
break; break;
} }
correlationValueTextFieldPrompt = new TextPrompt(text, correlationValueTextField); correlationValueTextFieldPrompt = new TextPrompt(text, correlationValueTextField);
/** /**
* Sets the foreground color and transparency of the text prompt. * Sets the foreground color and transparency of the text prompt.
*/ */
correlationValueTextFieldPrompt.setForeground(Color.LIGHT_GRAY); correlationValueTextFieldPrompt.setForeground(Color.LIGHT_GRAY);
correlationValueTextFieldPrompt.changeAlpha(0.9f); // Mostly opaque correlationValueTextFieldPrompt.changeAlpha(0.9f); // Mostly opaque
validate(); validate();
repaint(); repaint();
} }
/** /**
* Update the 'selectedCorrelationType' value to match the selected type * Update the 'selectedCorrelationType' value to match the selected type
* from the combo-box. * from the combo-box.
@ -406,7 +464,7 @@ final class OtherCasesSearchDialog extends javax.swing.JDialog {
} }
} }
} }
/** /**
* Enable or disable the Search button depending on whether or not text has * Enable or disable the Search button depending on whether or not text has
* been provided for the correlation property value. * been provided for the correlation property value.
@ -433,4 +491,4 @@ final class OtherCasesSearchDialog extends javax.swing.JDialog {
private javax.swing.JLabel errorLabel; private javax.swing.JLabel errorLabel;
private javax.swing.JButton searchButton; private javax.swing.JButton searchButton;
// End of variables declaration//GEN-END:variables // End of variables declaration//GEN-END:variables
} }

View File

@ -285,7 +285,19 @@ class ReportHTML implements TableReportModule {
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/accounts.png"); //NON-NLS in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/accounts.png"); //NON-NLS
break; break;
case TSK_WIFI_NETWORK: 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; break;
default: default:
logger.log(Level.WARNING, "useDataTypeIcon: unhandled artifact type = {0}", dataType); //NON-NLS 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.CentralRepoCommonAttributeInstance;
import org.sleuthkit.autopsy.commonfilesearch.CentralRepoCommonAttributeInstanceNode; import org.sleuthkit.autopsy.commonfilesearch.CentralRepoCommonAttributeInstanceNode;
import org.sleuthkit.autopsy.commonfilesearch.CommonAttributeSearchResults; 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.CommonAttributeValue;
import org.sleuthkit.autopsy.commonfilesearch.CommonAttributeValueList; import org.sleuthkit.autopsy.commonfilesearch.CommonAttributeValueList;
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode; 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.embeddedfileextractor.EmbeddedFileExtractorModuleFactory;
import org.sleuthkit.autopsy.modules.exif.ExifParserModuleFactory; import org.sleuthkit.autopsy.modules.exif.ExifParserModuleFactory;
import org.sleuthkit.autopsy.modules.fileextmismatch.FileExtMismatchDetectorModuleFactory; import org.sleuthkit.autopsy.modules.fileextmismatch.FileExtMismatchDetectorModuleFactory;
@ -183,8 +183,8 @@ class InterCaseTestUtils {
final IngestModuleTemplate hashLookupTemplate = IngestUtils.getIngestModuleTemplate(new HashLookupModuleFactory()); final IngestModuleTemplate hashLookupTemplate = IngestUtils.getIngestModuleTemplate(new HashLookupModuleFactory());
final IngestModuleTemplate vmExtractorTemplate = IngestUtils.getIngestModuleTemplate(new VMExtractorIngestModuleFactory()); final IngestModuleTemplate vmExtractorTemplate = IngestUtils.getIngestModuleTemplate(new VMExtractorIngestModuleFactory());
final IngestModuleTemplate photoRecTemplate = IngestUtils.getIngestModuleTemplate(new PhotoRecCarverIngestModuleFactory()); final IngestModuleTemplate photoRecTemplate = IngestUtils.getIngestModuleTemplate(new PhotoRecCarverIngestModuleFactory());
final IngestModuleTemplate e01VerifierTemplate = IngestUtils.getIngestModuleTemplate(new E01VerifierModuleFactory()); final IngestModuleTemplate dataSourceIntegrityTemplate = IngestUtils.getIngestModuleTemplate(new DataSourceIntegrityModuleFactory());
final IngestModuleTemplate eamDbTemplate = IngestUtils.getIngestModuleTemplate(new org.sleuthkit.autopsy.centralrepository.ingestmodule.IngestModuleFactory()); final IngestModuleTemplate eamDbTemplate = IngestUtils.getIngestModuleTemplate(new org.sleuthkit.autopsy.centralrepository.ingestmodule.CentralRepoIngestModuleFactory());
final IngestModuleTemplate fileExtMismatchDetectorTemplate = IngestUtils.getIngestModuleTemplate(new FileExtMismatchDetectorModuleFactory()); 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 //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()); // final IngestModuleTemplate objectDetectorTemplate = IngestUtils.getIngestModuleTemplate(new org.sleuthkit.autopsy.experimental.objectdetection.ObjectDetectionModuleFactory());
@ -217,10 +217,10 @@ class InterCaseTestUtils {
kitchenSink.add(hashLookupTemplate); kitchenSink.add(hashLookupTemplate);
kitchenSink.add(vmExtractorTemplate); kitchenSink.add(vmExtractorTemplate);
kitchenSink.add(photoRecTemplate); kitchenSink.add(photoRecTemplate);
kitchenSink.add(e01VerifierTemplate); kitchenSink.add(dataSourceIntegrityTemplate);
kitchenSink.add(eamDbTemplate); kitchenSink.add(eamDbTemplate);
kitchenSink.add(fileExtMismatchDetectorTemplate); 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(objectDetectorTemplate);
// kitchenSink.add(emailParserTemplate); // kitchenSink.add(emailParserTemplate);
// kitchenSink.add(recentActivityTemplate); // 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.centralrepository.datamodel.EamDbException;
import org.sleuthkit.autopsy.commonfilesearch.AbstractCommonAttributeInstance; import org.sleuthkit.autopsy.commonfilesearch.AbstractCommonAttributeInstance;
import org.sleuthkit.autopsy.commonfilesearch.CommonAttributeSearchResults; 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.CommonAttributeValue;
import org.sleuthkit.autopsy.commonfilesearch.CommonAttributeValueList; import org.sleuthkit.autopsy.commonfilesearch.CommonAttributeValueList;
import org.sleuthkit.autopsy.coreutils.TimeStampUtils; import org.sleuthkit.autopsy.coreutils.TimeStampUtils;

View File

@ -24,6 +24,7 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@ -374,25 +375,32 @@ class VolatilityProcessor {
continue; continue;
} }
try { try {
BlackboardArtifact volArtifact = resolvedFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT); Collection<BlackboardAttribute> attributes = new ArrayList<>();
BlackboardAttribute att1 = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME, VOLATILITY, Bundle.VolatilityProcessor_artifactAttribute_interestingFileSet(pluginName)); attributes.add(new BlackboardAttribute(
volArtifact.addAttribute(att1); BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME, VOLATILITY, Bundle.VolatilityProcessor_artifactAttribute_interestingFileSet(pluginName)));
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 { try {
// index the artifact for keyword search // index the artifact for keyword search
blackboard.indexArtifact(volArtifact); blackboard.indexArtifact(volArtifact);
} catch (Blackboard.BlackboardException ex) { } catch (Blackboard.BlackboardException ex) {
errorMsgs.add(Bundle.VolatilityProcessor_errorMessage_failedToIndexArtifact(pluginName)); errorMsgs.add(Bundle.VolatilityProcessor_errorMessage_failedToIndexArtifact(pluginName));
/* /*
* Log the exception as well as add it to the error * Log the exception as well as add it to the error
* messages, to ensure that the stack trace is not * messages, to ensure that the stack trace is not
* lost. * lost.
*/ */
logger.log(Level.SEVERE, String.format("Failed to index artifact (artifactId=%d) for for output of %s plugin", volArtifact.getArtifactID(), pluginName), ex); 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) { } catch (TskCoreException ex) {
throw new VolatilityProcessorException(Bundle.VolatilityProcessor_exceptionMessage_errorCreatingArtifact(pluginName), 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 harness.dir=${nbplatform.active.dir}/harness
bootstrap.url=http://bits.netbeans.org/dev/nbms-and-javadoc/lastSuccessfulBuild/artifact/nbbuild/netbeans/harness/tasks.jar 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 # 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=\ cluster.path=\
${nbplatform.active.dir}/harness:\ ${nbplatform.active.dir}/harness:\
${nbplatform.active.dir}/java:\ ${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 harness.dir=${nbplatform.active.dir}/harness
bootstrap.url=http://bits.netbeans.org/dev/nbms-and-javadoc/lastSuccessfulBuild/artifact/nbbuild/netbeans/harness/tasks.jar 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 # 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=\ cluster.path=\
${nbplatform.active.dir}/harness:\ ${nbplatform.active.dir}/harness:\
${nbplatform.active.dir}/java:\ ${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 harness.dir=${nbplatform.active.dir}/harness
bootstrap.url=http://bits.netbeans.org/dev/nbms-and-javadoc/lastSuccessfulBuild/artifact/nbbuild/netbeans/harness/tasks.jar 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 # 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=\ cluster.path=\
${nbplatform.active.dir}/harness:\ ${nbplatform.active.dir}/harness:\
${nbplatform.active.dir}/java:\ ${nbplatform.active.dir}/java:\