6225 resolve merge conflicts

This commit is contained in:
William Schaefer 2020-04-12 23:04:33 -04:00
commit c8eef33009
50 changed files with 727 additions and 300 deletions

View File

@ -2,7 +2,7 @@ Manifest-Version: 1.0
OpenIDE-Module: org.sleuthkit.autopsy.core/10 OpenIDE-Module: org.sleuthkit.autopsy.core/10
OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/core/Bundle.properties OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/core/Bundle.properties
OpenIDE-Module-Layer: org/sleuthkit/autopsy/core/layer.xml OpenIDE-Module-Layer: org/sleuthkit/autopsy/core/layer.xml
OpenIDE-Module-Implementation-Version: 30 OpenIDE-Module-Implementation-Version: 31
OpenIDE-Module-Requires: org.openide.windows.WindowManager OpenIDE-Module-Requires: org.openide.windows.WindowManager
AutoUpdate-Show-In-Client: true AutoUpdate-Show-In-Client: true
AutoUpdate-Essential-Module: true AutoUpdate-Essential-Module: true

View File

@ -126,5 +126,5 @@ nbm.homepage=http://www.sleuthkit.org/
nbm.module.author=Brian Carrier nbm.module.author=Brian Carrier
nbm.needs.restart=true nbm.needs.restart=true
source.reference.curator-recipes-2.8.0.jar=release/modules/ext/curator-recipes-2.8.0-sources.jar source.reference.curator-recipes-2.8.0.jar=release/modules/ext/curator-recipes-2.8.0-sources.jar
spec.version.base=10.18 spec.version.base=10.19

View File

@ -251,7 +251,7 @@
<compile-dependency/> <compile-dependency/>
<run-dependency> <run-dependency>
<release-version>3</release-version> <release-version>3</release-version>
<specification-version>1.3</specification-version> <specification-version>1.4</specification-version>
</run-dependency> </run-dependency>
</dependency> </dependency>
</module-dependencies> </module-dependencies>

View File

@ -50,7 +50,7 @@ import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
@ActionID(category = "Tools", id = "org.sleuthkit.autopsy.casemodule.CaseCloseAction") @ActionID(category = "Tools", id = "org.sleuthkit.autopsy.casemodule.CaseCloseAction")
@ActionRegistration(displayName = "#CTL_CaseCloseAct", lazy = false) @ActionRegistration(displayName = "#CTL_CaseCloseAct", lazy = false)
@ActionReferences(value = { @ActionReferences(value = {
@ActionReference(path = "Toolbars/Case", position = 106)}) @ActionReference(path = "Toolbars/Case", position = 107)})
public final class CaseCloseAction extends CallableSystemAction implements Presenter.Toolbar { public final class CaseCloseAction extends CallableSystemAction implements Presenter.Toolbar {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;

View File

@ -464,7 +464,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
// correlate on blackboard artifact attributes if they exist and supported // correlate on blackboard artifact attributes if they exist and supported
BlackboardArtifact bbArtifact = getBlackboardArtifactFromNode(node); BlackboardArtifact bbArtifact = getBlackboardArtifactFromNode(node);
if (bbArtifact != null && CentralRepository.isEnabled()) { if (bbArtifact != null && CentralRepository.isEnabled()) {
ret.addAll(CorrelationAttributeUtil.makeCorrAttrsFromArtifact(bbArtifact)); ret.addAll(CorrelationAttributeUtil.makeCorrAttrsForCorrelation(bbArtifact));
} }
// we can correlate based on the MD5 if it is enabled // we can correlate based on the MD5 if it is enabled

View File

@ -19,7 +19,9 @@
package org.sleuthkit.autopsy.centralrepository.datamodel; package org.sleuthkit.autopsy.centralrepository.datamodel;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.logging.Level; import java.util.logging.Level;
import org.openide.util.NbBundle.Messages; import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
@ -32,6 +34,7 @@ import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
import org.sleuthkit.datamodel.CommunicationsUtils;
import org.sleuthkit.datamodel.HashUtility; import org.sleuthkit.datamodel.HashUtility;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskData;
@ -59,25 +62,60 @@ public class CorrelationAttributeUtil {
return Bundle.CorrelationAttributeUtil_emailaddresses_text(); return Bundle.CorrelationAttributeUtil_emailaddresses_text();
} }
// Defines which artifact types act as the sources for CR data.
// Most notably, does not include KEYWORD HIT, CALLLOGS, MESSAGES, CONTACTS
// TSK_INTERESTING_ARTIFACT_HIT (See JIRA-6129 for more details on the
// interesting artifact hit).
// IMPORTANT: This set should be updated for new artifacts types that need to
// be inserted into the CR.
private static final Set<Integer> SOURCE_TYPES_FOR_CR_INSERT = new HashSet<Integer>() {{
add(ARTIFACT_TYPE.TSK_WEB_BOOKMARK.getTypeID());
add(ARTIFACT_TYPE.TSK_WEB_COOKIE.getTypeID());
add(ARTIFACT_TYPE.TSK_WEB_DOWNLOAD.getTypeID());
add(ARTIFACT_TYPE.TSK_WEB_HISTORY.getTypeID());
add(ARTIFACT_TYPE.TSK_DEVICE_ATTACHED.getTypeID());
add(ARTIFACT_TYPE.TSK_WIFI_NETWORK.getTypeID());
add(ARTIFACT_TYPE.TSK_WIFI_NETWORK_ADAPTER.getTypeID());
add(ARTIFACT_TYPE.TSK_BLUETOOTH_PAIRING.getTypeID());
add(ARTIFACT_TYPE.TSK_BLUETOOTH_ADAPTER.getTypeID());
add(ARTIFACT_TYPE.TSK_DEVICE_INFO.getTypeID());
add(ARTIFACT_TYPE.TSK_SIM_ATTACHED.getTypeID());
add(ARTIFACT_TYPE.TSK_WEB_FORM_ADDRESS.getTypeID());
add(ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID());
}};
/** /**
* Makes zero to many correlation attribute instances from the attributes of * Makes zero to many correlation attribute instances from the attributes of
* an artifact. * artifacts that have correlatable data. The intention of this method is to
* * use the results to save to the CR, not to correlate with them. If you
* IMPORTANT: The correlation attribute instances are NOT added to the * want to correlate, please use makeCorrAttrsForCorrelation. An artifact that can
* central repository by this method. * have correlatable data != An artifact that should be the source of data
* * in the CR, so results may be un-necessarily incomplete.
* @param artifact An artifact. *
* @param artifact An artifact.
* *
* @return A list, possibly empty, of correlation attribute instances for * @return A list, possibly empty, of correlation attribute instances for
* the artifact. * the artifact.
*/ */
public static List<CorrelationAttributeInstance> makeCorrAttrsFromArtifact(BlackboardArtifact artifact) { public static List<CorrelationAttributeInstance> makeCorrAttrsToSave(BlackboardArtifact artifact) {
return makeCorrAttrsFromArtifact(artifact, true ); if(SOURCE_TYPES_FOR_CR_INSERT.contains(artifact.getArtifactTypeID())) {
// Restrict the correlation attributes to use for saving.
// The artifacts which are suitable for saving are a subset of the
// artifacts that are suitable for correlating.
return makeCorrAttrsForCorrelation(artifact);
}
// Return an empty collection.
return new ArrayList<>();
} }
/** /**
* Makes zero to many correlation attribute instances from the attributes of * Makes zero to many correlation attribute instances from the attributes of
* an artifact. * artifacts that have correlatable data. The intention of this method is to
* use the results to correlate with, not to save. If you
* want to save, please use makeCorrAttrsToSave. An artifact that can
* have correlatable data != An artifact that should be the source of data
* in the CR, so results may be too lenient.
* *
* IMPORTANT: The correlation attribute instances are NOT added to the * IMPORTANT: The correlation attribute instances are NOT added to the
* central repository by this method. * central repository by this method.
@ -91,26 +129,22 @@ public class CorrelationAttributeUtil {
* checking is easy to forget, while catching exceptions is enforced. * checking is easy to forget, while catching exceptions is enforced.
* *
* @param artifact An artifact. * @param artifact An artifact.
* @param resolveSourceArtifact A flag to indicate whether to resolve the
* source artifact, if the given artifact is
* of type TSK_INTERESTING_ARTIFACT_HIT.
* *
* @return A list, possibly empty, of correlation attribute instances for * @return A list, possibly empty, of correlation attribute instances for
* the artifact. * the artifact.
*/ */
public static List<CorrelationAttributeInstance> makeCorrAttrsFromArtifact(BlackboardArtifact artifact, boolean resolveSourceArtifact) { public static List<CorrelationAttributeInstance> makeCorrAttrsForCorrelation(BlackboardArtifact artifact) {
List<CorrelationAttributeInstance> correlationAttrs = new ArrayList<>(); List<CorrelationAttributeInstance> correlationAttrs = new ArrayList<>();
// If the artifact is of type TSK_INTERESTING_ARTIFACT_HIT, and the caller
// has not indicated to resolve the source artifact, then return an empty list.
if ((artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID()) && (resolveSourceArtifact == false) ) {
return correlationAttrs;
}
try { try {
BlackboardArtifact sourceArtifact = getCorrAttrSourceArtifact(artifact); BlackboardArtifact sourceArtifact = getCorrAttrSourceArtifact(artifact);
if (sourceArtifact != null) { if (sourceArtifact != null) {
int artifactTypeID = sourceArtifact.getArtifactTypeID(); int artifactTypeID = sourceArtifact.getArtifactTypeID();
if (artifactTypeID == ARTIFACT_TYPE.TSK_WEB_BOOKMARK.getTypeID() if (artifactTypeID == ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) {
BlackboardAttribute setNameAttr = sourceArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME));
if (setNameAttr != null && CorrelationAttributeUtil.getEmailAddressAttrDisplayName().equals(setNameAttr.getValueString())) {
makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD, CorrelationAttributeInstance.EMAIL_TYPE_ID);
}
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_WEB_BOOKMARK.getTypeID()
|| artifactTypeID == ARTIFACT_TYPE.TSK_WEB_COOKIE.getTypeID() || artifactTypeID == ARTIFACT_TYPE.TSK_WEB_COOKIE.getTypeID()
|| artifactTypeID == ARTIFACT_TYPE.TSK_WEB_DOWNLOAD.getTypeID() || artifactTypeID == ARTIFACT_TYPE.TSK_WEB_DOWNLOAD.getTypeID()
|| artifactTypeID == ARTIFACT_TYPE.TSK_WEB_HISTORY.getTypeID()) { || artifactTypeID == ARTIFACT_TYPE.TSK_WEB_HISTORY.getTypeID()) {
@ -143,6 +177,11 @@ public class CorrelationAttributeUtil {
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) { } else if (artifactTypeID == ARTIFACT_TYPE.TSK_ACCOUNT.getTypeID()) {
makeCorrAttrFromAcctArtifact(correlationAttrs, sourceArtifact); makeCorrAttrFromAcctArtifact(correlationAttrs, sourceArtifact);
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_CONTACT.getTypeID()
|| artifactTypeID == ARTIFACT_TYPE.TSK_CALLLOG.getTypeID()
|| artifactTypeID == ARTIFACT_TYPE.TSK_MESSAGE.getTypeID()) {
makeCorrAttrsFromCommunicationArtifacts(correlationAttrs, sourceArtifact);
} }
} }
} catch (CentralRepoException ex) { } catch (CentralRepoException ex) {
@ -158,6 +197,47 @@ public class CorrelationAttributeUtil {
return correlationAttrs; return correlationAttrs;
} }
/**
* Makes a correlation attribute instance from a phone number attribute of an
* artifact.
*
* @param corrAttrInstances Correlation attributes will be added to this.
* @param artifact An artifact with a phone number attribute.
*
* @throws TskCoreException If there is an error querying the case
* database.
* @throws CentralRepoException If there is an error querying the central
* repository.
*/
private static void makeCorrAttrsFromCommunicationArtifacts(List<CorrelationAttributeInstance> corrAttrInstances, BlackboardArtifact artifact) throws TskCoreException, CentralRepoException {
CorrelationAttributeInstance corrAttr = null;
/*
* Extract the phone number from the artifact attribute.
*/
String value = null;
if (null != artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER))) {
value = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER)).getValueString();
} else if (null != artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM))) {
value = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM)).getValueString();
} else if (null != artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO))) {
value = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO)).getValueString();
}
/*
* Normalize the phone number.
*/
if (value != null) {
if(CommunicationsUtils.isValidPhoneNumber(value)) {
value = CommunicationsUtils.normalizePhoneNum(value);
corrAttr = makeCorrAttr(artifact, CentralRepository.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.PHONE_TYPE_ID), value);
if(corrAttr != null) {
corrAttrInstances.add(corrAttr);
}
}
}
}
/** /**
* Gets the associated artifact of a "meta-artifact" such as an interesting * Gets the associated artifact of a "meta-artifact" such as an interesting
* artifact hit artifact. * artifact hit artifact.
@ -186,33 +266,29 @@ public class CorrelationAttributeUtil {
/** /**
* Makes a correlation attribute instance for an account artifact. * Makes a correlation attribute instance for an account artifact.
* *
* Also creates an account in the CR DB if it doesn't exist. * Also creates an account in the CR DB if it doesn't exist.
* *
* IMPORTANT: The correlation attribute instance is NOT added to the central * IMPORTANT: The correlation attribute instance is NOT added to the central
* repository by this method. * repository by this method.
* *
* TODO (Jira-6088): The methods in this low-level, utility class should
* throw exceptions instead of logging them. The reason for this is that the
* clients of the utility class, not the utility class itself, should be in
* charge of error handling policy, per the Autopsy Coding Standard. Note
* that clients of several of these methods currently cannot determine
* whether receiving a null return value is an error or not, plus null
* checking is easy to forget, while catching exceptions is enforced.
*
* @param corrAttrInstances A list of correlation attribute instances. * @param corrAttrInstances A list of correlation attribute instances.
* @param acctArtifact An account artifact. * @param acctArtifact An account artifact.
* *
* @return The correlation attribute instance. * @return The correlation attribute instance.
*/ */
private static void makeCorrAttrFromAcctArtifact(List<CorrelationAttributeInstance> corrAttrInstances, BlackboardArtifact acctArtifact) throws TskCoreException, CentralRepoException { private static void makeCorrAttrFromAcctArtifact(List<CorrelationAttributeInstance> corrAttrInstances, BlackboardArtifact acctArtifact) throws TskCoreException, CentralRepoException {
// Get the account type from the artifact // Get the account type from the artifact
BlackboardAttribute accountTypeAttribute = acctArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE)); BlackboardAttribute accountTypeAttribute = acctArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE));
String accountTypeStr = accountTypeAttribute.getValueString(); String accountTypeStr = accountTypeAttribute.getValueString();
// @@TODO Vik-6136: CR currently does not know of custom account types.
// Ensure there is a predefined account type for this account.
Account.Type predefinedAccountType = Account.Type.PREDEFINED_ACCOUNT_TYPES.stream().filter(type -> type.getTypeName().equalsIgnoreCase(accountTypeStr)).findAny().orElse(null);
// do not create any correlation attribute instance for a Device account // do not create any correlation attribute instance for a Device account
if (Account.Type.DEVICE.getTypeName().equalsIgnoreCase(accountTypeStr) == false) { if (Account.Type.DEVICE.getTypeName().equalsIgnoreCase(accountTypeStr) == false && predefinedAccountType != null) {
// Get the corresponding CentralRepoAccountType from the database. // Get the corresponding CentralRepoAccountType from the database.
CentralRepoAccountType crAccountType = CentralRepository.getInstance().getAccountTypeByName(accountTypeStr); CentralRepoAccountType crAccountType = CentralRepository.getInstance().getAccountTypeByName(accountTypeStr);
@ -441,10 +517,10 @@ public class CorrelationAttributeUtil {
file.getId()); file.getId());
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
logger.log(Level.SEVERE, String.format("Error querying case database (%s)", file), ex); // NON-NLS logger.log(Level.SEVERE, String.format("Error querying case database (%s)", file), ex); // NON-NLS
return null; return null;
} catch (CentralRepoException ex) { } catch (CentralRepoException ex) {
logger.log(Level.SEVERE, String.format("Error querying central repository (%s)", file), ex); // NON-NLS logger.log(Level.SEVERE, String.format("Error querying central repository (%s)", file), ex); // NON-NLS
return null; return null;
} catch (CorrelationAttributeNormalizationException ex) { } catch (CorrelationAttributeNormalizationException ex) {
logger.log(Level.WARNING, String.format("Error creating correlation attribute instance (%s)", file), ex); // NON-NLS logger.log(Level.WARNING, String.format("Error creating correlation attribute instance (%s)", file), ex); // NON-NLS

View File

@ -296,7 +296,7 @@ final class CaseEventListener implements PropertyChangeListener {
return; return;
} }
List<CorrelationAttributeInstance> convertedArtifacts = CorrelationAttributeUtil.makeCorrAttrsFromArtifact(bbArtifact); List<CorrelationAttributeInstance> convertedArtifacts = CorrelationAttributeUtil.makeCorrAttrsForCorrelation(bbArtifact);
for (CorrelationAttributeInstance eamArtifact : convertedArtifacts) { for (CorrelationAttributeInstance eamArtifact : convertedArtifacts) {
eamArtifact.setComment(comment); eamArtifact.setComment(comment);
try { try {
@ -369,7 +369,7 @@ final class CaseEventListener implements PropertyChangeListener {
if (!hasTagWithConflictingKnownStatus) { if (!hasTagWithConflictingKnownStatus) {
//Get the correlation atttributes that correspond to the current BlackboardArtifactTag if their status should be changed //Get the correlation atttributes that correspond to the current BlackboardArtifactTag if their status should be changed
//with the initial set of correlation attributes this should be a single correlation attribute //with the initial set of correlation attributes this should be a single correlation attribute
List<CorrelationAttributeInstance> convertedArtifacts = CorrelationAttributeUtil.makeCorrAttrsFromArtifact(bbTag.getArtifact()); List<CorrelationAttributeInstance> convertedArtifacts = CorrelationAttributeUtil.makeCorrAttrsForCorrelation(bbTag.getArtifact());
for (CorrelationAttributeInstance eamArtifact : convertedArtifacts) { for (CorrelationAttributeInstance eamArtifact : convertedArtifacts) {
CentralRepository.getInstance().setAttributeInstanceKnownStatus(eamArtifact, tagName.getKnownStatus()); CentralRepository.getInstance().setAttributeInstanceKnownStatus(eamArtifact, tagName.getKnownStatus());
} }

View File

@ -455,11 +455,8 @@ public class IngestEventsListener {
List<CorrelationAttributeInstance> eamArtifacts = new ArrayList<>(); List<CorrelationAttributeInstance> eamArtifacts = new ArrayList<>();
for (BlackboardArtifact bbArtifact : bbArtifacts) { for (BlackboardArtifact bbArtifact : bbArtifacts) {
// If the incoming artifact is of type TSK_INTERESTING_ARTIFACT_HIT, // makeCorrAttrToSave will filter out artifacts which should not be sources of CR data.
// do not resolve to the source artifact, as correlation attributes List<CorrelationAttributeInstance> convertedArtifacts = CorrelationAttributeUtil.makeCorrAttrsToSave(bbArtifact);
// for the source artifact would have already been created,
// when the event for that source artifact was received.
List<CorrelationAttributeInstance> convertedArtifacts = CorrelationAttributeUtil.makeCorrAttrsFromArtifact(bbArtifact, false);
for (CorrelationAttributeInstance eamArtifact : convertedArtifacts) { for (CorrelationAttributeInstance eamArtifact : convertedArtifacts) {
try { try {
// Only do something with this artifact if it's unique within the job // Only do something with this artifact if it's unique within the job

View File

@ -84,3 +84,6 @@ ManageCasesDialog.closeButton.text=Close
ManageCasesDialog.notesLabel.text=Notes: ManageCasesDialog.notesLabel.text=Notes:
ManageCasesDialog.dataSourcesLabel.text=Data Sources: ManageCasesDialog.dataSourcesLabel.text=Data Sources:
ManageCasesDialog.caseInfoLabel.text=Case Info: ManageCasesDialog.caseInfoLabel.text=Case Info:
GlobalSettingsPanel.bnTestConfigure.text=Test
GlobalSettingsPanel.testStatusLabel.toolTipText=
GlobalSettingsPanel.testStatusLabel.text=

View File

@ -12,15 +12,15 @@ EamDbSettingsDialog.fcDatabasePath.title=Select location for central_repository.
EamDbSettingsDialog.lbDatabaseType.text=Database Type : EamDbSettingsDialog.lbDatabaseType.text=Database Type :
EamDbSettingsDialog.lbSingleUserSqLite.text=SQLite should only be used by one examiner at a time. EamDbSettingsDialog.lbSingleUserSqLite.text=SQLite should only be used by one examiner at a time.
EamDbSettingsDialog.okButton.connectionErrorMsg.text=Failed to connect to central repository database. EamDbSettingsDialog.okButton.connectionErrorMsg.text=Failed to connect to central repository database.
EamDbSettingsDialog.okButton.corruptDatabaseExists.message=Database exists but is not the right format. Manually delete it or choose a different path (if applicable). EamDbSettingsDialog.okButton.corruptDatabaseExists.message=Central Repository Database exists but is not the right format. Manually delete it or choose a different path (if applicable).
EamDbSettingsDialog.okButton.corruptDatabaseExists.title=Error Loading Database EamDbSettingsDialog.okButton.corruptDatabaseExists.title=Error Loading Central Repository Database
EamDbSettingsDialog.okButton.createDbDialog.message=Database does not exist, would you like to create it? EamDbSettingsDialog.okButton.createDbDialog.message=Central Repository Database does not exist, would you like to create it?
EamDbSettingsDialog.okButton.createDbDialog.title=Database Does Not Exist EamDbSettingsDialog.okButton.createDbDialog.title=Central Repository Database Does Not Exist
EamDbSettingsDialog.okButton.createDbError.title=Unable to Create Database EamDbSettingsDialog.okButton.createDbError.title=Unable to Create Central Repository Database
EamDbSettingsDialog.okButton.createPostgresDbError.message=Unable to create Postgres Database, please ensure address, port, and login credentials are correct for Postgres server and try again. EamDbSettingsDialog.okButton.createPostgresDbError.message=Unable to create Postgres Central Repository Database, please ensure address, port, and login credentials are correct for Postgres server and try again.
EamDbSettingsDialog.okButton.createSQLiteDbError.message=Unable to create SQLite Database, please ensure location exists and you have write permissions and try again. EamDbSettingsDialog.okButton.createSQLiteDbError.message=Unable to create SQLite Central Repository Database, please ensure location exists and you have write permissions and try again.
EamDbSettingsDialog.okButton.databaseConnectionFailed.message=Unable to connect to database. Please check your settings and try again. EamDbSettingsDialog.okButton.databaseConnectionFailed.message=Unable to connect to Central Repository Database. Please check your settings and try again.
EamDbSettingsDialog.okButton.databaseConnectionFailed.title=Database Connection Failed EamDbSettingsDialog.okButton.databaseConnectionFailed.title=Central Repository Database Connection Failed
EamDbSettingsDialog.okButton.errorMsg.text=Please restart Autopsy to begin using the new database platform. EamDbSettingsDialog.okButton.errorMsg.text=Please restart Autopsy to begin using the new database platform.
EamDbSettingsDialog.okButton.errorTitle.text=Restart Required. EamDbSettingsDialog.okButton.errorTitle.text=Restart Required.
EamDbSettingsDialog.textPrompt.dbName=Database Name EamDbSettingsDialog.textPrompt.dbName=Database Name
@ -33,12 +33,16 @@ EamDbSettingsDialog.validation.finished=Click OK to save your database settings
EamDbSettingsDialog.validation.incompleteFields=Fill in all values for the selected database. EamDbSettingsDialog.validation.incompleteFields=Fill in all values for the selected database.
EamOptionsController.moduleErr=Error processing value changes. EamOptionsController.moduleErr=Error processing value changes.
EamOptionsController.moduleErr.msg=Value change processing failed. EamOptionsController.moduleErr.msg=Value change processing failed.
GlobalSettingsPanel.askForCentralRepoDbChoice.customPostgrestChoice.text=Configure PostgreSQL
GlobalSettingsPanel.askForCentralRepoDbChoice.disableChoice.text=Disable Central Repository
GlobalSettingsPanel.askForCentralRepoDbChoice.sqliteChoice.text=Use SQLite
GlobalSettingsPanel.onMultiUserChange.disabledMu.description=The Central Repository will be reconfigured to use a local SQLite database. GlobalSettingsPanel.onMultiUserChange.disabledMu.description=The Central Repository will be reconfigured to use a local SQLite database.
GlobalSettingsPanel.onMultiUserChange.disabledMu.description2=Press Configure PostgreSQL to change to a PostgreSQL database. GlobalSettingsPanel.onMultiUserChange.disabledMu.description2=Press Configure PostgreSQL to change to a PostgreSQL database.
GlobalSettingsPanel.onMultiUserChange.disabledMu.title=Central Repository Change Necessary GlobalSettingsPanel.onMultiUserChange.disabledMu.title=Central Repository Change Necessary
GlobalSettingsPanel.onMultiUserChange.enable.description=Do you want to update the Central Repository to use this PostgreSQL database? GlobalSettingsPanel.onMultiUserChange.enable.description=Do you want to update the Central Repository to use this PostgreSQL database?
GlobalSettingsPanel.onMultiUserChange.enable.description2=The Central Repository stores hash values and accounts from past cases. GlobalSettingsPanel.onMultiUserChange.enable.description2=The Central Repository stores hash values and accounts from past cases.
GlobalSettingsPanel.onMultiUserChange.enable.title=Use with Central Repository? GlobalSettingsPanel.onMultiUserChange.enable.title=Use with Central Repository?
GlobalSettingsPanel.testCurrentConfiguration.dbDoesNotExist.message=Database does not exist.
GlobalSettingsPanel.validationErrMsg.ingestRunning=You cannot change settings while ingest is running. GlobalSettingsPanel.validationErrMsg.ingestRunning=You cannot change settings while ingest is running.
GlobalSettingsPanel.validationerrMsg.mustConfigure=Configure the database to enable this module. GlobalSettingsPanel.validationerrMsg.mustConfigure=Configure the database to enable this module.
ManageCasesDialog.title.text=Manage Cases ManageCasesDialog.title.text=Manage Cases
@ -147,3 +151,6 @@ ManageCasesDialog.closeButton.text=Close
ManageCasesDialog.notesLabel.text=Notes: ManageCasesDialog.notesLabel.text=Notes:
ManageCasesDialog.dataSourcesLabel.text=Data Sources: ManageCasesDialog.dataSourcesLabel.text=Data Sources:
ManageCasesDialog.caseInfoLabel.text=Case Info: ManageCasesDialog.caseInfoLabel.text=Case Info:
GlobalSettingsPanel.bnTestConfigure.text=Test
GlobalSettingsPanel.testStatusLabel.toolTipText=
GlobalSettingsPanel.testStatusLabel.text=

View File

@ -143,3 +143,5 @@ ManageCasesDialog.closeButton.text=\u9589\u3058\u308b
ManageCasesDialog.notesLabel.text=\u5099\u8003: ManageCasesDialog.notesLabel.text=\u5099\u8003:
ManageCasesDialog.dataSourcesLabel.text=\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9: ManageCasesDialog.dataSourcesLabel.text=\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9:
ManageCasesDialog.caseInfoLabel.text=\u30b1\u30fc\u30b9\u60c5\u5831: ManageCasesDialog.caseInfoLabel.text=\u30b1\u30fc\u30b9\u60c5\u5831:
GlobalSettingsPanel.bnTestConfigure.text=\u69cb\u6210
GlobalSettingsPanel.testStatusLabel.text=\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u5b9f\u884c\u4e2d\u306f\u30bb\u30f3\u30c8\u30e9\u30eb\u30fb\u30ec\u30dd\u30b8\u30c8\u30ea\u30fc\u8a2d\u5b9a\u3092\u5909\u66f4\u3067\u304d\u307e\u305b\u3093!

View File

@ -87,7 +87,6 @@ public class EamDbSettingsDialog extends JDialog {
private final Collection<JTextField> textBoxes; private final Collection<JTextField> textBoxes;
private final TextBoxChangedListener textBoxChangedListener; private final TextBoxChangedListener textBoxChangedListener;
private final CentralRepoDbManager manager = new CentralRepoDbManager(); private final CentralRepoDbManager manager = new CentralRepoDbManager();
private final boolean isMultiUserSelectable = CentralRepoDbManager.isPostgresMultiuserAllowed();
private final DbChoiceRenderer DB_CHOICE_RENDERER = new DbChoiceRenderer(); private final DbChoiceRenderer DB_CHOICE_RENDERER = new DbChoiceRenderer();
public EamDbSettingsDialog() { public EamDbSettingsDialog() {
@ -95,7 +94,7 @@ public class EamDbSettingsDialog extends JDialog {
} }
private boolean isDbChoiceSelectable(CentralRepoDbChoice item) { private boolean isDbChoiceSelectable(CentralRepoDbChoice item) {
return (item != CentralRepoDbChoice.POSTGRESQL_MULTIUSER || isMultiUserSelectable); return (item != CentralRepoDbChoice.POSTGRESQL_MULTIUSER || manager.isPostgresMultiuserAllowed());
} }
@ -159,15 +158,15 @@ public class EamDbSettingsDialog extends JDialog {
* @param dialog If non-null value, validates settings and updates 'okay' button enabled state. * @param dialog If non-null value, validates settings and updates 'okay' button enabled state.
* @return Whether or not the ultimate status after prompts is okay to continue. * @return Whether or not the ultimate status after prompts is okay to continue.
*/ */
@NbBundle.Messages({"EamDbSettingsDialog.okButton.corruptDatabaseExists.title=Error Loading Database", @NbBundle.Messages({"EamDbSettingsDialog.okButton.corruptDatabaseExists.title=Error Loading Central Repository Database",
"EamDbSettingsDialog.okButton.corruptDatabaseExists.message=Database exists but is not the right format. Manually delete it or choose a different path (if applicable).", "EamDbSettingsDialog.okButton.corruptDatabaseExists.message=Central Repository Database exists but is not the right format. Manually delete it or choose a different path (if applicable).",
"EamDbSettingsDialog.okButton.createDbDialog.title=Database Does Not Exist", "EamDbSettingsDialog.okButton.createDbDialog.title=Central Repository Database Does Not Exist",
"EamDbSettingsDialog.okButton.createDbDialog.message=Database does not exist, would you like to create it?", "EamDbSettingsDialog.okButton.createDbDialog.message=Central Repository Database does not exist, would you like to create it?",
"EamDbSettingsDialog.okButton.databaseConnectionFailed.title=Database Connection Failed", "EamDbSettingsDialog.okButton.databaseConnectionFailed.title=Central Repository Database Connection Failed",
"EamDbSettingsDialog.okButton.databaseConnectionFailed.message=Unable to connect to database. Please check your settings and try again.", "EamDbSettingsDialog.okButton.databaseConnectionFailed.message=Unable to connect to Central Repository Database. Please check your settings and try again.",
"EamDbSettingsDialog.okButton.createSQLiteDbError.message=Unable to create SQLite Database, please ensure location exists and you have write permissions and try again.", "EamDbSettingsDialog.okButton.createSQLiteDbError.message=Unable to create SQLite Central Repository Database, please ensure location exists and you have write permissions and try again.",
"EamDbSettingsDialog.okButton.createPostgresDbError.message=Unable to create Postgres Database, please ensure address, port, and login credentials are correct for Postgres server and try again.", "EamDbSettingsDialog.okButton.createPostgresDbError.message=Unable to create Postgres Central Repository Database, please ensure address, port, and login credentials are correct for Postgres server and try again.",
"EamDbSettingsDialog.okButton.createDbError.title=Unable to Create Database"}) "EamDbSettingsDialog.okButton.createDbError.title=Unable to Create Central Repository Database"})
private static boolean promptTestStatusWarnings(CentralRepoDbManager manager, EamDbSettingsDialog dialog) { private static boolean promptTestStatusWarnings(CentralRepoDbManager manager, EamDbSettingsDialog dialog) {
if (manager.getStatus() == DatabaseTestResult.CONNECTION_FAILED) { if (manager.getStatus() == DatabaseTestResult.CONNECTION_FAILED) {
JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(), JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
@ -181,31 +180,43 @@ public class EamDbSettingsDialog extends JDialog {
Bundle.EamDbSettingsDialog_okButton_corruptDatabaseExists_title(), Bundle.EamDbSettingsDialog_okButton_corruptDatabaseExists_title(),
JOptionPane.WARNING_MESSAGE); JOptionPane.WARNING_MESSAGE);
} else if (manager.getStatus() == DatabaseTestResult.DB_DOES_NOT_EXIST) { } else if (manager.getStatus() == DatabaseTestResult.DB_DOES_NOT_EXIST) {
//database doesn't exist. do you want to create? promptCreateDatabase(manager, dialog);
if (JOptionPane.YES_OPTION == JOptionPane.showConfirmDialog(WindowManager.getDefault().getMainWindow(),
Bundle.EamDbSettingsDialog_okButton_createDbDialog_message(),
Bundle.EamDbSettingsDialog_okButton_createDbDialog_title(),
JOptionPane.YES_NO_OPTION)) {
onUserPromptCreateDb(manager, dialog);
}
} }
return (manager.getStatus() == DatabaseTestResult.TESTED_OK); return (manager.getStatus() == DatabaseTestResult.TESTED_OK);
} }
/**
* When a new database needs to be created on user selecting cr, this code will be ran when user selects create cr. /**
* @param manager The manager handling the database creation. * This method prompts the user whether or not they would like to create a database in the instance that
* @param dialog The dialog that prompted database creation. * it doesn't exist.
* @param manager The manager to use when setting up the database.
* @param dialog If non-null value, validates settings and updates 'okay'
* button enabled state.
*
* @return Whether or not the ultimate status after prompts is okay.
*/ */
private static void onUserPromptCreateDb(CentralRepoDbManager manager, EamDbSettingsDialog dialog) { public static boolean promptCreateDatabase(CentralRepoDbManager manager, EamDbSettingsDialog dialog) {
try { //database doesn't exist. do you want to create?
manager.createDb(); if (JOptionPane.YES_OPTION == JOptionPane.showConfirmDialog(WindowManager.getDefault().getMainWindow(),
} catch (CentralRepoException e) { Bundle.EamDbSettingsDialog_okButton_createDbDialog_message(),
onPromptStatusError(manager); Bundle.EamDbSettingsDialog_okButton_createDbDialog_title(),
JOptionPane.YES_NO_OPTION)) {
try {
manager.createDb();
} catch (CentralRepoException e) {
onPromptStatusError(manager);
return false;
}
if (dialog != null) {
dialog.valid();
}
return true;
} }
if (dialog != null)
dialog.valid(); return manager.testStatus() == DatabaseTestResult.TESTED_OK;
} }
@ -604,8 +615,8 @@ public class EamDbSettingsDialog extends JDialog {
"EamDbSettingsDialog.okButton.errorMsg.text=Please restart Autopsy to begin using the new database platform.", "EamDbSettingsDialog.okButton.errorMsg.text=Please restart Autopsy to begin using the new database platform.",
"EamDbSettingsDialog.okButton.connectionErrorMsg.text=Failed to connect to central repository database."}) "EamDbSettingsDialog.okButton.connectionErrorMsg.text=Failed to connect to central repository database."})
private void bnOkActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnOkActionPerformed private void bnOkActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnOkActionPerformed
testStatusAndCreate(this, manager, this); if (testStatusAndCreate(this, manager, this))
dispose(); dispose();
}//GEN-LAST:event_bnOkActionPerformed }//GEN-LAST:event_bnOkActionPerformed
@ -659,6 +670,7 @@ public class EamDbSettingsDialog extends JDialog {
return true; return true;
} }
/** /**
* This method returns if changes to the central repository configuration were * This method returns if changes to the central repository configuration were
* successfully applied. * successfully applied.
@ -887,7 +899,6 @@ public class EamDbSettingsDialog extends JDialog {
@Override @Override
public void changedUpdate(DocumentEvent e) { public void changedUpdate(DocumentEvent e) {
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
manager.clearStatus(); manager.clearStatus();
updateFullDbPath(); updateFullDbPath();
valid(); valid();
@ -895,7 +906,6 @@ public class EamDbSettingsDialog extends JDialog {
@Override @Override
public void insertUpdate(DocumentEvent e) { public void insertUpdate(DocumentEvent e) {
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
manager.clearStatus(); manager.clearStatus();
updateFullDbPath(); updateFullDbPath();
valid(); valid();
@ -903,7 +913,6 @@ public class EamDbSettingsDialog extends JDialog {
@Override @Override
public void removeUpdate(DocumentEvent e) { public void removeUpdate(DocumentEvent e) {
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
manager.clearStatus(); manager.clearStatus();
updateFullDbPath(); updateFullDbPath();
valid(); valid();

View File

@ -61,7 +61,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">
<Component id="pnDatabaseConfiguration" alignment="0" max="32767" attributes="0"/> <Component id="pnDatabaseConfiguration" alignment="0" max="32767" attributes="0"/>
<Component id="pnCorrelationProperties" alignment="0" pref="1010" max="32767" attributes="0"/> <Component id="pnCorrelationProperties" alignment="0" pref="1016" max="32767" attributes="0"/>
<Component id="organizationPanel" alignment="1" max="32767" attributes="0"/> <Component id="organizationPanel" alignment="1" max="32767" attributes="0"/>
<Component id="casesPanel" alignment="0" max="32767" attributes="0"/> <Component id="casesPanel" alignment="0" max="32767" attributes="0"/>
<Group type="102" attributes="0"> <Group type="102" attributes="0">
@ -137,10 +137,6 @@
<Group type="102" attributes="0"> <Group type="102" attributes="0">
<EmptySpace min="-2" max="-2" attributes="0"/> <EmptySpace min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Component id="bnDbConfigure" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
</Group>
<Group type="102" attributes="0"> <Group type="102" attributes="0">
<Group type="103" groupAlignment="0" max="-2" attributes="0"> <Group type="103" groupAlignment="0" max="-2" attributes="0">
<Component id="lbDbPlatformTypeLabel" max="32767" attributes="0"/> <Component id="lbDbPlatformTypeLabel" max="32767" attributes="0"/>
@ -149,11 +145,22 @@
</Group> </Group>
<EmptySpace type="unrelated" min="-2" max="-2" attributes="0"/> <EmptySpace type="unrelated" min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="1" attributes="0"> <Group type="103" groupAlignment="1" attributes="0">
<Component id="lbDbNameValue" alignment="0" pref="936" max="32767" attributes="0"/> <Component id="lbDbNameValue" alignment="0" max="32767" attributes="0"/>
<Component id="lbDbPlatformValue" max="32767" attributes="0"/> <Component id="lbDbPlatformValue" max="32767" attributes="0"/>
<Component id="lbDbLocationValue" alignment="0" max="32767" attributes="0"/> <Group type="102" alignment="0" attributes="0">
<Component id="lbDbLocationValue" pref="255" max="32767" attributes="0"/>
<EmptySpace min="-2" pref="681" max="-2" attributes="0"/>
</Group>
</Group> </Group>
</Group> </Group>
<Group type="102" attributes="0">
<Component id="bnDbConfigure" min="-2" max="-2" attributes="0"/>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Component id="bnTestConfigure" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="testStatusLabel" min="-2" pref="675" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group> </Group>
</Group> </Group>
</Group> </Group>
@ -177,7 +184,13 @@
<Component id="lbDbLocationValue" min="-2" pref="14" max="-2" attributes="0"/> <Component id="lbDbLocationValue" min="-2" pref="14" max="-2" attributes="0"/>
</Group> </Group>
<EmptySpace max="32767" attributes="0"/> <EmptySpace max="32767" attributes="0"/>
<Component id="bnDbConfigure" min="-2" max="-2" attributes="0"/> <Group type="103" groupAlignment="0" attributes="0">
<Component id="testStatusLabel" alignment="0" max="32767" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="bnDbConfigure" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="bnTestConfigure" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace min="-2" pref="8" max="-2" attributes="0"/> <EmptySpace min="-2" pref="8" max="-2" attributes="0"/>
</Group> </Group>
</Group> </Group>
@ -221,6 +234,40 @@
</Component> </Component>
<Component class="javax.swing.JLabel" name="lbDbLocationValue"> <Component class="javax.swing.JLabel" name="lbDbLocationValue">
</Component> </Component>
<Component class="javax.swing.JButton" name="bnTestConfigure">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="GlobalSettingsPanel.bnTestConfigure.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="bnTestConfigureActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="testStatusLabel">
<Properties>
<Property name="font" type="java.awt.Font" editor="org.netbeans.modules.form.editors2.FontEditor">
<FontInfo relative="true">
<Font bold="false" component="testStatusLabel" property="font" relativeSize="false" size="11"/>
</FontInfo>
</Property>
<Property name="foreground" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
<Color blue="0" green="0" red="ff" type="rgb"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="GlobalSettingsPanel.testStatusLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="GlobalSettingsPanel.testStatusLabel.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[387, 16]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[387, 16]"/>
</Property>
</Properties>
</Component>
</SubComponents> </SubComponents>
</Container> </Container>
<Container class="javax.swing.JPanel" name="pnCorrelationProperties"> <Container class="javax.swing.JPanel" name="pnCorrelationProperties">
@ -256,7 +303,7 @@
<DimensionLayout dim="1"> <DimensionLayout dim="1">
<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="correlationPropertiesScrollPane" pref="28" max="32767" attributes="0"/> <Component id="correlationPropertiesScrollPane" pref="24" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Component id="bnManageTypes" min="-2" max="-2" attributes="0"/> <Component id="bnManageTypes" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="8" max="-2" attributes="0"/> <EmptySpace min="-2" pref="8" max="-2" attributes="0"/>

View File

@ -18,7 +18,6 @@
*/ */
package org.sleuthkit.autopsy.centralrepository.optionspanel; package org.sleuthkit.autopsy.centralrepository.optionspanel;
import java.awt.Cursor;
import java.awt.EventQueue; import java.awt.EventQueue;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeEvent;
@ -43,7 +42,13 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoDbUtil;
import org.sleuthkit.autopsy.centralrepository.datamodel.PostgresCentralRepoSettings; import org.sleuthkit.autopsy.centralrepository.datamodel.PostgresCentralRepoSettings;
import org.sleuthkit.autopsy.centralrepository.datamodel.SqliteCentralRepoSettings; import org.sleuthkit.autopsy.centralrepository.datamodel.SqliteCentralRepoSettings;
import java.awt.Component; import java.awt.Component;
import java.beans.PropertyChangeSupport;
import java.util.logging.Level; import java.util.logging.Level;
import javax.swing.ImageIcon;
import org.openide.util.ImageUtilities;
import org.sleuthkit.autopsy.centralrepository.datamodel.DatabaseTestResult;
/** /**
* Main settings panel for the Central Repository * Main settings panel for the Central Repository
@ -54,25 +59,57 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private static final Logger logger = Logger.getLogger(GlobalSettingsPanel.class.getName()); private static final Logger logger = Logger.getLogger(GlobalSettingsPanel.class.getName());
private static final Set<IngestManager.IngestJobEvent> INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.STARTED, IngestManager.IngestJobEvent.CANCELLED, IngestManager.IngestJobEvent.COMPLETED); private static final Set<IngestManager.IngestJobEvent> INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.STARTED, IngestManager.IngestJobEvent.CANCELLED, IngestManager.IngestJobEvent.COMPLETED);
private final IngestJobEventPropertyChangeListener ingestJobEventListener;
// this allows property change events to be fired at a static level but listened to by instances
private static final PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(GlobalSettingsPanel.class);
// tracks the last known instance property change listener so that only one GlobalSettingsPanel is listening for events
private static PropertyChangeListener lastRegistered = null;
private final IngestJobEventPropertyChangeListener ingestJobEventListener;
private final ImageIcon goodIcon = new ImageIcon(ImageUtilities.loadImage("org/sleuthkit/autopsy/images/good.png", false));
private final ImageIcon badIcon = new ImageIcon(ImageUtilities.loadImage("org/sleuthkit/autopsy/images/bad.png", false));
/** /**
* Creates new form EamOptionsPanel * Creates new form EamOptionsPanel
*/ */
public GlobalSettingsPanel() { public GlobalSettingsPanel() {
ingestJobEventListener = new IngestJobEventPropertyChangeListener(); ingestJobEventListener = new IngestJobEventPropertyChangeListener();
// listen for change events in currently saved choice
CentralRepoDbManager.addPropertyChangeListener((PropertyChangeEvent evt) -> ingestStateUpdated(Case.isCaseOpen()));
initComponents(); initComponents();
customizeComponents(); customizeComponents();
setupSettingsChangeListeners();
addIngestJobEventsListener(); addIngestJobEventsListener();
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), (PropertyChangeEvent evt) -> { Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), (PropertyChangeEvent evt) -> {
//disable when case is open, enable when case is closed //disable when case is open, enable when case is closed
ingestStateUpdated(evt.getNewValue() != null); ingestStateUpdated(evt.getNewValue() != null);
}); });
} }
/**
* Sets up this instance's listener for the GlobalSettingsPanel's changes.
*/
private void setupSettingsChangeListeners() {
// listen for change events in currently saved choice
if (lastRegistered != null) {
CentralRepoDbManager.removePropertyChangeListener(lastRegistered);
GlobalSettingsPanel.propertyChangeSupport.removePropertyChangeListener(lastRegistered);
}
lastRegistered = this::onSettingsChange;
CentralRepoDbManager.addPropertyChangeListener(lastRegistered);
GlobalSettingsPanel.propertyChangeSupport.addPropertyChangeListener(lastRegistered);
}
private void onSettingsChange(PropertyChangeEvent evt) {
ingestStateUpdated(Case.isCaseOpen());
clearStatus();
}
private void customizeComponents() { private void customizeComponents() {
setName(NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.pnCorrelationProperties.border.title")); setName(NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.pnCorrelationProperties.border.title"));
} }
@ -121,24 +158,23 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
public static void onMultiUserChange(Component parent, boolean muPreviouslySelected, boolean muCurrentlySelected) { public static void onMultiUserChange(Component parent, boolean muPreviouslySelected, boolean muCurrentlySelected) {
boolean crEnabled = CentralRepoDbUtil.allowUseOfCentralRepository(); boolean crEnabled = CentralRepoDbUtil.allowUseOfCentralRepository();
boolean crMultiUser = CentralRepoDbManager.getSavedDbChoice() == CentralRepoDbChoice.POSTGRESQL_MULTIUSER; boolean crMultiUser = CentralRepoDbManager.getSavedDbChoice() == CentralRepoDbChoice.POSTGRESQL_MULTIUSER;
boolean crDisabledDueToFailure = CentralRepoDbManager.isDisabledDueToFailure();
if (!muPreviouslySelected && muCurrentlySelected) { if (!muPreviouslySelected && muCurrentlySelected) {
SwingUtilities.invokeLater(() -> { SwingUtilities.invokeLater(() -> {
if (JOptionPane.YES_OPTION == JOptionPane.showConfirmDialog(parent, if (JOptionPane.YES_OPTION == JOptionPane.showConfirmDialog(parent,
"<html><body>" "<html><body>"
+ "<div style='width: 400px;'>" + "<div style='width: 400px;'>"
+ "<p>" + NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.onMultiUserChange.enable.description") + "</p>" + "<p>" + Bundle.GlobalSettingsPanel_onMultiUserChange_enable_description() + "</p>"
+ "<p style='margin-top: 10px'>" + NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.onMultiUserChange.enable.description2") + "</p>" + "<p style='margin-top: 10px'>" + Bundle.GlobalSettingsPanel_onMultiUserChange_enable_description2() + "</p>"
+ "</div>" + "</div>"
+ "</body></html>", + "</body></html>",
NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.onMultiUserChange.enable.title"), Bundle.GlobalSettingsPanel_onMultiUserChange_enable_title(),
JOptionPane.YES_NO_OPTION)) { JOptionPane.YES_NO_OPTION)) {
// setup database for CR // setup database for CR
CentralRepoDbUtil.setUseCentralRepo(true); CentralRepoDbUtil.setUseCentralRepo(true);
CentralRepoDbManager.saveDbChoice(CentralRepoDbChoice.POSTGRESQL_MULTIUSER); CentralRepoDbManager.saveDbChoice(CentralRepoDbChoice.POSTGRESQL_MULTIUSER);
handleDbChange(parent); checkStatusAndCreateDb(parent);
} }
}); });
} // moving from selected to not selected && 'PostgreSQL using multi-user settings' is selected } // moving from selected to not selected && 'PostgreSQL using multi-user settings' is selected
@ -148,12 +184,23 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
}); });
} // changing multi-user settings connection && 'PostgreSQL using multi-user settings' is selected && } // changing multi-user settings connection && 'PostgreSQL using multi-user settings' is selected &&
// central repo either enabled or was disabled due to error // central repo either enabled or was disabled due to error
else if (muPreviouslySelected && muCurrentlySelected && crMultiUser && (crEnabled || crDisabledDueToFailure)) { else if (muPreviouslySelected && muCurrentlySelected && crEnabled && crMultiUser) {
// test databse for CR change GlobalSettingsPanel.propertyChangeSupport.firePropertyChange("multiuserSettingsChanged", null, null);
CentralRepoDbUtil.setUseCentralRepo(true); checkStatusAndCreateDb(parent);
handleDbChange(parent);
} }
} }
/**
* Checks the status of current connectivity for CR and reports any issues. Will also prompt user to create
* database if cr database is absent.
* @param parent the parent component to which the dialogs will be associated.
*/
private static void checkStatusAndCreateDb(Component parent) {
SwingUtilities.invokeLater(() -> {
EamDbSettingsDialog.testStatusAndCreate(parent, new CentralRepoDbManager());
});
}
/** /**
* This method is called when a user must select a new database other than * This method is called when a user must select a new database other than
@ -165,28 +212,27 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
@NbBundle.Messages({ @NbBundle.Messages({
"GlobalSettingsPanel.onMultiUserChange.disabledMu.title=Central Repository Change Necessary", "GlobalSettingsPanel.onMultiUserChange.disabledMu.title=Central Repository Change Necessary",
"GlobalSettingsPanel.onMultiUserChange.disabledMu.description=The Central Repository will be reconfigured to use a local SQLite database.", "GlobalSettingsPanel.onMultiUserChange.disabledMu.description=The Central Repository will be reconfigured to use a local SQLite database.",
"GlobalSettingsPanel.onMultiUserChange.disabledMu.description2=Press Configure PostgreSQL to change to a PostgreSQL database." "GlobalSettingsPanel.onMultiUserChange.disabledMu.description2=Press Configure PostgreSQL to change to a PostgreSQL database.",
"GlobalSettingsPanel.askForCentralRepoDbChoice.sqliteChoice.text=Use SQLite",
"GlobalSettingsPanel.askForCentralRepoDbChoice.customPostgrestChoice.text=Configure PostgreSQL",
"GlobalSettingsPanel.askForCentralRepoDbChoice.disableChoice.text=Disable Central Repository"
}) })
private static void askForCentralRepoDbChoice(Component parent) { private static void askForCentralRepoDbChoice(Component parent) {
// disable central repository until user makes choice
CentralRepoDbUtil.setUseCentralRepo(false);
CentralRepoDbManager.saveDbChoice(CentralRepoDbChoice.DISABLED, false);
Object[] options = { Object[] options = {
"Use SQLite", Bundle.GlobalSettingsPanel_askForCentralRepoDbChoice_sqliteChoice_text(),
"Configure PostgreSQL", Bundle.GlobalSettingsPanel_askForCentralRepoDbChoice_customPostgrestChoice_text(),
"Disable Central Repository" Bundle.GlobalSettingsPanel_askForCentralRepoDbChoice_disableChoice_text()
}; };
int result = JOptionPane.showOptionDialog( int result = JOptionPane.showOptionDialog(
parent, parent,
"<html><body>" "<html><body>"
+ "<div style='width: 400px;'>" + "<div style='width: 400px;'>"
+ "<p>" + NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.onMultiUserChange.disabledMu.description") + "</p>" + "<p>" + Bundle.GlobalSettingsPanel_onMultiUserChange_disabledMu_description() + "</p>"
+ "<p style='margin-top: 10px'>" + NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.onMultiUserChange.disabledMu.description2") + "</p>" + "<p style='margin-top: 10px'>" + Bundle.GlobalSettingsPanel_onMultiUserChange_disabledMu_description2() + "</p>"
+ "</div>" + "</div>"
+ "</body></html>", + "</body></html>",
NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.onMultiUserChange.disabledMu.title"), Bundle.GlobalSettingsPanel_onMultiUserChange_disabledMu_title(),
JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.YES_NO_CANCEL_OPTION,
JOptionPane.PLAIN_MESSAGE, JOptionPane.PLAIN_MESSAGE,
null, null,
@ -200,13 +246,55 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
invokeCrChoice(parent, CentralRepoDbChoice.POSTGRESQL_CUSTOM); invokeCrChoice(parent, CentralRepoDbChoice.POSTGRESQL_CUSTOM);
} }
} }
@NbBundle.Messages({
"GlobalSettingsPanel.testCurrentConfiguration.dbDoesNotExist.message=Database does not exist.",
})
private boolean testCurrentConfiguration() {
if (CentralRepoDbManager.getSavedDbChoice() == null ||
CentralRepoDbManager.getSavedDbChoice() == CentralRepoDbChoice.DISABLED ||
!CentralRepoDbUtil.allowUseOfCentralRepository())
return false;
CentralRepoDbManager manager = new CentralRepoDbManager();
DatabaseTestResult testResult = manager.testStatus();
// if database doesn't exist, prompt user to create database
if (testResult == DatabaseTestResult.DB_DOES_NOT_EXIST) {
boolean success = EamDbSettingsDialog.promptCreateDatabase(manager, null);
if (success)
testResult = DatabaseTestResult.TESTED_OK;
}
// display to the user the status
switch (testResult) {
case TESTED_OK: return showStatusOkay();
case DB_DOES_NOT_EXIST: return showStatusFail(Bundle.GlobalSettingsPanel_testCurrentConfiguration_dbDoesNotExist_message());
case SCHEMA_INVALID: return showStatusFail(Bundle.EamDbSettingsDialog_okButton_corruptDatabaseExists_message());
case CONNECTION_FAILED:
default:
return showStatusFail(Bundle.EamDbSettingsDialog_okButton_databaseConnectionFailed_message());
}
}
private static void handleDbChange(Component parent) { private boolean showStatusOkay() {
SwingUtilities.invokeLater(() -> { return setStatus(goodIcon, " ");
if (!EamDbSettingsDialog.testStatusAndCreate(parent, new CentralRepoDbManager())) { }
CentralRepoDbManager.disableDueToFailure();
} private boolean showStatusFail(String message) {
}); return setStatus(badIcon, message);
}
private void clearStatus() {
setStatus(null, " ");
}
private boolean setStatus(ImageIcon icon, String text) {
synchronized (testStatusLabel) {
testStatusLabel.setIcon(icon);
testStatusLabel.setText(text);
return true;
}
} }
/** /**
@ -230,6 +318,8 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
lbDbPlatformValue = new javax.swing.JLabel(); lbDbPlatformValue = new javax.swing.JLabel();
lbDbNameValue = new javax.swing.JLabel(); lbDbNameValue = new javax.swing.JLabel();
lbDbLocationValue = new javax.swing.JLabel(); lbDbLocationValue = new javax.swing.JLabel();
bnTestConfigure = new javax.swing.JButton();
testStatusLabel = new javax.swing.JLabel();
pnCorrelationProperties = new javax.swing.JPanel(); pnCorrelationProperties = new javax.swing.JPanel();
bnManageTypes = new javax.swing.JButton(); bnManageTypes = new javax.swing.JButton();
correlationPropertiesScrollPane = new javax.swing.JScrollPane(); correlationPropertiesScrollPane = new javax.swing.JScrollPane();
@ -278,6 +368,20 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
} }
}); });
org.openide.awt.Mnemonics.setLocalizedText(bnTestConfigure, org.openide.util.NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.bnTestConfigure.text")); // NOI18N
bnTestConfigure.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
bnTestConfigureActionPerformed(evt);
}
});
testStatusLabel.setFont(testStatusLabel.getFont().deriveFont(testStatusLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11));
testStatusLabel.setForeground(new java.awt.Color(255, 0, 0));
org.openide.awt.Mnemonics.setLocalizedText(testStatusLabel, org.openide.util.NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.testStatusLabel.text")); // NOI18N
testStatusLabel.setToolTipText(org.openide.util.NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.testStatusLabel.toolTipText")); // NOI18N
testStatusLabel.setMaximumSize(new java.awt.Dimension(387, 16));
testStatusLabel.setPreferredSize(new java.awt.Dimension(387, 16));
javax.swing.GroupLayout pnDatabaseConfigurationLayout = new javax.swing.GroupLayout(pnDatabaseConfiguration); javax.swing.GroupLayout pnDatabaseConfigurationLayout = new javax.swing.GroupLayout(pnDatabaseConfiguration);
pnDatabaseConfiguration.setLayout(pnDatabaseConfigurationLayout); pnDatabaseConfiguration.setLayout(pnDatabaseConfigurationLayout);
pnDatabaseConfigurationLayout.setHorizontalGroup( pnDatabaseConfigurationLayout.setHorizontalGroup(
@ -285,9 +389,6 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
.addGroup(pnDatabaseConfigurationLayout.createSequentialGroup() .addGroup(pnDatabaseConfigurationLayout.createSequentialGroup()
.addContainerGap() .addContainerGap()
.addGroup(pnDatabaseConfigurationLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(pnDatabaseConfigurationLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(pnDatabaseConfigurationLayout.createSequentialGroup()
.addComponent(bnDbConfigure)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addGroup(pnDatabaseConfigurationLayout.createSequentialGroup() .addGroup(pnDatabaseConfigurationLayout.createSequentialGroup()
.addGroup(pnDatabaseConfigurationLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) .addGroup(pnDatabaseConfigurationLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addComponent(lbDbPlatformTypeLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(lbDbPlatformTypeLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
@ -295,9 +396,18 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
.addComponent(lbDbLocationLabel)) .addComponent(lbDbLocationLabel))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(pnDatabaseConfigurationLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) .addGroup(pnDatabaseConfigurationLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(lbDbNameValue, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 936, Short.MAX_VALUE) .addComponent(lbDbNameValue, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(lbDbPlatformValue, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(lbDbPlatformValue, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(lbDbLocationValue, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))))) .addGroup(javax.swing.GroupLayout.Alignment.LEADING, pnDatabaseConfigurationLayout.createSequentialGroup()
.addComponent(lbDbLocationValue, javax.swing.GroupLayout.DEFAULT_SIZE, 255, Short.MAX_VALUE)
.addGap(681, 681, 681))))
.addGroup(pnDatabaseConfigurationLayout.createSequentialGroup()
.addComponent(bnDbConfigure)
.addGap(18, 18, 18)
.addComponent(bnTestConfigure)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(testStatusLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 675, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))))
); );
pnDatabaseConfigurationLayout.setVerticalGroup( pnDatabaseConfigurationLayout.setVerticalGroup(
pnDatabaseConfigurationLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) pnDatabaseConfigurationLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
@ -315,7 +425,11 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
.addComponent(lbDbLocationLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(lbDbLocationLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(lbDbLocationValue, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE)) .addComponent(lbDbLocationValue, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(bnDbConfigure) .addGroup(pnDatabaseConfigurationLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(testStatusLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(pnDatabaseConfigurationLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(bnDbConfigure)
.addComponent(bnTestConfigure)))
.addGap(8, 8, 8)) .addGap(8, 8, 8))
); );
@ -359,7 +473,7 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
pnCorrelationPropertiesLayout.setVerticalGroup( pnCorrelationPropertiesLayout.setVerticalGroup(
pnCorrelationPropertiesLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) pnCorrelationPropertiesLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, pnCorrelationPropertiesLayout.createSequentialGroup() .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, pnCorrelationPropertiesLayout.createSequentialGroup()
.addComponent(correlationPropertiesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 28, Short.MAX_VALUE) .addComponent(correlationPropertiesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 24, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(bnManageTypes) .addComponent(bnManageTypes)
.addGap(8, 8, 8)) .addGap(8, 8, 8))
@ -472,7 +586,7 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
.addGroup(jPanel1Layout.createSequentialGroup() .addGroup(jPanel1Layout.createSequentialGroup()
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(pnDatabaseConfiguration, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(pnDatabaseConfiguration, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(pnCorrelationProperties, javax.swing.GroupLayout.DEFAULT_SIZE, 1010, Short.MAX_VALUE) .addComponent(pnCorrelationProperties, javax.swing.GroupLayout.DEFAULT_SIZE, 1016, Short.MAX_VALUE)
.addComponent(organizationPanel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(organizationPanel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(casesPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(casesPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(jPanel1Layout.createSequentialGroup() .addGroup(jPanel1Layout.createSequentialGroup()
@ -532,7 +646,6 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
boolean changed = invokeCrChoice(this, null); boolean changed = invokeCrChoice(this, null);
if (changed) { if (changed) {
load(); // reload db settings content and update buttons load(); // reload db settings content and update buttons
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
} }
}//GEN-LAST:event_bnDbConfigureActionPerformed }//GEN-LAST:event_bnDbConfigureActionPerformed
@ -549,20 +662,14 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
private void cbUseCentralRepoActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbUseCentralRepoActionPerformed private void cbUseCentralRepoActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbUseCentralRepoActionPerformed
//if saved setting is disabled checkbox should be disabled already //if saved setting is disabled checkbox should be disabled already
store(); store();
// if moving to using CR, multi-user mode is disabled and selection is multiuser settings, set to disabled
if (cbUseCentralRepo.isSelected()
&& !CentralRepoDbManager.isPostgresMultiuserAllowed()
&& CentralRepoDbManager.getSavedDbChoice() == CentralRepoDbChoice.POSTGRESQL_MULTIUSER) {
CentralRepoDbManager.saveDbChoice(CentralRepoDbChoice.DISABLED);
}
load(); load();
this.ingestStateUpdated(Case.isCaseOpen()); this.ingestStateUpdated(Case.isCaseOpen());
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}//GEN-LAST:event_cbUseCentralRepoActionPerformed }//GEN-LAST:event_cbUseCentralRepoActionPerformed
private void bnTestConfigureActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnTestConfigureActionPerformed
testCurrentConfiguration();
}//GEN-LAST:event_bnTestConfigureActionPerformed
@Override @Override
@Messages({"GlobalSettingsPanel.validationerrMsg.mustConfigure=Configure the database to enable this module."}) @Messages({"GlobalSettingsPanel.validationerrMsg.mustConfigure=Configure the database to enable this module."})
public void load() { public void load() {
@ -691,6 +798,8 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
enableDatabaseConfigureButton(cbUseCentralRepo.isSelected() && !caseIsOpen); enableDatabaseConfigureButton(cbUseCentralRepo.isSelected() && !caseIsOpen);
} }
/** /**
* Enable the Configure button * Enable the Configure button
@ -702,8 +811,10 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
private void enableDatabaseConfigureButton(Boolean enable) { private void enableDatabaseConfigureButton(Boolean enable) {
boolean ingestRunning = IngestManager.getInstance().isIngestRunning(); boolean ingestRunning = IngestManager.getInstance().isIngestRunning();
ingestRunningWarningLabel.setVisible(ingestRunning); ingestRunningWarningLabel.setVisible(ingestRunning);
pnDatabaseConfiguration.setEnabled(enable && !ingestRunning); pnDatabaseConfiguration.setEnabled(enable && !ingestRunning);
bnDbConfigure.setEnabled(enable && !ingestRunning); bnDbConfigure.setEnabled(enable && !ingestRunning);
bnTestConfigure.setEnabled(enable && !ingestRunning);
lbDbLocationLabel.setEnabled(enable && !ingestRunning); lbDbLocationLabel.setEnabled(enable && !ingestRunning);
lbDbLocationValue.setEnabled(enable && !ingestRunning); lbDbLocationValue.setEnabled(enable && !ingestRunning);
lbDbNameLabel.setEnabled(enable && !ingestRunning); lbDbNameLabel.setEnabled(enable && !ingestRunning);
@ -738,6 +849,7 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
// Variables declaration - do not modify//GEN-BEGIN:variables // Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton bnDbConfigure; private javax.swing.JButton bnDbConfigure;
private javax.swing.JButton bnManageTypes; private javax.swing.JButton bnManageTypes;
private javax.swing.JButton bnTestConfigure;
private javax.swing.JPanel casesPanel; private javax.swing.JPanel casesPanel;
private javax.swing.JScrollPane casesScrollPane; private javax.swing.JScrollPane casesScrollPane;
private javax.swing.JTextArea casesTextArea; private javax.swing.JTextArea casesTextArea;
@ -762,5 +874,6 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
private javax.swing.JPanel pnDatabaseConfiguration; private javax.swing.JPanel pnDatabaseConfiguration;
private javax.swing.JButton showCasesButton; private javax.swing.JButton showCasesButton;
private javax.swing.JTextField tbOops; private javax.swing.JTextField tbOops;
private javax.swing.JLabel testStatusLabel;
// End of variables declaration//GEN-END:variables // End of variables declaration//GEN-END:variables
} }

View File

@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.commonpropertiessearch;
import org.sleuthkit.autopsy.guiutils.DataSourceComboBoxModel; import org.sleuthkit.autopsy.guiutils.DataSourceComboBoxModel;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -119,6 +120,13 @@ public final class InterCasePanel extends javax.swing.JPanel {
this.correlationTypeFilters = new HashMap<>(); this.correlationTypeFilters = new HashMap<>();
try { try {
List<CorrelationAttributeInstance.Type> types = CentralRepository.getInstance().getDefinedCorrelationTypes(); List<CorrelationAttributeInstance.Type> types = CentralRepository.getInstance().getDefinedCorrelationTypes();
Collections.sort(types, new Comparator<CorrelationAttributeInstance.Type>() {
//The types should be sorted so that the File type is the first item in the combo box.
@Override
public int compare(CorrelationAttributeInstance.Type type1, CorrelationAttributeInstance.Type type2) {
return Integer.compare(type1.getId(), type2.getId());
}
});
for (CorrelationAttributeInstance.Type type : types) { for (CorrelationAttributeInstance.Type type : types) {
correlationTypeFilters.put(type.getDisplayName(), type); correlationTypeFilters.put(type.getDisplayName(), type);
this.correlationTypeComboBox.addItem(type.getDisplayName()); this.correlationTypeComboBox.addItem(type.getDisplayName());
@ -295,7 +303,7 @@ public final class InterCasePanel extends javax.swing.JPanel {
private void correlationTypeComboBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_correlationTypeComboBoxActionPerformed private void correlationTypeComboBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_correlationTypeComboBoxActionPerformed
boolean enableFileTypesFilter = this.correlationTypeComboBox.getSelectedItem().equals("Files"); boolean enableFileTypesFilter = this.correlationTypeComboBox.getSelectedItem().equals("Files");
categoriesLabel.setEnabled(enableFileTypesFilter); categoriesLabel.setEnabled(enableFileTypesFilter);
allFileCategoriesRadioButton.setEnabled(enableFileTypesFilter); allFileCategoriesRadioButton.setEnabled(enableFileTypesFilter);
selectedFileCategoriesButton.setEnabled(enableFileTypesFilter); selectedFileCategoriesButton.setEnabled(enableFileTypesFilter);
@ -329,8 +337,8 @@ public final class InterCasePanel extends javax.swing.JPanel {
// End of variables declaration//GEN-END:variables // End of variables declaration//GEN-END:variables
/** /**
* Get the map of cases which was used to populate the combo box on * Get the map of cases which was used to populate the combo box on this
* this panel. * panel.
* *
* @return an unmodifiable copy of the map of cases * @return an unmodifiable copy of the map of cases
*/ */
@ -339,8 +347,8 @@ public final class InterCasePanel extends javax.swing.JPanel {
} }
/** /**
* Set the datamodel for the combo box which displays the cases in * Set the datamodel for the combo box which displays the cases in the
* the central repository * central repository
* *
* @param dataSourceComboBoxModel the DataSourceComboBoxModel to use * @param dataSourceComboBoxModel the DataSourceComboBoxModel to use
*/ */

View File

@ -247,6 +247,8 @@ public class MessageViewer extends JPanel implements RelationshipsViewer {
*/ */
private void showMessagesPane() { private void showMessagesPane() {
switchCard("messages"); switchCard("messages");
Outline outline = rootTablePane.getOutlineView().getOutline();
outline.clearSelection();
} }
/** /**

View File

@ -198,7 +198,7 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data
startSection(html, "Central Repository Comments"); startSection(html, "Central Repository Comments");
List<CorrelationAttributeInstance> instancesList = new ArrayList<>(); List<CorrelationAttributeInstance> instancesList = new ArrayList<>();
if (artifact != null) { if (artifact != null) {
instancesList.addAll(CorrelationAttributeUtil.makeCorrAttrsFromArtifact(artifact)); instancesList.addAll(CorrelationAttributeUtil.makeCorrAttrsForCorrelation(artifact));
} }
try { try {
List<CorrelationAttributeInstance.Type> artifactTypes = CentralRepository.getInstance().getDefinedCorrelationTypes(); List<CorrelationAttributeInstance.Type> artifactTypes = CentralRepository.getInstance().getDefinedCorrelationTypes();

View File

@ -77,9 +77,9 @@ DataResultViewerThumbnail.switchPage.done.errMsg=Error making thumbnails: {0}
AboutWindowPanel.actVerboseLogging.text=Activate verbose logging AboutWindowPanel.actVerboseLogging.text=Activate verbose logging
OptionsCategory_Name_Multi_User_Settings=Multi-User OptionsCategory_Name_Multi_User_Settings=Multi-User
OptionsCategory_Keywords_Multi_User_Options=Multi-User Settings OptionsCategory_Keywords_Multi_User_Options=Multi-User Settings
MultiUserSettingsPanel.lbSolrSettings.text=Solr Settings MultiUserSettingsPanel.lbSolrSettings.text=Solr Server Settings
MultiUserSettingsPanel.cbEnableMultiUser.text=Enable multi-user cases MultiUserSettingsPanel.cbEnableMultiUser.text=Enable multi-user cases
MultiUserSettingsPanel.lbDatabaseSettings.text=Database Settings MultiUserSettingsPanel.lbDatabaseSettings.text=Database Server Settings
MultiUserSettingsPanel.validationErrMsg.incomplete=Fill in all values MultiUserSettingsPanel.validationErrMsg.incomplete=Fill in all values
MultiUserSettingsPanel.nonWindowsOs.msg=Multi-user cases are only available on Windows platforms MultiUserSettingsPanel.nonWindowsOs.msg=Multi-user cases are only available on Windows platforms
MultiUserSettingsPanel.validationErrMsg.invalidDatabasePort=Invalid database port number MultiUserSettingsPanel.validationErrMsg.invalidDatabasePort=Invalid database port number
@ -107,7 +107,7 @@ MultiUserSettingsPanel.tbSolrHostname.toolTipText=Hostname or IP Address
MultiUserSettingsPanel.tbSolrPort.toolTipText=Port Number MultiUserSettingsPanel.tbSolrPort.toolTipText=Port Number
MultiUserSettingsPanel.lbTestMessageService.text= MultiUserSettingsPanel.lbTestMessageService.text=
MultiUserSettingsPanel.bnTestMessageService.text=Test MultiUserSettingsPanel.bnTestMessageService.text=Test
MultiUserSettingsPanel.lbMessageServiceSettings.text=ActiveMQ Message Service Settings MultiUserSettingsPanel.lbMessageServiceSettings.text=ActiveMQ Message Server Settings
MultiUserSettingsPanel.tbMsgPort.toolTipText=Port Number MultiUserSettingsPanel.tbMsgPort.toolTipText=Port Number
MultiUserSettingsPanel.tbMsgPort.text= MultiUserSettingsPanel.tbMsgPort.text=
MultiUserSettingsPanel.tbMsgUsername.toolTipText=User Name (optional) MultiUserSettingsPanel.tbMsgUsername.toolTipText=User Name (optional)

View File

@ -97,7 +97,7 @@ class GetSCOTask implements Runnable {
logger.log(Level.WARNING, "Unable to get correlation type or value to determine value for O column for artifact", ex); logger.log(Level.WARNING, "Unable to get correlation type or value to determine value for O column for artifact", ex);
} }
} else { } else {
List<CorrelationAttributeInstance> listOfPossibleAttributes = CorrelationAttributeUtil.makeCorrAttrsFromArtifact(bbArtifact); List<CorrelationAttributeInstance> listOfPossibleAttributes = CorrelationAttributeUtil.makeCorrAttrsForCorrelation(bbArtifact);
if (listOfPossibleAttributes.size() > 1) { if (listOfPossibleAttributes.size() > 1) {
//Don't display anything if there is more than 1 correlation property for an artifact but let the user know //Don't display anything if there is more than 1 correlation property for an artifact but let the user know
description = Bundle.GetSCOTask_occurrences_multipleProperties(); description = Bundle.GetSCOTask_occurrences_multipleProperties();

View File

@ -23,6 +23,10 @@ import com.google.common.cache.CacheBuilder;
import com.google.common.io.Files; import com.google.common.io.Files;
import java.awt.Image; import java.awt.Image;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException; import java.io.IOException;
import java.io.Reader; import java.io.Reader;
import java.nio.file.Paths; import java.nio.file.Paths;
@ -79,6 +83,9 @@ import org.sleuthkit.autopsy.textextractors.TextExtractor;
import org.sleuthkit.autopsy.textextractors.TextExtractorFactory; import org.sleuthkit.autopsy.textextractors.TextExtractorFactory;
import org.sleuthkit.autopsy.textsummarizer.TextSummarizer; import org.sleuthkit.autopsy.textsummarizer.TextSummarizer;
import org.sleuthkit.autopsy.textsummarizer.TextSummary; import org.sleuthkit.autopsy.textsummarizer.TextSummary;
import org.sleuthkit.autopsy.texttranslation.NoServiceProviderException;
import org.sleuthkit.autopsy.texttranslation.TextTranslationService;
import org.sleuthkit.autopsy.texttranslation.TranslationException;
/** /**
* Main class to perform the file search. * Main class to perform the file search.
@ -304,9 +311,113 @@ class FileSearch {
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
logger.log(Level.WARNING, "Error getting children for file: " + file.getId(), ex); logger.log(Level.WARNING, "Error getting children for file: " + file.getId(), ex);
} }
image = image == null ? image : image.getScaledInstance(ImageUtils.ICON_SIZE_MEDIUM, ImageUtils.ICON_SIZE_MEDIUM, image = image == null ? image : image.getScaledInstance(ImageUtils.ICON_SIZE_MEDIUM, ImageUtils.ICON_SIZE_MEDIUM,
Image.SCALE_SMOOTH); Image.SCALE_SMOOTH);
return new TextSummary(getFirstLines(file), image, countOfImages); String summaryText = null;
if (file.getMd5Hash() != null) {
try {
summaryText = getSavedSummary(Paths.get(Case.getCurrentCaseThrows().getCacheDirectory(), "summaries", file.getMd5Hash() + "-default-" + PREVIEW_SIZE + "-translated.txt").toString());
} catch (NoCurrentCaseException ex) {
logger.log(Level.WARNING, "Unable to retrieve saved summary. No case is open.", ex);
}
}
if (StringUtils.isBlank(summaryText)) {
String firstLines = getFirstLines(file);
String translatedFirstLines = getTranslatedVersion(firstLines);
if (!StringUtils.isBlank(translatedFirstLines)) {
summaryText = translatedFirstLines;
if (file.getMd5Hash() != null) {
try {
saveSummary(summaryText, Paths.get(Case.getCurrentCaseThrows().getCacheDirectory(), "summaries", file.getMd5Hash() + "-default-" + PREVIEW_SIZE + "-translated.txt").toString());
} catch (NoCurrentCaseException ex) {
logger.log(Level.WARNING, "Unable to save translated summary. No case is open.", ex);
}
}
} else {
summaryText = firstLines;
}
}
return new TextSummary(summaryText, image, countOfImages);
}
/**
* Provide an English version of the specified String if it is not English,
* translation is enabled, and it can be translated.
*
* @param documentString The String to provide an English version of.
*
* @return The English version of the provided String, or null if no
* translation occurred.
*/
private static String getTranslatedVersion(String documentString) {
try {
TextTranslationService translatorInstance = TextTranslationService.getInstance();
if (translatorInstance.hasProvider()) {
String translatedResult = translatorInstance.translate(documentString);
if (translatedResult.isEmpty() == false) {
return translatedResult;
}
}
} catch (NoServiceProviderException | TranslationException ex) {
logger.log(Level.INFO, "Error translating string for summary", ex);
}
return null;
}
/**
* Find and load a saved summary from the case folder for the specified
* file.
*
* @param summarySavePath The full path for the saved summary file.
*
* @return The summary found given the specified path, null if no summary
* was found.
*/
private static String getSavedSummary(String summarySavePath) {
if (summarySavePath == null) {
return null;
}
File savedFile = new File(summarySavePath);
if (savedFile.exists()) {
try (BufferedReader bReader = new BufferedReader(new FileReader(savedFile))) {
// pass the path to the file as a parameter
StringBuilder sBuilder = new StringBuilder();
String sCurrentLine = bReader.readLine();
while (sCurrentLine != null) {
sBuilder.append(sCurrentLine).append('\n');
sCurrentLine = bReader.readLine();
}
return sBuilder.toString();
} catch (IOException ingored) {
//summary file may not exist or may be incomplete in which case return null so a summary can be generated
return null; //no saved summary was able to be found
}
} else {
try { //if the file didn't exist make sure the parent directories exist before we move on to creating a summary
Files.createParentDirs(savedFile);
} catch (IOException ex) {
logger.log(Level.WARNING, "Unable to create summaries directory in case folder for file at: " + summarySavePath, ex);
}
return null; //no saved summary was able to be found
}
}
/**
* Save a summary at the specified location.
*
* @param summary The text of the summary being saved.
* @param summarySavePath The full path for the saved summary file.
*/
private static void saveSummary(String summary, String summarySavePath) {
if (summarySavePath == null) {
return; //can't save a summary if we don't have a path
}
try (FileWriter myWriter = new FileWriter(summarySavePath)) {
myWriter.write(summary);
} catch (IOException ex) {
logger.log(Level.WARNING, "Unable to save summary at: " + summarySavePath, ex);
}
} }
/** /**

View File

@ -310,7 +310,7 @@ final public class MapPanel extends javax.swing.JPanel {
void setZoom(int zoom) { void setZoom(int zoom) {
zoomChanging = true; zoomChanging = true;
mapViewer.setZoom(zoom); mapViewer.setZoom(zoom);
zoomSlider.setValue((zoomSlider.getMaximum() + zoomSlider.getMinimum()) - zoom); zoomSlider.setValue(zoom);
zoomChanging = false; zoomChanging = false;
} }
@ -572,6 +572,7 @@ final public class MapPanel extends javax.swing.JPanel {
zoomSlider.setOrientation(javax.swing.JSlider.VERTICAL); zoomSlider.setOrientation(javax.swing.JSlider.VERTICAL);
zoomSlider.setPaintTicks(true); zoomSlider.setPaintTicks(true);
zoomSlider.setSnapToTicks(true); zoomSlider.setSnapToTicks(true);
zoomSlider.setInverted(true);
zoomSlider.setMinimumSize(new java.awt.Dimension(35, 100)); zoomSlider.setMinimumSize(new java.awt.Dimension(35, 100));
zoomSlider.setOpaque(false); zoomSlider.setOpaque(false);
zoomSlider.setPreferredSize(new java.awt.Dimension(35, 190)); zoomSlider.setPreferredSize(new java.awt.Dimension(35, 190));

View File

@ -2,7 +2,7 @@
* *
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2019 Basis Technology Corp. * Copyright 2019-2020 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");
@ -25,9 +25,9 @@ import java.util.Map;
import org.openide.util.NbBundle.Messages; import org.openide.util.NbBundle.Messages;
import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.blackboardutils.attributes.TskGeoWaypointsUtil; import org.sleuthkit.datamodel.blackboardutils.attributes.BlackboardJsonAttrUtil;
import org.sleuthkit.datamodel.blackboardutils.attributes.TskGeoWaypointsUtil.GeoWaypointList.GeoWaypoint; import org.sleuthkit.datamodel.blackboardutils.attributes.BlackboardJsonAttrUtil.InvalidJsonException;
import org.sleuthkit.datamodel.blackboardutils.attributes.TskGeoWaypointsUtil.GeoWaypointList; import org.sleuthkit.datamodel.blackboardutils.attributes.GeoWaypoints;
/** /**
* A Route represents a TSK_GPS_ROUTE artifact which has a start and end point * A Route represents a TSK_GPS_ROUTE artifact which has a start and end point
@ -42,8 +42,6 @@ public class Route extends GeoPath {
// This list is not expected to change after construction so the // This list is not expected to change after construction so the
// constructor will take care of creating an unmodifiable List // constructor will take care of creating an unmodifiable List
private final List<Waypoint.Property> propertiesList; private final List<Waypoint.Property> propertiesList;
private static final TskGeoWaypointsUtil attributeUtil = new TskGeoWaypointsUtil();
/** /**
* Construct a route for the given artifact. * Construct a route for the given artifact.
@ -119,9 +117,13 @@ public class Route extends GeoPath {
} }
if (attribute != null) { if (attribute != null) {
GeoWaypointList waypoints = attributeUtil.fromAttribute(attribute); GeoWaypoints waypoints;
try {
for(GeoWaypoint waypoint: waypoints) { waypoints = BlackboardJsonAttrUtil.fromAttribute(attribute, GeoWaypoints.class);
} catch (InvalidJsonException ex) {
throw new GeoLocationDataException(String.format("Unable to parse waypoints in TSK_GEO_WAYPOINTS attribute (artifact object ID =%d)", artifact.getId()), ex);
}
for (GeoWaypoints.Waypoint waypoint : waypoints) {
addToPath(new Waypoint(artifact, label, null, waypoint.getLatitude(), waypoint.getLongitude(), waypoint.getAltitude(), null, attributeMap, this)); addToPath(new Waypoint(artifact, label, null, waypoint.getLatitude(), waypoint.getLongitude(), waypoint.getAltitude(), null, attributeMap, this));
} }
} else { } else {

View File

@ -1,5 +1,4 @@
/* /*
*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2020 Basis Technology Corp. * Copyright 2020 Basis Technology Corp.
@ -26,26 +25,24 @@ import java.util.Map;
import org.openide.util.NbBundle.Messages; import org.openide.util.NbBundle.Messages;
import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.blackboardutils.attributes.TskGeoTrackpointsUtil; import org.sleuthkit.datamodel.blackboardutils.attributes.BlackboardJsonAttrUtil;
import org.sleuthkit.datamodel.blackboardutils.attributes.TskGeoTrackpointsUtil.GeoTrackPointList; import org.sleuthkit.datamodel.blackboardutils.attributes.BlackboardJsonAttrUtil.InvalidJsonException;
import org.sleuthkit.datamodel.blackboardutils.attributes.TskGeoTrackpointsUtil.GeoTrackPointList.GeoTrackPoint; import org.sleuthkit.datamodel.blackboardutils.attributes.GeoTrackPoints;
/** /**
* A GPS track with which wraps the TSK_GPS_TRACK artifact. * A GPS track with which wraps the TSK_GPS_TRACK artifact.
*/ */
public final class Track extends GeoPath{ public final class Track extends GeoPath {
private final Long startTimestamp; private final Long startTimestamp;
private final Long endTimeStamp; private final Long endTimeStamp;
private static final TskGeoTrackpointsUtil attributeUtil = new TskGeoTrackpointsUtil();
/** /**
* Construct a new Track for the given artifact. * Construct a new Track for the given artifact.
* *
* @param artifact * @param artifact
* *
* @throws GeoLocationDataException * @throws GeoLocationDataException
*/ */
public Track(BlackboardArtifact artifact) throws GeoLocationDataException { public Track(BlackboardArtifact artifact) throws GeoLocationDataException {
this(artifact, Waypoint.getAttributesFromArtifactAsMap(artifact)); this(artifact, Waypoint.getAttributesFromArtifactAsMap(artifact));
@ -53,49 +50,49 @@ public final class Track extends GeoPath{
/** /**
* Construct a Track for the given artifact and attributeMap. * Construct a Track for the given artifact and attributeMap.
* *
* @param artifact TSK_GPD_TRACK artifact * @param artifact TSK_GPD_TRACK artifact
* @param attributeMap Map of the artifact attributes * @param attributeMap Map of the artifact attributes
* *
* @throws GeoLocationDataException * @throws GeoLocationDataException
*/ */
private Track(BlackboardArtifact artifact, Map<BlackboardAttribute.ATTRIBUTE_TYPE, BlackboardAttribute> attributeMap) throws GeoLocationDataException { private Track(BlackboardArtifact artifact, Map<BlackboardAttribute.ATTRIBUTE_TYPE, BlackboardAttribute> attributeMap) throws GeoLocationDataException {
super(artifact, getTrackName(attributeMap)); super(artifact, getTrackName(attributeMap));
GeoTrackPointList points = getPointsList(attributeMap); GeoTrackPoints points = getPointsList(attributeMap);
buildPath(points, artifact); buildPath(points, artifact);
startTimestamp = points.getStartTime(); startTimestamp = points.getStartTime();
endTimeStamp = points.getEndTime(); endTimeStamp = points.getEndTime();
} }
/** /**
* Returns the start time of this track. * Returns the start time of this track.
* *
* @return Earliest time, or null if none was available. * @return Earliest time, or null if none was available. (seconds from java
* (seconds from java epoch) * epoch)
*/ */
public Long getStartTime() { public Long getStartTime() {
return startTimestamp; return startTimestamp;
} }
/** /**
* Returns the end time of this track. * Returns the end time of this track.
* *
* @return Earliest timestamp, or null if none was available. * @return Earliest timestamp, or null if none was available. (seconds from
* (seconds from java epoch) * java epoch)
*/ */
public Long getEndTime() { public Long getEndTime() {
return endTimeStamp; return endTimeStamp;
} }
/** /**
* Return the name of the track from the attributeMap. * Return the name of the track from the attributeMap. Track name is stored
* Track name is stored in the attribute TSK_NAME * in the attribute TSK_NAME
* *
* @param attributeMap * @param attributeMap
*
* @return Track name or empty string if none was available. * @return Track name or empty string if none was available.
*/ */
private static String getTrackName(Map<BlackboardAttribute.ATTRIBUTE_TYPE, BlackboardAttribute> attributeMap) { private static String getTrackName(Map<BlackboardAttribute.ATTRIBUTE_TYPE, BlackboardAttribute> attributeMap) {
BlackboardAttribute attribute = attributeMap.get(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME); BlackboardAttribute attribute = attributeMap.get(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME);
@ -105,38 +102,41 @@ public final class Track extends GeoPath{
/** /**
* Create the list of TrackWaypoints from the GeoTrackPoint list. * Create the list of TrackWaypoints from the GeoTrackPoint list.
* *
* @param points List of GeoTrackPoints * @param points GeoTrackPoints object.
*
* @param artifact The artifact to which these points belong * @param artifact The artifact to which these points belong
* *
* @throws GeoLocationDataException * @throws GeoLocationDataException
*/ */
@Messages({ @Messages({
"# {0} - track name", "# {0} - track name",
"GEOTrack_point_label_header=Trackpoint for track: {0}" "GEOTrack_point_label_header=Trackpoint for track: {0}"
}) })
private void buildPath(GeoTrackPointList points, BlackboardArtifact artifact) private void buildPath(GeoTrackPoints points, BlackboardArtifact artifact) throws GeoLocationDataException {
throws GeoLocationDataException { for (GeoTrackPoints.TrackPoint point : points) {
for(GeoTrackPoint point: points) {
addToPath(new TrackWaypoint(artifact, Bundle.GEOTrack_point_label_header(getLabel()), point)); addToPath(new TrackWaypoint(artifact, Bundle.GEOTrack_point_label_header(getLabel()), point));
} }
} }
/** /**
* Returns the list of GeoTrackPoints from the attributeMap. Creates the * Returns the list of GeoTrackPoints from the attributeMap. Creates the
* GeoTrackPoint list from the TSK_GEO_TRACKPOINTS attribute. * GeoTrackPoint list from the TSK_GEO_TRACKPOINTS attribute.
* *
* @param attributeMap Map of artifact attributes. * @param attributeMap Map of artifact attributes.
* *
* @return GeoTrackPoint list empty list if the attribute was not found. * @return GeoTrackPoint list empty list if the attribute was not found.
*
* @throws GeoLocationDataException
*/ */
private GeoTrackPointList getPointsList(Map<BlackboardAttribute.ATTRIBUTE_TYPE, BlackboardAttribute> attributeMap) { private GeoTrackPoints getPointsList(Map<BlackboardAttribute.ATTRIBUTE_TYPE, BlackboardAttribute> attributeMap) throws GeoLocationDataException {
BlackboardAttribute attribute = attributeMap.get(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_TRACKPOINTS); BlackboardAttribute attribute = attributeMap.get(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_TRACKPOINTS);
if (attribute != null) { if (attribute != null) {
return attributeUtil.fromAttribute(attribute); try {
return BlackboardJsonAttrUtil.fromAttribute(attribute, GeoTrackPoints.class);
} catch (InvalidJsonException ex) {
throw new GeoLocationDataException("Unable to parse track points in TSK_GEO_TRACKPOINTS attribute", ex);
}
} }
return null; return null;
} }
@ -149,16 +149,16 @@ public final class Track extends GeoPath{
/** /**
* Construct a TrackWaypoint. * Construct a TrackWaypoint.
* *
* @param artifact the artifact to which this waypoint belongs * @param artifact the artifact to which this waypoint belongs
* *
* @param pointLabel the label for the waypoint * @param pointLabel the label for the waypoint
* *
* @param point GeoTrackPoint * @param point GeoTrackPoint
* *
* @throws GeoLocationDataException * @throws GeoLocationDataException
*/ */
TrackWaypoint(BlackboardArtifact artifact, String pointLabel, GeoTrackPoint point) throws GeoLocationDataException { TrackWaypoint(BlackboardArtifact artifact, String pointLabel, GeoTrackPoints.TrackPoint point) throws GeoLocationDataException {
super(artifact, pointLabel, super(artifact, pointLabel,
point.getTimeStamp(), point.getTimeStamp(),
point.getLatitude(), point.getLatitude(),
@ -172,10 +172,10 @@ public final class Track extends GeoPath{
} }
/** /**
* Overloaded to return a property list that is generated from * Overloaded to return a property list that is generated from the
* the GeoTrackPoint instead of an artifact. * GeoTrackPoint instead of an artifact.
* *
* @return unmodifiable list of Waypoint.Property * @return unmodifiable list of Waypoint.Property
*/ */
@Override @Override
public List<Waypoint.Property> getOtherProperties() { public List<Waypoint.Property> getOtherProperties() {
@ -184,16 +184,16 @@ public final class Track extends GeoPath{
/** /**
* Create a propertyList specific to GeoTrackPoints. * Create a propertyList specific to GeoTrackPoints.
* *
* @param point GeoTrackPoint to get values from. * @param point GeoTrackPoint to get values from.
* *
* @return A list of Waypoint.properies. * @return A list of Waypoint.properies.
*/ */
@Messages({ @Messages({
"Track_distanceTraveled_displayName=Distance traveled", "Track_distanceTraveled_displayName=Distance traveled",
"Track_distanceFromHome_displayName=Distance from home point" "Track_distanceFromHome_displayName=Distance from home point"
}) })
private List<Waypoint.Property> createPropertyList(GeoTrackPoint point) { private List<Waypoint.Property> createPropertyList(GeoTrackPoints.TrackPoint point) {
List<Waypoint.Property> list = new ArrayList<>(); List<Waypoint.Property> list = new ArrayList<>();
Long timestamp = point.getTimeStamp(); Long timestamp = point.getTimeStamp();

View File

@ -41,11 +41,11 @@ import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProgress;
import org.sleuthkit.autopsy.ingest.IngestJobContext; import org.sleuthkit.autopsy.ingest.IngestJobContext;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.blackboardutils.attributes.TskGeoTrackpointsUtil.GeoTrackPointList.GeoTrackPoint;
import org.sleuthkit.datamodel.blackboardutils.GeoArtifactsHelper; import org.sleuthkit.datamodel.blackboardutils.GeoArtifactsHelper;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.Blackboard.BlackboardException; import org.sleuthkit.datamodel.Blackboard.BlackboardException;
import org.sleuthkit.datamodel.blackboardutils.attributes.TskGeoTrackpointsUtil.GeoTrackPointList; import org.sleuthkit.datamodel.blackboardutils.attributes.GeoTrackPoints;
import org.sleuthkit.datamodel.blackboardutils.attributes.GeoTrackPoints.TrackPoint;
/** /**
* Extract drone position data from DJI Phantom drones. * Extract drone position data from DJI Phantom drones.
@ -111,7 +111,7 @@ final class DATExtractor extends DroneExtractor {
} }
// Process the csv file // Process the csv file
GeoTrackPointList trackPoints = processCSVFile(context, DATFile, csvFilePath); GeoTrackPoints trackPoints = processCSVFile(context, DATFile, csvFilePath);
if (trackPoints != null && !trackPoints.isEmpty()) { if (trackPoints != null && !trackPoints.isEmpty()) {
(new GeoArtifactsHelper(getSleuthkitCase(), getName(), "DatCon", DATFile)).addTrack(DATFile.getName(), trackPoints, null); (new GeoArtifactsHelper(getSleuthkitCase(), getName(), "DatCon", DATFile)).addTrack(DATFile.getName(), trackPoints, null);
@ -188,8 +188,8 @@ final class DATExtractor extends DroneExtractor {
* *
* @throws DroneIngestException * @throws DroneIngestException
*/ */
private GeoTrackPointList processCSVFile(IngestJobContext context, AbstractFile DATFile, String csvFilePath) throws DroneIngestException { private GeoTrackPoints processCSVFile(IngestJobContext context, AbstractFile DATFile, String csvFilePath) throws DroneIngestException {
GeoTrackPointList trackPoints = new GeoTrackPointList(); GeoTrackPoints trackPoints = new GeoTrackPoints();
try (BufferedReader reader = new BufferedReader(new FileReader(new File(csvFilePath)))) { try (BufferedReader reader = new BufferedReader(new FileReader(new File(csvFilePath)))) {
// First read in the header line and process // First read in the header line and process
String line = reader.readLine(); String line = reader.readLine();
@ -201,7 +201,7 @@ final class DATExtractor extends DroneExtractor {
} }
String[] values = line.split(","); //NON-NLS String[] values = line.split(","); //NON-NLS
GeoTrackPoint point = createTrackPoint(headerMap, values); TrackPoint point = createTrackPoint(headerMap, values);
if (point != null) { if (point != null) {
trackPoints.addPoint(point); trackPoints.addPoint(point);
} }
@ -246,7 +246,7 @@ final class DATExtractor extends DroneExtractor {
* *
* @throws DroneIngestException * @throws DroneIngestException
*/ */
private GeoTrackPoint createTrackPoint(Map<String, Integer> columnLookup, String[] values) throws DroneIngestException { private TrackPoint createTrackPoint(Map<String, Integer> columnLookup, String[] values) throws DroneIngestException {
Double latitude = getDoubleValue(columnLookup.get(HEADER_LAT), values); Double latitude = getDoubleValue(columnLookup.get(HEADER_LAT), values);
Double longitude = getDoubleValue(columnLookup.get(HEADER_LONG), values); Double longitude = getDoubleValue(columnLookup.get(HEADER_LONG), values);
@ -256,7 +256,7 @@ final class DATExtractor extends DroneExtractor {
return null; return null;
} }
return new GeoTrackPoint(latitude, return new TrackPoint(latitude,
longitude, longitude,
getDoubleValue(columnLookup.get(HEADER_ALTITUDE), values), getDoubleValue(columnLookup.get(HEADER_ALTITUDE), values),
null, null,

View File

@ -52,6 +52,7 @@ import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.CentralRepoHashS
import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb.KnownFilesType; import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb.KnownFilesType;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb;
import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.SetEvt;
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository;
/** /**
@ -94,6 +95,17 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan
} }
} }
}); });
HashDbManager.getInstance().addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
String propName = evt.getPropertyName();
if(propName.equals(SetEvt.DB_ADDED.toString()) ||
propName.equals(SetEvt.DB_DELETED.toString())) {
hashSetTableModel.refreshModel();
}
}
});
} }
@NbBundle.Messages({"HashLookupSettingsPanel.Title=Global Hash Lookup Settings"}) @NbBundle.Messages({"HashLookupSettingsPanel.Title=Global Hash Lookup Settings"})

View File

@ -59,7 +59,7 @@ import org.sleuthkit.autopsy.report.ReportModule;
@ActionReferences(value = { @ActionReferences(value = {
@ActionReference(path = "Menu/Tools", position = 301, separatorAfter = 399) @ActionReference(path = "Menu/Tools", position = 301, separatorAfter = 399)
, ,
@ActionReference(path = "Toolbars/Case", position = 107)}) @ActionReference(path = "Toolbars/Case", position = 106)})
public final class ReportWizardAction extends CallableSystemAction implements Presenter.Toolbar, ActionListener { public final class ReportWizardAction extends CallableSystemAction implements Presenter.Toolbar, ActionListener {
private static final Logger logger = Logger.getLogger(ReportWizardAction.class.getName()); private static final Logger logger = Logger.getLogger(ReportWizardAction.class.getName());

View File

@ -1,8 +1,8 @@
Manifest-Version: 1.0 Manifest-Version: 1.0
OpenIDE-Module: org.sleuthkit.autopsy.corelibs/3 OpenIDE-Module: org.sleuthkit.autopsy.corelibs/3
OpenIDE-Module-Implementation-Version: 6 OpenIDE-Module-Implementation-Version: 7
OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/corelibs/Bundle.properties OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/corelibs/Bundle.properties
OpenIDE-Module-Specification-Version: 1.3 OpenIDE-Module-Specification-Version: 1.4
AutoUpdate-Show-In-Client: true AutoUpdate-Show-In-Client: true
AutoUpdate-Essential-Module: true AutoUpdate-Essential-Module: true

View File

@ -135,7 +135,7 @@
<compile-dependency/> <compile-dependency/>
<run-dependency> <run-dependency>
<release-version>10</release-version> <release-version>10</release-version>
<specification-version>10.18</specification-version> <specification-version>10.19</specification-version>
</run-dependency> </run-dependency>
</dependency> </dependency>
<dependency> <dependency>
@ -144,7 +144,7 @@
<compile-dependency/> <compile-dependency/>
<run-dependency> <run-dependency>
<release-version>3</release-version> <release-version>3</release-version>
<specification-version>1.3</specification-version> <specification-version>1.4</specification-version>
</run-dependency> </run-dependency>
</dependency> </dependency>
<dependency> <dependency>

View File

@ -57,6 +57,7 @@ import org.sleuthkit.autopsy.ingest.IngestJobStartResult;
import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.ingest.IngestModuleError; import org.sleuthkit.autopsy.ingest.IngestModuleError;
import org.sleuthkit.autopsy.keywordsearchservice.KeywordSearchService; import org.sleuthkit.autopsy.keywordsearchservice.KeywordSearchService;
import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
/** /**
@ -83,6 +84,7 @@ class MultiUserTestTool {
"MultiUserTestTool.unableCreatFile=Unable to create a file in case output directory", "MultiUserTestTool.unableCreatFile=Unable to create a file in case output directory",
"MultiUserTestTool.unableAddFileAsDataSource=Unable to add test file as data source to case", "MultiUserTestTool.unableAddFileAsDataSource=Unable to add test file as data source to case",
"MultiUserTestTool.unableToReadTestFileFromDatabase=Unable to read test file info from case database", "MultiUserTestTool.unableToReadTestFileFromDatabase=Unable to read test file info from case database",
"MultiUserTestTool.unableToInitializeFilTypeDetector=Unable to initialize File Type Detector",
"MultiUserTestTool.unableToUpdateKWSIndex=Unable to write to Keyword Search index", "MultiUserTestTool.unableToUpdateKWSIndex=Unable to write to Keyword Search index",
"MultiUserTestTool.unableToRunIngest=Unable to run ingest on test data source", "MultiUserTestTool.unableToRunIngest=Unable to run ingest on test data source",
"MultiUserTestTool.unexpectedError=Unexpected error while performing Multi User test", "MultiUserTestTool.unexpectedError=Unexpected error while performing Multi User test",
@ -187,6 +189,16 @@ class MultiUserTestTool {
} }
AbstractFile file = listOfFiles.get(0); AbstractFile file = listOfFiles.get(0);
// Set MIME type of the test file (required to test indexing)
FileTypeDetector fileTypeDetector = null;
try {
fileTypeDetector = new FileTypeDetector();
} catch (FileTypeDetector.FileTypeDetectorInitException ex) {
return Bundle.MultiUserTestTool_unableToInitializeFilTypeDetector() + ". " + ex.getMessage();
}
String mimeType = fileTypeDetector.getMIMEType(file);
file.setMIMEType(mimeType);
// write to KWS index // write to KWS index
KeywordSearchService kwsService = Lookup.getDefault().lookup(KeywordSearchService.class); KeywordSearchService kwsService = Lookup.getDefault().lookup(KeywordSearchService.class);

View File

@ -127,7 +127,7 @@
<compile-dependency/> <compile-dependency/>
<run-dependency> <run-dependency>
<release-version>10</release-version> <release-version>10</release-version>
<specification-version>10.18</specification-version> <specification-version>10.19</specification-version>
</run-dependency> </run-dependency>
</dependency> </dependency>
<dependency> <dependency>
@ -136,7 +136,7 @@
<compile-dependency/> <compile-dependency/>
<run-dependency> <run-dependency>
<release-version>3</release-version> <release-version>3</release-version>
<specification-version>1.3</specification-version> <specification-version>1.4</specification-version>
</run-dependency> </run-dependency>
</dependency> </dependency>
</module-dependencies> </module-dependencies>

View File

@ -37,12 +37,10 @@ from org.sleuthkit.datamodel import BlackboardArtifact
from org.sleuthkit.datamodel import BlackboardAttribute from org.sleuthkit.datamodel import BlackboardAttribute
from org.sleuthkit.datamodel import TskCoreException from org.sleuthkit.datamodel import TskCoreException
from org.sleuthkit.datamodel.blackboardutils import GeoArtifactsHelper from org.sleuthkit.datamodel.blackboardutils import GeoArtifactsHelper
from org.sleuthkit.datamodel.blackboardutils.attributes import TskGeoWaypointsUtil from org.sleuthkit.datamodel.blackboardutils.attributes import GeoWaypoints
from org.sleuthkit.datamodel.blackboardutils.attributes.TskGeoWaypointsUtil import GeoWaypointList from org.sleuthkit.datamodel.blackboardutils.attributes.GeoWaypoints import Waypoint
from org.sleuthkit.datamodel.blackboardutils.attributes.TskGeoWaypointsUtil.GeoWaypointList import GeoWaypoint from org.sleuthkit.datamodel.blackboardutils.attributes import GeoTrackPoints
from org.sleuthkit.datamodel.blackboardutils.attributes import TskGeoTrackpointsUtil from org.sleuthkit.datamodel.blackboardutils.attributes.GeoTrackPoints import TrackPoint
from org.sleuthkit.datamodel.blackboardutils.attributes.TskGeoTrackpointsUtil import GeoTrackPointList
from org.sleuthkit.datamodel.blackboardutils.attributes.TskGeoTrackpointsUtil.GeoTrackPointList import GeoTrackPoint
from org.sleuthkit.autopsy.datamodel import ContentUtils from org.sleuthkit.autopsy.datamodel import ContentUtils
from org.sleuthkit.autopsy.ingest import IngestModule from org.sleuthkit.autopsy.ingest import IngestModule
from org.sleuthkit.autopsy.ingest.IngestModule import IngestModuleException from org.sleuthkit.autopsy.ingest.IngestModule import IngestModuleException
@ -166,7 +164,7 @@ class GPXParserDataSourceIngestModule(DataSourceIngestModule):
if self.writeDebugMsgs: self.log(Level.INFO, "Processing tracks from " + file.getUniquePath() + " (objID = " + str(file.getId()) + ")") if self.writeDebugMsgs: self.log(Level.INFO, "Processing tracks from " + file.getUniquePath() + " (objID = " + str(file.getId()) + ")")
for track in gpx.tracks: for track in gpx.tracks:
for segment in track.segments: for segment in track.segments:
geoPointList = TskGeoTrackpointsUtil.GeoTrackPointList() geoPointList = GeoTrackPoints()
for point in segment.points: for point in segment.points:
elevation = 0 elevation = 0
@ -180,7 +178,7 @@ class GPXParserDataSourceIngestModule(DataSourceIngestModule):
except Exception as e: except Exception as e:
self.log(Level.WARNING, "Error getting track timestamp from " + file.getUniquePath() + " (objID = " + str(file.getId()) + "):" + str(e)) self.log(Level.WARNING, "Error getting track timestamp from " + file.getUniquePath() + " (objID = " + str(file.getId()) + "):" + str(e))
geoPointList.addPoint(GeoTrackPoint(point.latitude, point.longitude, elevation, None, 0, 0, 0, timeStamp)) geoPointList.addPoint(TrackPoint(point.latitude, point.longitude, elevation, None, 0, 0, 0, timeStamp))
try: try:
geoArtifactHelper.addTrack("Track", geoPointList, None) geoArtifactHelper.addTrack("Track", geoPointList, None)
@ -213,13 +211,13 @@ class GPXParserDataSourceIngestModule(DataSourceIngestModule):
if self.writeDebugMsgs: self.log(Level.INFO, "Processing routes from " + file.getUniquePath() + " (objID = " + str(file.getId()) + ")") if self.writeDebugMsgs: self.log(Level.INFO, "Processing routes from " + file.getUniquePath() + " (objID = " + str(file.getId()) + ")")
for route in gpx.routes: for route in gpx.routes:
geoWaypointList = TskGeoWaypointsUtil.GeoWaypointList() geoWaypoints = GeoWaypoints()
for point in route.points: for point in route.points:
geoWaypointList.addPoint(GeoWaypoint(point.latitude, point.longitude, point.elevation, point.name)) geoWaypoints.addPoint(Waypoint(point.latitude, point.longitude, point.elevation, point.name))
try: try:
geoArtifactHelper.addRoute(None, None, geoWaypointList, None) geoArtifactHelper.addRoute(None, None, geoWaypoints, None)
except Blackboard.BlackboardException as e: except Blackboard.BlackboardException as e:
self.log("Error posting GPS route artifact for " + file.getUniquePath() + " (objID = " + str(file.getId()) + "):" + e.getMessage()) self.log("Error posting GPS route artifact for " + file.getUniquePath() + " (objID = " + str(file.getId()) + "):" + e.getMessage())
except TskCoreException as e: except TskCoreException as e:

View File

@ -103,10 +103,7 @@ class CallLogAnalyzer(general.AndroidComponentAnalyzer):
calleeId = None calleeId = None
timeStamp = resultSet.getLong("date") / 1000 timeStamp = resultSet.getLong("date") / 1000
number = resultSet.getString("number") number = resultSet.getString("number")
if not general.isValidPhoneNumer(number):
number = None
duration = resultSet.getLong("duration") # duration of call is in seconds duration = resultSet.getLong("duration") # duration of call is in seconds
name = resultSet.getString("name") # name of person dialed or called. None if unregistered name = resultSet.getString("name") # name of person dialed or called. None if unregistered

View File

@ -45,19 +45,15 @@ def appendAttachmentList(msgBody, attachmentsList):
""" """
Checks if the given string might be a phone number. Checks if the given string might be a phone number.
""" """
def isValidPhoneNumer(data): def isValidPhoneNumber(data):
try: return CommunicationsUtils.isValidPhoneNumber(data)
return CommunicationsUtils.normalizePhoneNum(data) is not None
except TskCoreException as ex:
return False
""" """
Checks if the given string is a valid email address. Checks if the given string is a valid email address.
""" """
def isValidEmailAddress(data): def isValidEmailAddress(data):
try: return CommunicationsUtils.isValidEmailAddress(data)
return CommunicationsUtils.normalizeEmailAddress(data) is not None
except TskCoreException as ex:
return False

View File

@ -43,8 +43,8 @@ from org.sleuthkit.datamodel import Content
from org.sleuthkit.datamodel import TskCoreException from org.sleuthkit.datamodel import TskCoreException
from org.sleuthkit.datamodel.Blackboard import BlackboardException from org.sleuthkit.datamodel.Blackboard import BlackboardException
from org.sleuthkit.datamodel.blackboardutils import GeoArtifactsHelper from org.sleuthkit.datamodel.blackboardutils import GeoArtifactsHelper
from org.sleuthkit.datamodel.blackboardutils.attributes.TskGeoWaypointsUtil import GeoWaypointList from org.sleuthkit.datamodel.blackboardutils.attributes import GeoWaypoints
from org.sleuthkit.datamodel.blackboardutils.attributes.TskGeoWaypointsUtil.GeoWaypointList import GeoWaypoint from org.sleuthkit.datamodel.blackboardutils.attributes.GeoWaypoints import Waypoint
import traceback import traceback
import general import general
@ -117,9 +117,9 @@ class GoogleMapLocationAnalyzer(general.AndroidComponentAnalyzer):
source_lat = GoogleMapLocationAnalyzer.convertGeo(resultSet.getString("source_lat")) source_lat = GoogleMapLocationAnalyzer.convertGeo(resultSet.getString("source_lat"))
source_lng = GoogleMapLocationAnalyzer.convertGeo(resultSet.getString("source_lng")) source_lng = GoogleMapLocationAnalyzer.convertGeo(resultSet.getString("source_lng"))
waypointlist = GeoWaypointList() waypointlist = GeoWaypoints()
waypointlist.addPoint(GeoWaypoint(source_lat, source_lng, None, None)) waypointlist.addPoint(Waypoint(source_lat, source_lng, None, None))
waypointlist.addPoint(GeoWaypoint(dest_lat, dest_lng, None, dest_address)) waypointlist.addPoint(Waypoint(dest_lat, dest_lng, None, dest_address))
artifactHelper.addRoute(dest_title, time, waypointlist, None) artifactHelper.addRoute(dest_title, time, waypointlist, None)

View File

@ -45,7 +45,8 @@ from org.sleuthkit.datamodel import Content
from org.sleuthkit.datamodel import TskCoreException from org.sleuthkit.datamodel import TskCoreException
from org.sleuthkit.datamodel.Blackboard import BlackboardException from org.sleuthkit.datamodel.Blackboard import BlackboardException
from org.sleuthkit.datamodel.blackboardutils import GeoArtifactsHelper from org.sleuthkit.datamodel.blackboardutils import GeoArtifactsHelper
from org.sleuthkit.datamodel.blackboardutils.attributes import TskGeoTrackpointsUtil from org.sleuthkit.datamodel.blackboardutils.attributes import GeoTrackPoints
from org.sleuthkit.datamodel.blackboardutils.attributes.GeoTrackPoints import TrackPoint
import traceback import traceback
import general import general
@ -139,14 +140,14 @@ class OruxMapsAnalyzer(general.AndroidComponentAnalyzer):
trackpointsQueryString = "SELECT trkptlat, trkptlon, trkptalt, trkpttime FROM trackpoints WHERE trkptseg = " + segmentId trackpointsQueryString = "SELECT trkptlat, trkptlon, trkptalt, trkpttime FROM trackpoints WHERE trkptseg = " + segmentId
trackpointsResultSet = oruxMapsTrackpointsDb.runQuery(trackpointsQueryString) trackpointsResultSet = oruxMapsTrackpointsDb.runQuery(trackpointsQueryString)
if trackpointsResultSet is not None: if trackpointsResultSet is not None:
geoPointList = TskGeoTrackpointsUtil.GeoTrackPointList() geoPointList = GeoTrackPoints()
while trackpointsResultSet.next(): while trackpointsResultSet.next():
latitude = trackpointsResultSet.getDouble("trkptlat") latitude = trackpointsResultSet.getDouble("trkptlat")
longitude = trackpointsResultSet.getDouble("trkptlon") longitude = trackpointsResultSet.getDouble("trkptlon")
altitude = trackpointsResultSet.getDouble("trkptalt") altitude = trackpointsResultSet.getDouble("trkptalt")
time = trackpointsResultSet.getLong("trkpttime") / 1000 # milliseconds since unix epoch time = trackpointsResultSet.getLong("trkpttime") / 1000 # milliseconds since unix epoch
geoPointList.addPoint(TskGeoTrackpointsUtil.GeoTrackPointList.GeoTrackPoint(latitude, longitude, altitude, segmentName, 0, 0, 0, time)) geoPointList.addPoint(TrackPoint(latitude, longitude, altitude, segmentName, 0, 0, 0, time))
try: try:
geoartifact = geoArtifactHelper.addTrack(segmentName, geoPointList, None) geoartifact = geoArtifactHelper.addTrack(segmentName, geoPointList, None)

View File

@ -286,7 +286,7 @@ class TextNowContactsParser(TskContactsParser):
def get_phone(self): def get_phone(self):
number = self.result_set.getString("number") number = self.result_set.getString("number")
return (number if general.isValidPhoneNumer(number) else None) return (number if general.isValidPhoneNumber(number) else None)
def get_email(self): def get_email(self):
# occasionally the 'number' column may have an email address instead # occasionally the 'number' column may have an email address instead

View File

@ -435,7 +435,7 @@ class WhatsAppContactsParser(TskContactsParser):
def get_phone(self): def get_phone(self):
number = self.result_set.getString("number") number = self.result_set.getString("number")
return (number if general.isValidPhoneNumer(number) else None) return (number if general.isValidPhoneNumber(number) else None)
def get_email(self): def get_email(self):
# occasionally the 'number' column may have an email address instead # occasionally the 'number' column may have an email address instead

View File

@ -119,7 +119,7 @@
<compile-dependency/> <compile-dependency/>
<run-dependency> <run-dependency>
<release-version>10</release-version> <release-version>10</release-version>
<specification-version>10.18</specification-version> <specification-version>10.19</specification-version>
</run-dependency> </run-dependency>
</dependency> </dependency>
<dependency> <dependency>
@ -128,7 +128,7 @@
<compile-dependency/> <compile-dependency/>
<run-dependency> <run-dependency>
<release-version>3</release-version> <release-version>3</release-version>
<specification-version>1.3</specification-version> <specification-version>1.4</specification-version>
</run-dependency> </run-dependency>
</dependency> </dependency>
</module-dependencies> </module-dependencies>

View File

@ -1,3 +1,32 @@
---------------- VERSION 4.15.0 --------------
New UI Features:
- Added Document view to File Discovery.
- Expanded Context Content Viewer to show if an app accessed a file.
- Added translation feature to Message Content Viewer.
- Added waypoint type filter to the Geolocation viewer.
- Added zoom feature to Indexed Text Content Viewer.
New Ingest Modules Features:
- New GPX ingest module.
- New Drone ingest module for DJI drones based on DatCon.
- Create artifacts for files opened by Adobe Reader, Windows Media Player, Office Docs (Most Recently Used (MRU) and TrustRecords), 7Zip MRU, WinRAR MRU, Applets, Microsoft Management Console (MMC) via RegRipper.
New Central Repository Features:
- Central Repository stores account IDs that were previously seen.
- Central Repository is enabled by default to store past hashes. Feature to flag previously seen files is disabled by default.
Other New Features:
- Multi-user cases can be created via command line
Bug fixes:
- Prevent entire application from crashing when gstreamer crashes on videos.
- Improve Geolocation viewer with large data sets.
- Fix error with non-sector aligned reads on local disks.
- Times from Recycle Bin files are now in timeline.
- Validate timeline events and ignore events too far in the future.
- Moved some database queries off of UI thread.
- Remove hard coded sizes from UI that cause issues with other languages.
---------------- VERSION 4.14.0 -------------- ---------------- VERSION 4.14.0 --------------
Specialized UIs: Specialized UIs:
- New File Discovery UI that allows you to search and filter for certain types of files. - New File Discovery UI that allows you to search and filter for certain types of files.

View File

@ -60,7 +60,7 @@
<compile-dependency/> <compile-dependency/>
<run-dependency> <run-dependency>
<release-version>10</release-version> <release-version>10</release-version>
<specification-version>10.18</specification-version> <specification-version>10.19</specification-version>
</run-dependency> </run-dependency>
</dependency> </dependency>
<dependency> <dependency>
@ -69,7 +69,7 @@
<compile-dependency/> <compile-dependency/>
<run-dependency> <run-dependency>
<release-version>3</release-version> <release-version>3</release-version>
<specification-version>1.3</specification-version> <specification-version>1.4</specification-version>
</run-dependency> </run-dependency>
</dependency> </dependency>
</module-dependencies> </module-dependencies>

View File

@ -47,7 +47,7 @@
<compile-dependency/> <compile-dependency/>
<run-dependency> <run-dependency>
<release-version>10</release-version> <release-version>10</release-version>
<specification-version>10.18</specification-version> <specification-version>10.19</specification-version>
</run-dependency> </run-dependency>
</dependency> </dependency>
<dependency> <dependency>

View File

@ -38,7 +38,7 @@ PROJECT_NAME = "Autopsy User Documentation"
# could be handy for archiving the generated documentation or if some version # could be handy for archiving the generated documentation or if some version
# control system is used. # control system is used.
PROJECT_NUMBER = 4.14.0 PROJECT_NUMBER = 4.15.0
# Using the PROJECT_BRIEF tag one can provide an optional one line description # Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a # for a project that appears at the top of each page and should give viewer a
@ -1025,7 +1025,7 @@ GENERATE_HTML = YES
# The default directory is: html. # The default directory is: html.
# This tag requires that the tag GENERATE_HTML is set to YES. # This tag requires that the tag GENERATE_HTML is set to YES.
HTML_OUTPUT = 4.14.0 HTML_OUTPUT = 4.15.0
# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each # The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
# generated HTML page (for example: .htm, .php, .asp). # generated HTML page (for example: .htm, .php, .asp).

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1017 B

After

Width:  |  Height:  |  Size: 9.5 KiB

View File

@ -8,14 +8,14 @@ ActiveMQ is a messaging service that allows the Autopsy clients to communicate w
\section install_activemq_prereq Prerequisites \section install_activemq_prereq Prerequisites
You will need: You will need:
- 64-bit version of the Java Runtime Environment (JRE) from http://www.oracle.com/technetwork/java/javase/downloads/jre8-downloads-2133155.html. - 64-bit version of the Java 8 Runtime Environment (JRE) from https://github.com/ojdkbuild/ojdkbuild (<a href="https://github.com/ojdkbuild/ojdkbuild/releases/download/java-1.8.0-openjdk-1.8.0.242-1.b08/java-1.8.0-openjdk-1.8.0.242-1.b08.ojdkbuild.windows.x86_64.msi"> Link to installer</a>)
- Download ActiveMQ from: http://activemq.apache.org/download.html . Autopsy has been tested with ActiveMQ version 5.14.0. - Download ActiveMQ from: http://activemq.apache.org/download.html . Autopsy has been tested with ActiveMQ version 5.14.0.
\section install_activemq_install Installation \section install_activemq_install Installation
\subsection install_activemq_install_java JRE Installation \subsection install_activemq_install_java JRE Installation
Install the Java JRE if needed. You can test this by running _where java_ from the command line. If you see output like the yellow results below, you have a JRE. Install the Java JRE if needed. You can test this by running _where java_ from the command line. If you see output similar to the results below, you have a JRE.
<br><br> <br><br>
\image html wherejava.PNG \image html wherejava.PNG
<br><br> <br><br>

View File

@ -13,7 +13,7 @@ Solr's embedded ZooKeeper is also used as a coordination service for Autopsy.
We use Bitnami Solr, which packages Solr as a Windows service. We use Bitnami Solr, which packages Solr as a Windows service.
You will need: You will need:
- A 64-bit version of the Java Runtime Environment (JRE) from http://www.oracle.com/technetwork/java/javase/downloads/jre8-downloads-2133155.html. - A 64-bit version of the Java 8 Runtime Environment (JRE) from https://github.com/ojdkbuild/ojdkbuild. (<a href="https://github.com/ojdkbuild/ojdkbuild/releases/download/java-1.8.0-openjdk-1.8.0.242-1.b08/java-1.8.0-openjdk-1.8.0.242-1.b08.ojdkbuild.windows.x86_64.msi"> Link to installer</a>)
- The Apache Solr 4.10.3-0 installation package. This is no longer available from its original source, but you can find it on our site: https://sourceforge.net/projects/autopsy/files/CollaborativeServices/Solr. - The Apache Solr 4.10.3-0 installation package. This is no longer available from its original source, but you can find it on our site: https://sourceforge.net/projects/autopsy/files/CollaborativeServices/Solr.
-- NOTE: We tested Solr 6 at one point, but ran into stability problems when loading and unloading cores. For now, you need to use Solr 4. -- NOTE: We tested Solr 6 at one point, but ran into stability problems when loading and unloading cores. For now, you need to use Solr 4.
- An installed version of Autopsy so that you can copy files from it. You can install Autopsy on one of the planned client systems. You do not need to install it on the Solr server. - An installed version of Autopsy so that you can copy files from it. You can install Autopsy on one of the planned client systems. You do not need to install it on the Solr server.
@ -24,7 +24,11 @@ You will need:
\section install_solr_install Installation \section install_solr_install Installation
\subsection install_solr_install_java JRE Installation \subsection install_solr_install_java JRE Installation
1. JREs are normally installed under "C:\Program Files\Java\jre(version)", so check there to see if you have one installed already. If not, get the installer as listed in the above Prerequisites section and install it with the default settings. 1. Install the Java JRE if needed. You can test this by running _where java_ from the command line. If you see output similar to the results below, you have a JRE.
<br><br>
\image html wherejava.PNG
<br><br>
If you need the JRE, install it with the default settings.
\subsection install_solr_install_solr Solr Installation \subsection install_solr_install_solr Solr Installation
@ -52,7 +56,7 @@ The following steps will configure Solr to run using an account that will have a
+ <i>++JvmOptions=-Dbootstrap_confdir="C:\Bitnami\solr-4.10.3-0\apache-solr\solr\configsets\AutopsyConfig\conf"</i> + <i>++JvmOptions=-Dbootstrap_confdir="C:\Bitnami\solr-4.10.3-0\apache-solr\solr\configsets\AutopsyConfig\conf"</i>
+ <i>++JvmOptions=-DzkRun </i> + <i>++JvmOptions=-DzkRun </i>
<br> <br>
- Replace the path to JavaHome with the path to your 64-bit version of the JRE. If you do not know the path, the correct JavaHome path can be obtained by running the command "where java" from the Windows command line. An example is shown below. The text in yellow is what we are interested in. Do not include the "bin" folder in the path you place into the JavaHome variable. A correct example of the final result will look something like this: <i>-JavaHome="C:\Program Files\Java\jre1.8.0_111"</i> - Replace the path to JavaHome with the path to your 64-bit version of the JRE. If you do not know the path, the correct JavaHome path can be obtained by running the command "where java" from the Windows command line. An example is shown below. The text in yellow is what we are interested in. Do not include the "bin" folder in the path you place into the JavaHome variable. A correct example of the final result will look something like this: <i>-JavaHome="C:\Program Files\ojdkbuild\java-1.8.0-openjdk-1.8.0.222-1"</i>
<br><br> <br><br>
A portion of an updated _serviceinstall.bat_ is shown below, with the changes marked in yellow. A portion of an updated _serviceinstall.bat_ is shown below, with the changes marked in yellow.
<br><br> <br><br>

View File

@ -38,7 +38,7 @@ PROJECT_NAME = "Autopsy"
# could be handy for archiving the generated documentation or if some version # could be handy for archiving the generated documentation or if some version
# control system is used. # control system is used.
PROJECT_NUMBER = 4.14.0 PROJECT_NUMBER = 4.15.0
# Using the PROJECT_BRIEF tag one can provide an optional one line description # Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears a the top of each page and should give viewer a # for a project that appears a the top of each page and should give viewer a
@ -1066,7 +1066,7 @@ GENERATE_HTML = YES
# The default directory is: html. # The default directory is: html.
# This tag requires that the tag GENERATE_HTML is set to YES. # This tag requires that the tag GENERATE_HTML is set to YES.
HTML_OUTPUT = api-docs/4.14.0/ HTML_OUTPUT = api-docs/4.15.0/
# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each # The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
# generated HTML page (for example: .htm, .php, .asp). # generated HTML page (for example: .htm, .php, .asp).

View File

@ -5,7 +5,7 @@ Report modules allow Autopsy users to create different report types. Autopsy co
All custom report modules will be general report modules. General report modules have a single method to generate the report. This method gives the module freedom to find and process any data it so chooses. General modules also have the ability to provide a configuration panel, allowing the user to choose from various displayed settings. The report module may then use the user's selection to generate a more specific report. All custom report modules will be general report modules. General report modules have a single method to generate the report. This method gives the module freedom to find and process any data it so chooses. General modules also have the ability to provide a configuration panel, allowing the user to choose from various displayed settings. The report module may then use the user's selection to generate a more specific report.
General modules are also given the responsibility of updating their report's progress bar and processing label in the UI. A progress panel is given to every general report module. It contains basic API to start, stop, and add to the progress bar, as well as update the processing label. The module is also expected to check the progress bar's status occasionally to see if the user has manually canceled the report. General modules are also given the responsibility of updating their report's progress bar and processing label in the UI. A progress panel is given to every general report module. It defines a basic API to start, stop, and increment the progress bar and to update the processing label. The module is also expected to check the progress bar's status occasionally to see if the user has manually canceled the report.
\section report_create_module Creating a Report Module \section report_create_module Creating a Report Module
To create a report module, start off by creating a new Java or Python (Jython) class and implementing (Java) or inheriting (Jython) from org.sleuthkit.autopsy.report.GeneralReportModule. You'll need to override multiple methods including the following: To create a report module, start off by creating a new Java or Python (Jython) class and implementing (Java) or inheriting (Jython) from org.sleuthkit.autopsy.report.GeneralReportModule. You'll need to override multiple methods including the following:
@ -17,11 +17,11 @@ To create a report module, start off by creating a new Java or Python (Jython) c
If your report module requires configuration, you'll need to override: If your report module requires configuration, you'll need to override:
- org.sleuthkit.autopsy.report.GeneralReportModule.getConfigurationPanel() - org.sleuthkit.autopsy.report.GeneralReportModule.getConfigurationPanel()
For general report modules, Autopsy will simply call the generateReport(String reportPath, ReportProgressPanel progressPanel) method and leave it up to the module to aquire and report data in its desired format. The only requirements are that the module saves to the given report path and updates the org.sleuthkit.autopsy.report.ReportProgressPanel as the report progresses. For general report modules, Autopsy will simply call the generateReport(String reportPath, ReportProgressPanel progressPanel) method and leave it up to the module to acquire and report data in its desired format. The only requirements are that the module saves to the given report path and updates the org.sleuthkit.autopsy.report.ReportProgressPanel as the report progresses.
When updating the progress panel, it is recommended to update it as infrequently as possible, while still keeping the user informed. If your report processes 100,000 files and you chose to update the UI each time a file is reviewed, the UI would freeze when trying to process all your requests. This would cause problems to not only your reporting module, but to other modules running in parallel. A safer approach would be to update the UI every 1,000 files, or when a certain "category" of the files being processed has changed. For example, the HTML report module increments the progress bar and changes the processing label every time a new Blackboard Artifact Type is being processed. When updating the progress panel, it is recommended to update it as infrequently as possible, while still keeping the user informed. If your report processes 100,000 files and you chose to update the UI each time a file is reviewed, the UI would freeze when trying to process all your requests. This would cause problems to not only your reporting module, but to other modules running in parallel. A safer approach would be to update the UI every 1,000 files, or when a certain "category" of the files being processed has changed. For example, the HTML report module increments the progress bar and changes the processing label every time a new Blackboard Artifact Type is being processed.
Autopsy will also display the panel returned by getConfigurationPanel() in the generate report wizard. This panel can be used to allow the user custom controls over the report. To make this panel, use NetBeans to make a new JPanel class and use its layout interface to put the UI widgets in the places that you want them. Then, your getConfigurationPanel() method should create an instance of that class and return it. Autopsy will also display the panel returned by getConfigurationPanel() in the generate report wizard. This panel can be used to allow the user to customize the report. To make this panel, use NetBeans to make a new JPanel class and use its layout interface to put the UI widgets in the places that you want them. Then, your getConfigurationPanel() method should create an instance of that class and return it.
Typically a general report module should interact with both the Blackboard API in the org.sleuthkit.datamodel.SleuthkitCase class, in addition to an API (possibly external/thirdparty) to convert Blackboard Artifacts to the desired reporting format. Typically a general report module should interact with both the Blackboard API in the org.sleuthkit.datamodel.SleuthkitCase class, in addition to an API (possibly external/thirdparty) to convert Blackboard Artifacts to the desired reporting format.
@ -32,7 +32,7 @@ You should call org.sleuthkit.autopsy.casemodule.Case.addReport() with the path
\subsection report_create_module_indexing Indexing Reports \subsection report_create_module_indexing Indexing Reports
After you have called org.sleuthkit.autopsy.casemodule.Case.addReport() and created a report, you can pass it to org.sleuthkit.autopsy.keywordsearchservice.KeywordSearchService.index() so that it is indexed and can then be found by a user. This is most commonly used when an Ingest Module runs a 3rd party tool and the output of that tool is added back into Autopsy as a report. Here is some example code: After you have called org.sleuthkit.autopsy.casemodule.Case.addReport() and created a report, you can pass it to org.sleuthkit.autopsy.keywordsearchservice.KeywordSearchService.index() so that the report text is indexed for keyword search. This is most commonly used when an Ingest Module runs a 3rd party tool and the output of that tool is added back into Autopsy as a report. Here is some example code:
\code{.java} \code{.java}
KeywordSearchService searchService = Lookup.getDefault().lookup(KeywordSearchService.class); KeywordSearchService searchService = Lookup.getDefault().lookup(KeywordSearchService.class);

View File

@ -4,10 +4,10 @@ app.title=Autopsy
### lowercase version of above ### lowercase version of above
app.name=${branding.token} app.name=${branding.token}
### if left unset, version will default to today's date ### if left unset, version will default to today's date
app.version=4.14.0 app.version=4.15.0
### build.type must be one of: DEVELOPMENT, RELEASE ### build.type must be one of: DEVELOPMENT, RELEASE
#build.type=RELEASE build.type=RELEASE
build.type=DEVELOPMENT #build.type=DEVELOPMENT
project.org.netbeans.progress=org-netbeans-api-progress project.org.netbeans.progress=org-netbeans-api-progress
project.org.sleuthkit.autopsy.experimental=Experimental project.org.sleuthkit.autopsy.experimental=Experimental

View File

@ -36,7 +36,7 @@
<compile-dependency/> <compile-dependency/>
<run-dependency> <run-dependency>
<release-version>10</release-version> <release-version>10</release-version>
<specification-version>10.18</specification-version> <specification-version>10.19</specification-version>
</run-dependency> </run-dependency>
</dependency> </dependency>
<dependency> <dependency>