mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-06 21:00:22 +00:00
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:
commit
43b580052b
@ -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"/>
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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>
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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) {
|
||||||
|
@ -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));
|
@ -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");
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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">
|
||||||
|
@ -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();
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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"/>
|
||||||
|
@ -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
|
|
||||||
|
@ -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
|
||||||
|
@ -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[]{};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="ViewPreferencesPanel.maximumResultsLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</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, "{key}")"/>
|
||||||
<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, "{key}")"/>
|
|
||||||
</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">
|
||||||
|
@ -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;
|
||||||
|
@ -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());
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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(),
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -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:
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
@ -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;
|
BIN
Core/src/org/sleuthkit/autopsy/images/devices.png
Normal file
BIN
Core/src/org/sleuthkit/autopsy/images/devices.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 483 B |
BIN
Core/src/org/sleuthkit/autopsy/images/sim_card.png
Normal file
BIN
Core/src/org/sleuthkit/autopsy/images/sim_card.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 306 B |
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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>
|
||||||
|
4
Core/src/org/sleuthkit/autopsy/modules/case_uco/Bundle.properties
Executable file
4
Core/src/org/sleuthkit/autopsy/modules/case_uco/Bundle.properties
Executable 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
|
458
Core/src/org/sleuthkit/autopsy/modules/case_uco/ReportCaseUco.java
Executable file
458
Core/src/org/sleuthkit/autopsy/modules/case_uco/ReportCaseUco.java
Executable 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;
|
||||||
|
}
|
||||||
|
}
|
@ -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="<String>"/>
|
||||||
|
</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, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
<AuxValues>
|
||||||
|
<AuxValue name="generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
|
||||||
|
</AuxValues>
|
||||||
|
</Component>
|
||||||
|
</SubComponents>
|
||||||
|
</Form>
|
133
Core/src/org/sleuthkit/autopsy/modules/case_uco/ReportCaseUcoConfigPanel.java
Executable file
133
Core/src/org/sleuthkit/autopsy/modules/case_uco/ReportCaseUcoConfigPanel.java
Executable 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);
|
||||||
|
}
|
||||||
|
}
|
@ -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
|
@ -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
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -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, "{key}")"/>
|
||||||
|
</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, "{key}")"/>
|
||||||
|
</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, "{key}")"/>
|
||||||
|
</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, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
</Component>
|
||||||
|
</SubComponents>
|
||||||
|
</Form>
|
@ -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
|
||||||
|
|
||||||
|
}
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
@ -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>
|
|
@ -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
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,6 +91,9 @@
|
|||||||
<ResourceString bundle="org/sleuthkit/autopsy/othercasessearch/Bundle.properties" key="OtherCasesSearchDialog.correlationValueTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/othercasessearch/Bundle.properties" key="OtherCasesSearchDialog.correlationValueTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</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="<String>"/>
|
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="<String>"/>
|
||||||
</AuxValues>
|
</AuxValues>
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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:\
|
||||||
|
@ -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:\
|
||||||
|
@ -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:\
|
||||||
|
Loading…
x
Reference in New Issue
Block a user