diff --git a/Core/nbproject/project.properties b/Core/nbproject/project.properties index b6931ff315..905e6dac13 100755 --- a/Core/nbproject/project.properties +++ b/Core/nbproject/project.properties @@ -7,6 +7,7 @@ file.reference.jdom-2.0.5-contrib.jar=release/modules/ext/jdom-2.0.5-contrib.jar file.reference.jdom-2.0.5.jar=release/modules/ext/jdom-2.0.5.jar file.reference.jsoup-1.10.3.jar=release/modules/ext/jsoup-1.10.3.jar file.reference.jython-standalone-2.7.0.jar=release/modules/ext/jython-standalone-2.7.0.jar +file.reference.LGoodDatePicker-10.3.1.jar=release/modules/ext/LGoodDatePicker-10.3.1.jar file.reference.mchange-commons-java-0.2.9.jar=release/modules/ext/mchange-commons-java-0.2.9.jar file.reference.metadata-extractor-2.9.1.jar=release/modules/ext/metadata-extractor-2.9.1.jar file.reference.postgresql-9.4.1211.jre7.jar=release/modules/ext/postgresql-9.4.1211.jre7.jar @@ -26,10 +27,12 @@ file.reference.curator-recipes-2.8.0.jar=release/modules/ext/curator-recipes-2.8 file.reference.zookeeper-3.4.6.jar=release/modules/ext/zookeeper-3.4.6.jar javac.source=1.8 javac.compilerargs=-Xlint -Xlint:-serial +javadoc.reference.LGoodDatePicker-10.3.1.jar=release/modules/ext/LGoodDatePicker-10.3.1-javadoc.jar license.file=../LICENSE-2.0.txt nbm.homepage=http://www.sleuthkit.org/ nbm.module.author=Brian Carrier nbm.needs.restart=true source.reference.curator-recipes-2.8.0.jar=release/modules/ext/curator-recipes-2.8.0-sources.jar +source.reference.LGoodDatePicker-10.3.1.jar=release/modules/ext/LGoodDatePicker-10.3.1-sources.jar spec.version.base=10.9 diff --git a/Core/nbproject/project.xml b/Core/nbproject/project.xml index c4fea0885c..896926f17f 100755 --- a/Core/nbproject/project.xml +++ b/Core/nbproject/project.xml @@ -336,6 +336,10 @@ ext/tika-core-1.14.jar release/modules/ext/tika-core-1.14.jar + + ext/LGoodDatePicker-10.3.1.jar + release/modules/ext/LGoodDatePicker-10.3.1.jar + ext/Tsk_DataModel_PostgreSQL.jar release/modules/ext/Tsk_DataModel_PostgreSQL.jar diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageAction.java index 1ae20d1163..860fc6dcb5 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageAction.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageAction.java @@ -29,6 +29,7 @@ import java.util.logging.Level; import javax.swing.Action; import javax.swing.ImageIcon; import javax.swing.JButton; +import javax.swing.RootPaneContainer; import javax.swing.SwingUtilities; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; @@ -56,13 +57,15 @@ import org.sleuthkit.datamodel.Image; */ @ActionID(category = "Tools", id = "org.sleuthkit.autopsy.casemodule.AddImageAction") @ActionRegistration(displayName = "#CTL_AddImage", lazy = false) -@ActionReferences(value = {@ActionReference(path = "Toolbars/Case", position = 100)}) +@ActionReferences(value = { + @ActionReference(path = "Toolbars/Case", position = 100)}) @ServiceProvider(service = AddImageAction.class) public final class AddImageAction extends CallableSystemAction implements Presenter.Toolbar { private static final long serialVersionUID = 1L; private static final Dimension SIZE = new Dimension(875, 550); private final ChangeSupport cleanupSupport = new ChangeSupport(this); + // private final static MouseAdapter mouseDisabler = new MouseAdapter() {}; // Keys into the WizardDescriptor properties that pass information between stages of the wizard // : @@ -116,6 +119,9 @@ public final class AddImageAction extends CallableSystemAction implements Presen String optionsDlgTitle = NbBundle.getMessage(this.getClass(), "AddImageAction.ingestConfig.ongoingIngest.title"); String optionsDlgMessage = NbBundle.getMessage(this.getClass(), "AddImageAction.ingestConfig.ongoingIngest.msg"); if (IngestRunningCheck.checkAndConfirmProceed(optionsDlgTitle, optionsDlgMessage)) { + RootPaneContainer root = (RootPaneContainer) WindowManager.getDefault().getMainWindow(); + root.getGlassPane().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + root.getGlassPane().setVisible(true); WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); iterator = new AddImageWizardIterator(this); wizardDescriptor = new WizardDescriptor(iterator); @@ -129,7 +135,8 @@ public final class AddImageAction extends CallableSystemAction implements Presen dialog = DialogDisplayer.getDefault().createDialog(wizardDescriptor); Dimension d = dialog.getSize(); dialog.setSize(SIZE); - WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + root.getGlassPane().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + root.getGlassPane().setVisible(false); dialog.setVisible(true); dialog.toFront(); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenAction.java index adb84b680e..50a6ce5ade 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenAction.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenAction.java @@ -158,11 +158,15 @@ public final class CaseOpenAction extends CallableSystemAction implements Action @Override public void actionPerformed(ActionEvent e) { if (UserPreferences.getIsMultiUserModeEnabled()) { + WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + if (multiUserCaseWindow == null) { multiUserCaseWindow = MultiUserCasesDialog.getInstance(); } multiUserCaseWindow.setLocationRelativeTo(WindowManager.getDefault().getMainWindow()); multiUserCaseWindow.setVisible(true); + + WindowManager.getDefault().getMainWindow().setCursor(null); } else { openCaseSelectionWindow(); } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.java index 42e462dc37..0bef140c6d 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CueBannerPanel.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.casemodule; +import java.awt.Cursor; import java.awt.Dialog; import java.awt.Dimension; import java.awt.event.ActionEvent; @@ -239,7 +240,9 @@ public class CueBannerPanel extends javax.swing.JPanel { }//GEN-LAST:event_newCaseButtonActionPerformed private void openCaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openCaseButtonActionPerformed + setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); Lookup.getDefault().lookup(CaseOpenAction.class).actionPerformed(evt); + setCursor(null); }//GEN-LAST:event_openCaseButtonActionPerformed private void openRecentCaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openRecentCaseButtonActionPerformed diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDefinition.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDefinition.java index e1d81d2b65..e1d90d2f15 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDefinition.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDefinition.java @@ -179,7 +179,7 @@ final class TagNameDefinition implements Comparable { return displayName + "," + description + "," + color.name() + "," + knownStatus.toString(); } - private TagName saveToCase(SleuthkitCase caseDb) { + TagName saveToCase(SleuthkitCase caseDb) { TagName tagName = null; try { tagName = caseDb.addOrUpdateTagName(displayName, description, color, knownStatus); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index f96fe08f23..8d7eda2ec4 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -128,6 +128,9 @@ public class TagsManager implements Closeable { */ TagsManager(SleuthkitCase caseDb) { this.caseDb = caseDb; + for (TagNameDefinition tagName : TagNameDefinition.getTagNameDefinitions()) { + tagName.saveToCase(caseDb); + } } /** diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java index fbc955ca72..ad642a9cbc 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java @@ -433,36 +433,6 @@ public class DataContentViewerOtherCases extends javax.swing.JPanel implements D return Collections.emptyList(); } - /** - * Get the global file instances matching the given eamArtifact and convert - * them to central repository artifact instances. - * - * @param eamArtifact Artifact to use for ArtifactTypeEnum matching - * - * @return List of central repository artifact instances, empty list if none - * found - */ - public Collection getReferenceInstancesAsArtifactInstances(CorrelationAttribute eamArtifact) { - Collection eamArtifactInstances = new ArrayList<>(); - // FUTURE: support other reference types - if (eamArtifact.getCorrelationType().getId() != CorrelationAttribute.FILES_TYPE_ID) { - return Collections.emptyList(); - } - try { - EamDb dbManager = EamDb.getInstance(); - Collection eamGlobalFileInstances = dbManager.getReferenceInstancesByTypeValue(eamArtifact.getCorrelationType(), eamArtifact.getCorrelationValue()); - eamGlobalFileInstances.forEach((eamGlobalFileInstance) -> { - eamArtifactInstances.add(new CorrelationAttributeInstance( - null, null, "", eamGlobalFileInstance.getComment(), eamGlobalFileInstance.getKnownStatus(), CorrelationAttributeInstance.GlobalStatus.GLOBAL - )); - }); - return eamArtifactInstances; - } catch (EamDbException ex) { - LOGGER.log(Level.SEVERE, "Error getting reference instances from database.", ex); // NON-NLS - } - return Collections.emptyList(); - } - @Override public boolean isSupported(Node node) { if (!EamDb.isEnabled()) { @@ -517,7 +487,6 @@ public class DataContentViewerOtherCases extends javax.swing.JPanel implements D // get correlation and reference set instances from DB corAttrInstances.addAll(getCorrelatedInstances(corAttr, dataSourceName, deviceId)); - corAttrInstances.addAll(getReferenceInstancesAsArtifactInstances(corAttr)); corAttrInstances.forEach((corAttrInstance) -> { CorrelationAttribute newCeArtifact = new CorrelationAttribute( diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCasesTableModel.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCasesTableModel.java index 58395b7ad5..61bcd68211 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCasesTableModel.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCasesTableModel.java @@ -36,8 +36,7 @@ public class DataContentViewerOtherCasesTableModel extends AbstractTableModel { "DataContentViewerOtherCasesTableModel.path=Path", "DataContentViewerOtherCasesTableModel.type=Correlation Type", "DataContentViewerOtherCasesTableModel.value=Correlation Value", - "DataContentViewerOtherCasesTableModel.scope=Scope", - "DataContentViewerOtherCasesTableModel.known=Known", + "DataContentViewerOtherCasesTableModel.known=Tagged", "DataContentViewerOtherCasesTableModel.comment=Comment", "DataContentViewerOtherCasesTableModel.noData=No Data.",}) enum TableColumns { @@ -48,7 +47,6 @@ public class DataContentViewerOtherCasesTableModel extends AbstractTableModel { TYPE(Bundle.DataContentViewerOtherCasesTableModel_type(), 100), VALUE(Bundle.DataContentViewerOtherCasesTableModel_value(), 200), KNOWN(Bundle.DataContentViewerOtherCasesTableModel_known(), 50), - SCOPE(Bundle.DataContentViewerOtherCasesTableModel_scope(), 50), FILE_PATH(Bundle.DataContentViewerOtherCasesTableModel_path(), 450), COMMENT(Bundle.DataContentViewerOtherCasesTableModel_comment(), 200), DEVICE(Bundle.DataContentViewerOtherCasesTableModel_device(), 250); @@ -156,9 +154,6 @@ public class DataContentViewerOtherCasesTableModel extends AbstractTableModel { case VALUE: value = eamArtifact.getCorrelationValue(); break; - case SCOPE: - value = eamArtifactInstance.getGlobalStatus().toString(); - break; case KNOWN: value = eamArtifactInstance.getKnownStatus().getName(); break; diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java index 9560d635c4..2cac9b4927 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java @@ -34,9 +34,12 @@ import java.time.LocalDate; import java.util.HashMap; import java.util.Map; import java.util.Set; +import java.util.logging.Level; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; +import static org.sleuthkit.autopsy.centralrepository.datamodel.EamDbUtil.updateSchemaVersion; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.datamodel.CaseDbSchemaVersionNumber; import org.sleuthkit.datamodel.TskData; /** @@ -77,7 +80,7 @@ public abstract class AbstractSqlEamDb implements EamDb { /** * Add a new name/value pair in the db_info table. * - * @param name Key to set + * @param name Key to set * @param value Value to set * * @throws EamDbException @@ -140,7 +143,7 @@ public abstract class AbstractSqlEamDb implements EamDb { /** * Update the value for a name in the name/value db_info table. * - * @param name Name to find + * @param name Name to find * @param value Value to assign to name. * * @throws EamDbException @@ -226,7 +229,7 @@ public abstract class AbstractSqlEamDb implements EamDb { EamDbUtil.closePreparedStatement(preparedStatement); EamDbUtil.closeConnection(conn); } - + // get a new version with the updated ID return getCaseByUUID(eamCase.getCaseUUID()); } @@ -255,12 +258,11 @@ public abstract class AbstractSqlEamDb implements EamDb { autopsyCase.getCaseNotes()); return newCase(curCeCase); } - + @Override public CorrelationCase getCase(Case autopsyCase) throws EamDbException { return getCaseByUUID(autopsyCase.getName()); } - /** * Updates an existing Case in the database @@ -434,8 +436,8 @@ public abstract class AbstractSqlEamDb implements EamDb { /** * Retrieves Data Source details based on data source device ID * - * @param correlationCase the current CorrelationCase used for ensuring - * uniqueness of DataSource + * @param correlationCase the current CorrelationCase used for ensuring + * uniqueness of DataSource * @param dataSourceDeviceId the data source device ID number * * @return The data source @@ -608,7 +610,7 @@ public abstract class AbstractSqlEamDb implements EamDb { * Retrieves eamArtifact instances from the database that are associated * with the aType and filePath * - * @param aType EamArtifact.Type to search for + * @param aType EamArtifact.Type to search for * @param filePath File path to search for * * @return List of 0 or more EamArtifactInstances @@ -664,7 +666,7 @@ public abstract class AbstractSqlEamDb implements EamDb { * @param value The correlation value * * @return Number of artifact instances having ArtifactType and - * ArtifactValue. + * ArtifactValue. */ @Override public Long getCountArtifactInstancesByTypeValue(CorrelationAttribute.Type aType, String value) throws EamDbException { @@ -779,11 +781,11 @@ public abstract class AbstractSqlEamDb implements EamDb { * associated with the caseDisplayName and dataSource of the given * eamArtifact instance. * - * @param caseUUID Case ID to search for + * @param caseUUID Case ID to search for * @param dataSourceID Data source ID to search for * * @return Number of artifact instances having caseDisplayName and - * dataSource + * dataSource */ @Override public Long getCountArtifactInstancesByCaseDataSource(String caseUUID, String dataSourceID) throws EamDbException { @@ -999,12 +1001,14 @@ public abstract class AbstractSqlEamDb implements EamDb { } /** - * Sets an eamArtifact instance to the given knownStatus. If eamArtifact + * Sets an eamArtifact instance to the given knownStatus. + * knownStatus should be BAD if the file has been tagged with a notable tag and + * UNKNOWN otherwise. If eamArtifact * exists, it is updated. If eamArtifact does not exist it is added with the * given status. * * @param eamArtifact Artifact containing exactly one (1) ArtifactInstance. - * @param knownStatus The status to change the artifact to + * @param knownStatus The status to change the artifact to. Should never be KNOWN */ @Override public void setArtifactInstanceKnownStatus(CorrelationAttribute eamArtifact, TskData.FileKnown knownStatus) throws EamDbException { @@ -1070,7 +1074,7 @@ public abstract class AbstractSqlEamDb implements EamDb { if (null == correlationCaseWithId) { correlationCaseWithId = newCase(eamInstance.getCorrelationCase()); } - + if (null == getDataSource(correlationCaseWithId, eamInstance.getCorrelationDataSource().getDeviceID())) { newDataSource(eamInstance.getCorrelationDataSource()); } @@ -1187,7 +1191,7 @@ public abstract class AbstractSqlEamDb implements EamDb { * @param value Value to search for * * @return List of cases containing this artifact with instances marked as - * bad + * bad * * @throws EamDbException */ @@ -1230,24 +1234,26 @@ public abstract class AbstractSqlEamDb implements EamDb { return caseNames.stream().collect(Collectors.toList()); } - + /** * Remove a reference set and all entries contained in it. + * * @param referenceSetID - * @throws EamDbException + * @throws EamDbException */ @Override - public void deleteReferenceSet(int referenceSetID) throws EamDbException{ + public void deleteReferenceSet(int referenceSetID) throws EamDbException { deleteReferenceSetEntries(referenceSetID); deleteReferenceSetEntry(referenceSetID); - } - + } + /** * Remove the entry for this set from the reference_sets table + * * @param referenceSetID - * @throws EamDbException + * @throws EamDbException */ - private void deleteReferenceSetEntry(int referenceSetID) throws EamDbException{ + private void deleteReferenceSetEntry(int referenceSetID) throws EamDbException { Connection conn = connect(); PreparedStatement preparedStatement = null; @@ -1262,21 +1268,22 @@ public abstract class AbstractSqlEamDb implements EamDb { } finally { EamDbUtil.closePreparedStatement(preparedStatement); EamDbUtil.closeConnection(conn); - } + } } - + /** * Remove all entries for this reference set from the reference tables * (Currently only removes entries from the reference_file table) + * * @param referenceSetID - * @throws EamDbException + * @throws EamDbException */ - private void deleteReferenceSetEntries(int referenceSetID) throws EamDbException{ + private void deleteReferenceSetEntries(int referenceSetID) throws EamDbException { Connection conn = connect(); PreparedStatement preparedStatement = null; String sql = "DELETE FROM %s WHERE reference_set_id=?"; - + // When other reference types are added, this will need to loop over all the tables String fileTableName = EamDbUtil.correlationTypeToReferenceTableName(getCorrelationTypeById(CorrelationAttribute.FILES_TYPE_ID)); @@ -1289,12 +1296,14 @@ public abstract class AbstractSqlEamDb implements EamDb { } finally { EamDbUtil.closePreparedStatement(preparedStatement); EamDbUtil.closeConnection(conn); - } + } } - + /** - * Check whether a reference set with the given parameters exists in the central repository. - * Used to check whether reference sets saved in the settings are still present. + * Check whether a reference set with the given parameters exists in the + * central repository. Used to check whether reference sets saved in the + * settings are still present. + * * @param referenceSetID * @param setName * @param version @@ -1302,37 +1311,39 @@ public abstract class AbstractSqlEamDb implements EamDb { * @throws EamDbException */ @Override - public boolean referenceSetIsValid(int referenceSetID, String setName, String version) throws EamDbException{ + public boolean referenceSetIsValid(int referenceSetID, String setName, String version) throws EamDbException { EamGlobalSet refSet = this.getReferenceSetByID(referenceSetID); - if(refSet == null){ + if (refSet == null) { return false; } - - return(refSet.getSetName().equals(setName) && refSet.getVersion().equals(version)); + + return (refSet.getSetName().equals(setName) && refSet.getVersion().equals(version)); } - + /** - * Check if the given file hash is in this reference set. - * Only searches the reference_files table. + * Check if the given file hash is in this reference set. Only searches the + * reference_files table. + * * @param hash * @param referenceSetID * @return true if the hash is found in the reference set - * @throws EamDbException + * @throws EamDbException */ @Override - public boolean isFileHashInReferenceSet(String hash, int referenceSetID) throws EamDbException{ + public boolean isFileHashInReferenceSet(String hash, int referenceSetID) throws EamDbException { return isValueInReferenceSet(hash, referenceSetID, CorrelationAttribute.FILES_TYPE_ID); - } - + } + /** * Check if the given value is in a specific reference set + * * @param value * @param referenceSetID - * @param correlationTypeID + * @param correlationTypeID * @return true if the value is found in the reference set */ @Override - public boolean isValueInReferenceSet(String value, int referenceSetID, int correlationTypeID) throws EamDbException{ + public boolean isValueInReferenceSet(String value, int referenceSetID, int correlationTypeID) throws EamDbException { Connection conn = connect(); @@ -1340,7 +1351,7 @@ public abstract class AbstractSqlEamDb implements EamDb { PreparedStatement preparedStatement = null; ResultSet resultSet = null; String sql = "SELECT count(*) FROM %s WHERE value=? AND reference_set_id=?"; - + String fileTableName = EamDbUtil.correlationTypeToReferenceTableName(getCorrelationTypeById(correlationTypeID)); try { @@ -1506,15 +1517,16 @@ public abstract class AbstractSqlEamDb implements EamDb { EamDbUtil.closeConnection(conn); } } - + /** * Get the organization associated with the given reference set. + * * @param referenceSetID ID of the reference set * @return The organization object - * @throws EamDbException + * @throws EamDbException */ @Override - public EamOrganization getReferenceSetOrganization(int referenceSetID) throws EamDbException{ + public EamOrganization getReferenceSetOrganization(int referenceSetID) throws EamDbException { EamGlobalSet globalSet = getReferenceSetByID(referenceSetID); return (getOrganizationByID(globalSet.getOrgID())); @@ -1524,7 +1536,7 @@ public abstract class AbstractSqlEamDb implements EamDb { * Update an existing organization. * * @param updatedOrganization the values the Organization with the same ID - * will be updated to in the database. + * will be updated to in the database. * * @throws EamDbException */ @@ -1550,8 +1562,8 @@ public abstract class AbstractSqlEamDb implements EamDb { } @Messages({"AbstractSqlEamDb.deleteOrganization.inUseException.message=Can not delete organization " - + "which is currently in use by a case or reference set in the central repository.", - "AbstractSqlEamDb.deleteOrganization.errorDeleting.message=Error executing query when attempting to delete organization by id."}) + + "which is currently in use by a case or reference set in the central repository.", + "AbstractSqlEamDb.deleteOrganization.errorDeleting.message=Error executing query when attempting to delete organization by id."}) @Override public void deleteOrganization(EamOrganization organizationToDelete) throws EamDbException { Connection conn = connect(); @@ -1598,7 +1610,7 @@ public abstract class AbstractSqlEamDb implements EamDb { PreparedStatement preparedStatement1 = null; PreparedStatement preparedStatement2 = null; ResultSet resultSet = null; - String sql1 = "INSERT INTO reference_sets(org_id, set_name, version, known_status, read_only, import_date) VALUES (?, ?, ?, ?, ?, ?)"; + String sql1 = "INSERT INTO reference_sets(org_id, set_name, version, known_status, read_only, type, import_date) VALUES (?, ?, ?, ?, ?, ?, ?)"; String sql2 = "SELECT id FROM reference_sets WHERE org_id=? AND set_name=? AND version=? AND import_date=? LIMIT 1"; try { @@ -1608,7 +1620,8 @@ public abstract class AbstractSqlEamDb implements EamDb { preparedStatement1.setString(3, eamGlobalSet.getVersion()); preparedStatement1.setInt(4, eamGlobalSet.getFileKnownStatus().getFileKnownValue()); preparedStatement1.setBoolean(5, eamGlobalSet.isReadOnly()); - preparedStatement1.setString(6, eamGlobalSet.getImportDate().toString()); + preparedStatement1.setInt(6, eamGlobalSet.getType().getId()); + preparedStatement1.setString(7, eamGlobalSet.getImportDate().toString()); preparedStatement1.executeUpdate(); @@ -1664,22 +1677,24 @@ public abstract class AbstractSqlEamDb implements EamDb { EamDbUtil.closeConnection(conn); } } - + /** * Get all reference sets * + * @param correlationType Type of sets to return + * * @return List of all reference sets in the central repository * * @throws EamDbException */ @Override - public List getAllReferenceSets() throws EamDbException{ + public List getAllReferenceSets(CorrelationAttribute.Type correlationType) throws EamDbException { List results = new ArrayList<>(); Connection conn = connect(); PreparedStatement preparedStatement1 = null; ResultSet resultSet = null; - String sql1 = "SELECT * FROM reference_sets"; + String sql1 = "SELECT * FROM reference_sets WHERE type=" + correlationType.getId(); try { preparedStatement1 = conn.prepareStatement(sql1); @@ -1702,8 +1717,7 @@ public abstract class AbstractSqlEamDb implements EamDb { * Add a new reference instance * * @param eamGlobalFileInstance The reference instance to add - * @param correlationType Correlation Type that this Reference - * Instance is + * @param correlationType Correlation Type that this Reference Instance is * * @throws EamDbException */ @@ -1729,17 +1743,19 @@ public abstract class AbstractSqlEamDb implements EamDb { EamDbUtil.closeConnection(conn); } } - + /** - * Check whether a reference set with the given name/version is in the central repo. - * Used to check for name collisions when creating reference sets. + * Check whether a reference set with the given name/version is in the + * central repo. Used to check for name collisions when creating reference + * sets. + * * @param referenceSetName * @param version * @return true if a matching set is found - * @throws EamDbException + * @throws EamDbException */ @Override - public boolean referenceSetExists(String referenceSetName, String version) throws EamDbException{ + public boolean referenceSetExists(String referenceSetName, String version) throws EamDbException { Connection conn = connect(); PreparedStatement preparedStatement1 = null; @@ -1754,13 +1770,13 @@ public abstract class AbstractSqlEamDb implements EamDb { return (resultSet.next()); } catch (SQLException ex) { - throw new EamDbException("Error testing whether reference set exists (name: " + referenceSetName + throw new EamDbException("Error testing whether reference set exists (name: " + referenceSetName + " version: " + version, ex); // NON-NLS } finally { EamDbUtil.closePreparedStatement(preparedStatement1); EamDbUtil.closeResultSet(resultSet); EamDbUtil.closeConnection(conn); - } + } } /** @@ -1808,7 +1824,7 @@ public abstract class AbstractSqlEamDb implements EamDb { /** * Get all reference entries having a given correlation type and value * - * @param aType Type to use for matching + * @param aType Type to use for matching * @param aValue Value to use for matching * * @return List of all global file instances with a type and value @@ -1938,7 +1954,7 @@ public abstract class AbstractSqlEamDb implements EamDb { * artifacts. * * @return List of enabled EamArtifact.Type's. If none are defined in the - * database, the default list will be returned. + * database, the default list will be returned. * * @throws EamDbException */ @@ -1973,7 +1989,7 @@ public abstract class AbstractSqlEamDb implements EamDb { * correlate artifacts. * * @return List of supported EamArtifact.Type's. If none are defined in the - * database, the default list will be returned. + * database, the default list will be returned. * * @throws EamDbException */ @@ -2074,7 +2090,7 @@ public abstract class AbstractSqlEamDb implements EamDb { * Convert a ResultSet to a EamCase object * * @param resultSet A resultSet with a set of values to create a EamCase - * object. + * object. * * @return fully populated EamCase object, or null * @@ -2144,7 +2160,7 @@ public abstract class AbstractSqlEamDb implements EamDb { * Convert a ResultSet to a EamArtifactInstance object * * @param resultSet A resultSet with a set of values to create a - * EamArtifactInstance object. + * EamArtifactInstance object. * * @return fully populated EamArtifactInstance, or null * @@ -2159,8 +2175,7 @@ public abstract class AbstractSqlEamDb implements EamDb { new CorrelationDataSource(-1, resultSet.getInt("case_id"), resultSet.getString("device_id"), resultSet.getString("name")), resultSet.getString("file_path"), resultSet.getString("comment"), - TskData.FileKnown.valueOf(resultSet.getByte("known_status")), - CorrelationAttributeInstance.GlobalStatus.LOCAL + TskData.FileKnown.valueOf(resultSet.getByte("known_status")) ); return eamArtifactInstance; @@ -2182,7 +2197,7 @@ public abstract class AbstractSqlEamDb implements EamDb { return eamOrganization; } - private EamGlobalSet getEamGlobalSetFromResultSet(ResultSet resultSet) throws SQLException { + private EamGlobalSet getEamGlobalSetFromResultSet(ResultSet resultSet) throws SQLException, EamDbException { if (null == resultSet) { return null; } @@ -2194,6 +2209,7 @@ public abstract class AbstractSqlEamDb implements EamDb { resultSet.getString("version"), TskData.FileKnown.valueOf(resultSet.getByte("known_status")), resultSet.getBoolean("read_only"), + EamDb.getInstance().getCorrelationTypeById(resultSet.getInt("type")), LocalDate.parse(resultSet.getString("import_date")) ); @@ -2216,4 +2232,82 @@ public abstract class AbstractSqlEamDb implements EamDb { return eamGlobalFileInstance; } + /** + * Upgrade the schema of the database (if needed) + * + * @throws EamDbException + */ + @Override + public void upgradeSchema() throws EamDbException, SQLException { + + ResultSet resultSet = null; + Statement statement; + Connection conn = null; + try { + + conn = connect(); + conn.setAutoCommit(false); + statement = conn.createStatement(); + + int minorVersion = 0; + int majorVersion = 0; + resultSet = statement.executeQuery("SELECT value FROM db_info WHERE name='SCHEMA_MINOR_VERSION'"); + if (resultSet.next()) { + String minorVersionStr = resultSet.getString("value"); + try { + minorVersion = Integer.parseInt(minorVersionStr); + } catch (NumberFormatException ex) { + throw new EamDbException("Bad value for schema minor version (" + minorVersionStr + ") - database is corrupt"); + } + } + + resultSet = statement.executeQuery("SELECT value FROM db_info WHERE name='SCHEMA_VERSION'"); + if (resultSet.next()) { + String majorVersionStr = resultSet.getString("value"); + try { + majorVersion = Integer.parseInt(majorVersionStr); + } catch (NumberFormatException ex) { + throw new EamDbException("Bad value for schema version (" + majorVersionStr + ") - database is corrupt"); + } + } + + CaseDbSchemaVersionNumber dbSchemaVersion = new CaseDbSchemaVersionNumber(majorVersion, minorVersion); + if (dbSchemaVersion.equals(CURRENT_DB_SCHEMA_VERSION)) { + LOGGER.log(Level.INFO, "Central Repository is up to date"); + return; + } + + // Update from 1.0 to 1.1 + if (dbSchemaVersion.compareTo(new CaseDbSchemaVersionNumber(1, 1)) < 0) { + statement.execute("ALTER TABLE reference_sets ADD COLUMN known_status INTEGER;"); //NON-NLS + statement.execute("ALTER TABLE reference_sets ADD COLUMN read_only BOOLEAN;"); //NON-NLS + statement.execute("ALTER TABLE reference_sets ADD COLUMN type INTEGER;"); //NON-NLS + + // There's an outide chance that the user has already made an organization with the default name, + // and the default org being missing will not impact any database operations, so continue on + // regardless of whether this succeeds. + EamDbUtil.insertDefaultOrganization(conn); + } + + if (!updateSchemaVersion(conn)) { + throw new EamDbException("Error updating schema version"); + } + + conn.commit(); + LOGGER.log(Level.INFO, "Central Repository upgraded to version " + CURRENT_DB_SCHEMA_VERSION); + } catch (SQLException | EamDbException ex) { + try { + if (conn != null) { + conn.rollback(); + } + } catch (SQLException ex2) { + LOGGER.log(Level.SEVERE, "Database rollback failed", ex2); + } + throw ex; + } finally { + EamDbUtil.closeResultSet(resultSet); + EamDbUtil.closeConnection(conn); + } + } + } diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeInstance.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeInstance.java index 7db48d28db..f75364c580 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeInstance.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeInstance.java @@ -28,29 +28,12 @@ import org.sleuthkit.datamodel.TskData; * CorrelationAttribute. Includes its data source, path, etc. * */ -@Messages({"EamArtifactInstances.globalStatus.local=Local", - "EamArtifactInstances.globalStatus.global=Global", +@Messages({ "EamArtifactInstances.knownStatus.bad=Bad", "EamArtifactInstances.knownStatus.known=Known", "EamArtifactInstances.knownStatus.unknown=Unknown"}) public class CorrelationAttributeInstance implements Serializable { - public enum GlobalStatus { - LOCAL(Bundle.EamArtifactInstances_globalStatus_local()), - GLOBAL(Bundle.EamArtifactInstances_globalStatus_global()); - - private final String globalStatus; - - private GlobalStatus(String globalStatus) { - this.globalStatus = globalStatus; - } - - @Override - public String toString() { - return globalStatus; - } - } - private static final long serialVersionUID = 1L; private int ID; @@ -59,13 +42,12 @@ public class CorrelationAttributeInstance implements Serializable { private String filePath; private String comment; private TskData.FileKnown knownStatus; - private GlobalStatus globalStatus; public CorrelationAttributeInstance( CorrelationCase eamCase, CorrelationDataSource eamDataSource ) { - this(-1, eamCase, eamDataSource, "", null, TskData.FileKnown.UNKNOWN, GlobalStatus.LOCAL); + this(-1, eamCase, eamDataSource, "", null, TskData.FileKnown.UNKNOWN); } public CorrelationAttributeInstance( @@ -73,7 +55,7 @@ public class CorrelationAttributeInstance implements Serializable { CorrelationDataSource eamDataSource, String filePath ) { - this(-1, eamCase, eamDataSource, filePath, null, TskData.FileKnown.UNKNOWN, GlobalStatus.LOCAL); + this(-1, eamCase, eamDataSource, filePath, null, TskData.FileKnown.UNKNOWN); } public CorrelationAttributeInstance( @@ -82,7 +64,7 @@ public class CorrelationAttributeInstance implements Serializable { String filePath, String comment ) { - this(-1, eamCase, eamDataSource, filePath, comment, TskData.FileKnown.UNKNOWN, GlobalStatus.LOCAL); + this(-1, eamCase, eamDataSource, filePath, comment, TskData.FileKnown.UNKNOWN); } public CorrelationAttributeInstance( @@ -90,20 +72,18 @@ public class CorrelationAttributeInstance implements Serializable { CorrelationDataSource eamDataSource, String filePath, String comment, - TskData.FileKnown knownStatus, - GlobalStatus globalStatus + TskData.FileKnown knownStatus ) { - this(-1, eamCase, eamDataSource, filePath, comment, knownStatus, globalStatus); + this(-1, eamCase, eamDataSource, filePath, comment, knownStatus); } - public CorrelationAttributeInstance( + CorrelationAttributeInstance( int ID, CorrelationCase eamCase, CorrelationDataSource eamDataSource, String filePath, String comment, - TskData.FileKnown knownStatus, - GlobalStatus globalStatus + TskData.FileKnown knownStatus ) { this.ID = ID; this.correlationCase = eamCase; @@ -112,7 +92,6 @@ public class CorrelationAttributeInstance implements Serializable { this.filePath = filePath.toLowerCase(); this.comment = comment; this.knownStatus = knownStatus; - this.globalStatus = globalStatus; } public Boolean equals(CorrelationAttributeInstance otherInstance) { @@ -120,7 +99,6 @@ public class CorrelationAttributeInstance implements Serializable { && (this.getCorrelationCase().equals(otherInstance.getCorrelationCase())) && (this.getCorrelationDataSource().equals(otherInstance.getCorrelationDataSource())) && (this.getFilePath().equals(otherInstance.getFilePath())) - && (this.getGlobalStatus().equals(otherInstance.getGlobalStatus())) && (this.getKnownStatus().equals(otherInstance.getKnownStatus())) && (this.getComment().equals(otherInstance.getComment()))); } @@ -131,7 +109,6 @@ public class CorrelationAttributeInstance implements Serializable { + this.getCorrelationCase().getCaseUUID() + this.getCorrelationDataSource().getName() + this.getFilePath() - + this.getGlobalStatus() + this.getKnownStatus() + this.getComment(); } @@ -179,31 +156,22 @@ public class CorrelationAttributeInstance implements Serializable { } /** - * @return the knownStatus + * Get this knownStatus. This only indicates whether an item has been + * tagged as notable and should never return KNOWN. + * + * @return BAD if the item has been tagged as notable, UNKNOWN otherwise */ public TskData.FileKnown getKnownStatus() { return knownStatus; } /** - * @param knownStatus the knownStatus to set + * Set the knownStatus. This only indicates whether an item has been + * tagged as notable and should never be set to KNOWN. + * + * @param knownStatus Should be BAD if the item is tagged as notable, UNKNOWN otherwise */ public void setKnownStatus(TskData.FileKnown knownStatus) { this.knownStatus = knownStatus; } - - /** - * @return the globalStatus - */ - public GlobalStatus getGlobalStatus() { - return globalStatus; - } - - /** - * @param globalStatus the globalStatus to set - */ - public void setGlobalStatus(GlobalStatus globalStatus) { - this.globalStatus = globalStatus; - } - } diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamArtifactUtil.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamArtifactUtil.java index c2bb0e0016..171444fa42 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamArtifactUtil.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamArtifactUtil.java @@ -28,6 +28,7 @@ import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.HashUtility; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; @@ -105,8 +106,7 @@ public class EamArtifactUtil { CorrelationDataSource.fromTSKDataSource(correlationCase, bbSourceFile.getDataSource()), bbSourceFile.getParentPath() + bbSourceFile.getName(), "", - TskData.FileKnown.UNKNOWN, - CorrelationAttributeInstance.GlobalStatus.LOCAL + TskData.FileKnown.UNKNOWN ); // add the instance details @@ -227,7 +227,7 @@ public class EamArtifactUtil { * * @return The new EamArtifact or null if creation failed */ - public static CorrelationAttribute getEamArtifactFromContent(Content content, TskData.FileKnown knownStatus, String comment) { + public static CorrelationAttribute getCorrelationAttributeFromContent(Content content, TskData.FileKnown knownStatus, String comment) { if (!(content instanceof AbstractFile)) { return null; @@ -241,7 +241,7 @@ public class EamArtifactUtil { // We need a hash to make the artifact String md5 = af.getMd5Hash(); - if (md5 == null || md5.isEmpty()) { + if (md5 == null || md5.isEmpty() || HashUtility.isNoDataMd5(md5)) { return null; } @@ -258,8 +258,7 @@ public class EamArtifactUtil { CorrelationDataSource.fromTSKDataSource(correlationCase, af.getDataSource()), af.getParentPath() + af.getName(), comment, - TskData.FileKnown.BAD, - CorrelationAttributeInstance.GlobalStatus.LOCAL + knownStatus ); eamArtifact.addInstance(cei); return eamArtifact; diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java index b9ce4320de..2b05cb1d70 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java @@ -18,10 +18,13 @@ */ package org.sleuthkit.autopsy.centralrepository.datamodel; +import java.sql.SQLException; import java.util.List; import java.util.Set; import org.sleuthkit.datamodel.TskData; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.coordinationservice.CoordinationService; +import org.sleuthkit.datamodel.CaseDbSchemaVersionNumber; /** * Main interface for interacting with the database @@ -29,6 +32,8 @@ import org.sleuthkit.autopsy.casemodule.Case; public interface EamDb { public static final int SCHEMA_VERSION = 1; + public static final CaseDbSchemaVersionNumber CURRENT_DB_SCHEMA_VERSION + = new CaseDbSchemaVersionNumber(1, 1); /** * Get the instance @@ -98,7 +103,7 @@ public interface EamDb { /** * Add a new name/value pair in the db_info table. * - * @param name Key to set + * @param name Key to set * @param value Value to set * * @throws EamDbException @@ -119,7 +124,7 @@ public interface EamDb { /** * Update the value for a name in the name/value db_info table. * - * @param name Name to find + * @param name Name to find * @param value Value to assign to name. * * @throws EamDbException @@ -141,8 +146,6 @@ public interface EamDb { * @param autopsyCase The case to add */ CorrelationCase newCase(Case autopsyCase) throws EamDbException; - - /** * Updates an existing Case in the database @@ -153,13 +156,13 @@ public interface EamDb { /** * Retrieves Central Repo case based on an Autopsy Case - * + * * @param autopsyCase Autopsy case to find corresponding CR case for * @return CR Case - * @throws EamDbException + * @throws EamDbException */ CorrelationCase getCase(Case autopsyCase) throws EamDbException; - + /** * Retrieves Case details based on Case UUID * @@ -186,8 +189,8 @@ public interface EamDb { /** * Retrieves Data Source details based on data source device ID * - * @param correlationCase the current CorrelationCase used for ensuring - * uniqueness of DataSource + * @param correlationCase the current CorrelationCase used for ensuring + * uniqueness of DataSource * @param dataSourceDeviceId the data source device ID number * * @return The data source @@ -224,7 +227,7 @@ public interface EamDb { * Retrieves eamArtifact instances from the database that are associated * with the aType and filePath * - * @param aType EamArtifact.Type to search for + * @param aType EamArtifact.Type to search for * @param filePath File path to search for * * @return List of 0 or more EamArtifactInstances @@ -241,7 +244,7 @@ public interface EamDb { * @param value Value to search for * * @return Number of artifact instances having ArtifactType and - * ArtifactValue. + * ArtifactValue. */ Long getCountArtifactInstancesByTypeValue(CorrelationAttribute.Type aType, String value) throws EamDbException; @@ -278,11 +281,11 @@ public interface EamDb { * associated with the caseDisplayName and dataSource of the given * eamArtifact instance. * - * @param caseUUID Case ID to search for + * @param caseUUID Case ID to search for * @param dataSourceID Data source ID to search for * * @return Number of artifact instances having caseDisplayName and - * dataSource + * dataSource */ Long getCountArtifactInstancesByCaseDataSource(String caseUUID, String dataSourceID) throws EamDbException; @@ -344,7 +347,7 @@ public interface EamDb { * @param value Value to search for * * @return List of cases containing this artifact with instances marked as - * bad + * bad * * @throws EamDbException */ @@ -352,14 +355,17 @@ public interface EamDb { /** * Remove a reference set and all values contained in it. + * * @param referenceSetID - * @throws EamDbException + * @throws EamDbException */ public void deleteReferenceSet(int referenceSetID) throws EamDbException; - + /** - * Check whether a reference set with the given parameters exists in the central repository. - * Used to check whether reference sets saved in the settings are still present. + * Check whether a reference set with the given parameters exists in the + * central repository. Used to check whether reference sets saved in the + * settings are still present. + * * @param referenceSetID * @param referenceSetName * @param version @@ -367,36 +373,40 @@ public interface EamDb { * @throws EamDbException */ public boolean referenceSetIsValid(int referenceSetID, String referenceSetName, String version) throws EamDbException; - + /** - * Check whether a reference set with the given name/version is in the central repo. - * Used to check for name collisions when creating reference sets. + * Check whether a reference set with the given name/version is in the + * central repo. Used to check for name collisions when creating reference + * sets. + * * @param referenceSetName * @param version * @return true if a matching set is found - * @throws EamDbException + * @throws EamDbException */ public boolean referenceSetExists(String referenceSetName, String version) throws EamDbException; - + /** - * Check if the given file hash is in this reference set. - * Only searches the reference_files table. + * Check if the given file hash is in this reference set. Only searches the + * reference_files table. + * * @param hash * @param referenceSetID * @return true if the hash is found in the reference set - * @throws EamDbException + * @throws EamDbException */ public boolean isFileHashInReferenceSet(String hash, int referenceSetID) throws EamDbException; - + /** * Check if the given value is in a specific reference set + * * @param value * @param referenceSetID - * @param correlationTypeID + * @param correlationTypeID * @return true if the hash is found in the reference set */ - public boolean isValueInReferenceSet(String value, int referenceSetID, int correlationTypeID) throws EamDbException; - + public boolean isValueInReferenceSet(String value, int referenceSetID, int correlationTypeID) throws EamDbException; + /** * Is the artifact known as bad according to the reference entries? * @@ -413,7 +423,7 @@ public interface EamDb { * @param eamOrg The organization to add * * @return the Organization ID of the newly created organization. - * + * * @throws EamDbException */ long newOrganization(EamOrganization eamOrg) throws EamDbException; @@ -440,9 +450,10 @@ public interface EamDb { /** * Get the organization associated with the given reference set. + * * @param referenceSetID ID of the reference set * @return The organization object - * @throws EamDbException + * @throws EamDbException */ EamOrganization getReferenceSetOrganization(int referenceSetID) throws EamDbException; @@ -450,7 +461,7 @@ public interface EamDb { * Update an existing organization. * * @param updatedOrganization the values the Organization with the same ID - * will be updated to in the database. + * will be updated to in the database. * * @throws EamDbException */ @@ -458,13 +469,13 @@ public interface EamDb { /** * Delete an organization if it is not being used by any case. - * + * * @param organizationToDelete the organization to be deleted - * - * @throws EamDbException + * + * @throws EamDbException */ void deleteOrganization(EamOrganization organizationToDelete) throws EamDbException; - + /** * Add a new Global Set * @@ -486,33 +497,34 @@ public interface EamDb { * @throws EamDbException */ EamGlobalSet getReferenceSetByID(int globalSetID) throws EamDbException; - + /** * Get all reference sets * + * @param correlationType Type of sets to return + * * @return List of all reference sets in the central repository * * @throws EamDbException */ - List getAllReferenceSets() throws EamDbException; + List getAllReferenceSets(CorrelationAttribute.Type correlationType) throws EamDbException; /** * Add a new reference instance * * @param eamGlobalFileInstance The reference instance to add - * @param correlationType Correlation Type that this Reference - * Instance is + * @param correlationType Correlation Type that this Reference Instance is * * @throws EamDbException */ void addReferenceInstance(EamGlobalFileInstance eamGlobalFileInstance, CorrelationAttribute.Type correlationType) throws EamDbException; - + /** * Insert the bulk collection of Global File Instances * * @param globalInstances a Set of EamGlobalFileInstances to insert into the - * db. - * @param contentType the Type of the global instances + * db. + * @param contentType the Type of the global instances * * @throws EamDbException */ @@ -521,7 +533,7 @@ public interface EamDb { /** * Get all reference entries having a given correlation type and value * - * @param aType Type to use for matching + * @param aType Type to use for matching * @param aValue Value to use for matching * * @return List of all global file instances with a type and value @@ -546,7 +558,7 @@ public interface EamDb { * used to correlate artifacts. * * @return List of EamArtifact.Type's. If none are defined in the database, - * the default list will be returned. + * the default list will be returned. * * @throws EamDbException */ @@ -557,7 +569,7 @@ public interface EamDb { * artifacts. * * @return List of enabled EamArtifact.Type's. If none are defined in the - * database, the default list will be returned. + * database, the default list will be returned. * * @throws EamDbException */ @@ -568,7 +580,7 @@ public interface EamDb { * correlate artifacts. * * @return List of supported EamArtifact.Type's. If none are defined in the - * database, the default list will be returned. + * database, the default list will be returned. * * @throws EamDbException */ @@ -593,4 +605,23 @@ public interface EamDb { * @throws EamDbException */ public CorrelationAttribute.Type getCorrelationTypeById(int typeId) throws EamDbException; + + /** + * Upgrade the schema of the database (if needed) + * + * @throws EamDbException + */ + public void upgradeSchema() throws EamDbException, SQLException; + + /** + * Gets an exclusive lock (if applicable). Will return the lock if + * successful, null if unsuccessful because locking isn't supported, and + * throw an exception if we should have been able to get the lock but failed + * (meaning the database is in use). + * + * @return the lock, or null if locking is not supported + * @throws EamDbException if the coordination service is running but we fail + * to get the lock + */ + public CoordinationService.Lock getExclusiveMultiUserDbLock() throws EamDbException; } diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDbUtil.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDbUtil.java old mode 100755 new mode 100644 index 49f49f9d38..7c91f24648 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDbUtil.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDbUtil.java @@ -25,7 +25,9 @@ import java.sql.SQLException; import java.sql.Statement; import java.util.List; import java.util.logging.Level; -import static org.sleuthkit.autopsy.centralrepository.datamodel.EamDb.SCHEMA_VERSION; +import static org.sleuthkit.autopsy.centralrepository.datamodel.EamDb.CURRENT_DB_SCHEMA_VERSION; +import org.sleuthkit.autopsy.coordinationservice.CoordinationService; +import org.sleuthkit.autopsy.coordinationservice.CoordinationService.CoordinationServiceException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ModuleSettings; @@ -133,20 +135,33 @@ public class EamDbUtil { * * @return true on success, else false */ - public static boolean insertSchemaVersion(Connection conn) { - PreparedStatement preparedStatement = null; + static boolean updateSchemaVersion(Connection conn) { + + Statement statement; + ResultSet resultSet; String sql = "INSERT INTO db_info (name, value) VALUES (?, ?)"; try { - preparedStatement = conn.prepareStatement(sql); - preparedStatement.setString(1, "SCHEMA_VERSION"); - preparedStatement.setString(2, String.valueOf(SCHEMA_VERSION)); - preparedStatement.executeUpdate(); + statement = conn.createStatement(); + resultSet = statement.executeQuery("SELECT id FROM db_info WHERE name='SCHEMA_VERSION'"); + if (resultSet.next()) { + int id = resultSet.getInt("id"); + statement.execute("UPDATE db_info SET value=" + CURRENT_DB_SCHEMA_VERSION.getMajor() + " WHERE id=" + id); + } else { + statement.execute("INSERT INTO db_info (name, value) VALUES ('SCHEMA_VERSION', '" + CURRENT_DB_SCHEMA_VERSION.getMajor() + "')"); + } + + resultSet = statement.executeQuery("SELECT id FROM db_info WHERE name='SCHEMA_MINOR_VERSION'"); + if (resultSet.next()) { + int id = resultSet.getInt("id"); + statement.execute("UPDATE db_info SET value=" + CURRENT_DB_SCHEMA_VERSION.getMinor() + " WHERE id=" + id); + } else { + statement.execute("INSERT INTO db_info (name, value) VALUES ('SCHEMA_MINOR_VERSION', '" + CURRENT_DB_SCHEMA_VERSION.getMinor() + "')"); + } } catch (SQLException ex) { LOGGER.log(Level.SEVERE, "Error adding schema version to db_info.", ex); return false; - } finally { - EamDbUtil.closePreparedStatement(preparedStatement); } + return true; } @@ -176,6 +191,66 @@ public class EamDbUtil { return true; } + /** + * Upgrade the current central reposity to the newest version. If the upgrade + * fails, the central repository will be disabled and the current settings + * will be cleared. + * + * @return true if the upgrade succeeds, false otherwise. + */ + public static boolean upgradeDatabase() { + if (!EamDb.isEnabled()) { + return true; + } + + CoordinationService.Lock lock = null; + try { + EamDb db = EamDb.getInstance(); + + // This may return null if locking isn't supported, which is fine. It will + // throw an exception if locking is supported but we can't get the lock + // (meaning the database is in use by another user) + lock = db.getExclusiveMultiUserDbLock(); + + db.upgradeSchema(); + + } catch (EamDbException | SQLException ex) { + LOGGER.log(Level.SEVERE, "Error updating central repository", ex); + + // Disable the central repo and clear the current settings. + try{ + if (null != EamDb.getInstance()) { + EamDb.getInstance().shutdownConnections(); + } + } catch (EamDbException ex2){ + LOGGER.log(Level.SEVERE, "Error shutting down central repo connection pool", ex); + } + setUseCentralRepo(false); + EamDbPlatformEnum.setSelectedPlatform(EamDbPlatformEnum.DISABLED.name()); + EamDbPlatformEnum.saveSelectedPlatform(); + + return false; + } finally { + if(lock != null){ + try{ + lock.release(); + } catch (CoordinationServiceException ex){ + LOGGER.log(Level.SEVERE, "Error releasing database lock", ex); + } + } + } + return true; + } + + /** + * Get the default organization name + * + * @return the default org name + */ + static String getDefaultOrgName() { + return DEFAULT_ORG_NAME; + } + /** * Check whether the given org is the default organization. * diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamGlobalSet.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamGlobalSet.java index 23a4c257ae..a434afb32b 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamGlobalSet.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamGlobalSet.java @@ -32,6 +32,7 @@ public class EamGlobalSet { private String version; private TskData.FileKnown fileKnownStatus; private boolean isReadOnly; + private CorrelationAttribute.Type type; private LocalDate importDate; public EamGlobalSet( @@ -41,6 +42,7 @@ public class EamGlobalSet { String version, TskData.FileKnown knownStatus, boolean isReadOnly, + CorrelationAttribute.Type type, LocalDate importDate) { this.globalSetID = globalSetID; this.orgID = orgID; @@ -48,6 +50,7 @@ public class EamGlobalSet { this.version = version; this.fileKnownStatus = knownStatus; this.isReadOnly = isReadOnly; + this.type = type; this.importDate = importDate; } @@ -57,8 +60,9 @@ public class EamGlobalSet { String version, TskData.FileKnown knownStatus, boolean isReadOnly, + CorrelationAttribute.Type type, LocalDate importDate) { - this(-1, orgID, setName, version, knownStatus, isReadOnly, importDate); + this(-1, orgID, setName, version, knownStatus, isReadOnly, type, importDate); } /** @@ -77,8 +81,9 @@ public class EamGlobalSet { String setName, String version, TskData.FileKnown knownStatus, - boolean isReadOnly) { - this(-1, orgID, setName, version, knownStatus, isReadOnly, LocalDate.now()); + boolean isReadOnly, + CorrelationAttribute.Type type) { + this(-1, orgID, setName, version, knownStatus, isReadOnly, type, LocalDate.now()); } /** @@ -164,6 +169,24 @@ public class EamGlobalSet { public void setFileKnownStatus(TskData.FileKnown fileKnownStatus) { this.fileKnownStatus = fileKnownStatus; } + + /** + * Get the type of reference set + * + * @return the type (files, phone numbers, etc) + */ + public CorrelationAttribute.Type getType() { + return type; + } + + /** + * Sets the type of reference set + * + * @param type + */ + void setType(CorrelationAttribute.Type type) { + this.type = type; + } /** * @return the importDate diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDb.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDb.java index c139554c9c..46d579ad87 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDb.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDb.java @@ -21,8 +21,13 @@ package org.sleuthkit.autopsy.centralrepository.datamodel; import java.sql.Connection; import java.sql.SQLException; import java.sql.Statement; +import java.util.concurrent.TimeUnit; import java.util.logging.Level; import org.apache.commons.dbcp2.BasicDataSource; +import org.sleuthkit.autopsy.casemodule.CaseActionCancelledException; +import org.sleuthkit.autopsy.casemodule.CaseActionException; +import org.sleuthkit.autopsy.coordinationservice.CoordinationService; +import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.Logger; /** @@ -185,5 +190,36 @@ public class PostgresEamDb extends AbstractSqlEamDb { protected String getConflictClause() { return CONFLICT_CLAUSE; } + + /** + * Gets an exclusive lock (if applicable). + * Will return the lock if successful, null if unsuccessful because locking + * isn't supported, and throw an exception if we should have been able to get the + * lock but failed (meaning the database is in use). + * @return the lock, or null if locking is not supported + * @throws EamDbException if the coordination service is running but we fail to get the lock + */ + @Override + public CoordinationService.Lock getExclusiveMultiUserDbLock() throws EamDbException{ + try { + // First check if multi user mode is enabled - if not there's no point trying to get a lock + if( ! UserPreferences.getIsMultiUserModeEnabled()){ + return null; + } + + String databaseNodeName = dbSettings.getHost() + "_" + dbSettings.getDbName(); + CoordinationService.Lock lock = CoordinationService.getInstance().tryGetExclusiveLock(CoordinationService.CategoryNode.CENTRAL_REPO, databaseNodeName, 5, TimeUnit.MINUTES); + + if(lock != null){ + return lock; + } + throw new EamDbException("Error acquiring database lock"); + } catch (InterruptedException ex){ + throw new EamDbException("Error acquiring database lock"); + } catch (CoordinationService.CoordinationServiceException ex) { + // This likely just means the coordination service isn't running, which is ok + return null; + } + } } diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDbSettings.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDbSettings.java old mode 100755 new mode 100644 index fe85685de8..37a2970082 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDbSettings.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDbSettings.java @@ -356,6 +356,7 @@ public final class PostgresEamDbSettings { createReferenceSetsTable.append("version text NOT NULL,"); createReferenceSetsTable.append("known_status integer NOT NULL,"); createReferenceSetsTable.append("read_only boolean NOT NULL,"); + createReferenceSetsTable.append("type integer NOT NULL,"); createReferenceSetsTable.append("import_date text NOT NULL,"); createReferenceSetsTable.append("foreign key (org_id) references organizations(id) ON UPDATE SET NULL ON DELETE SET NULL,"); createReferenceSetsTable.append("CONSTRAINT hash_set_unique UNIQUE (set_name, version)"); @@ -485,7 +486,7 @@ public final class PostgresEamDbSettings { } boolean result = EamDbUtil.insertDefaultCorrelationTypes(conn) - && EamDbUtil.insertSchemaVersion(conn) + && EamDbUtil.updateSchemaVersion(conn) && EamDbUtil.insertDefaultOrganization(conn); EamDbUtil.closeConnection(conn); diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDb.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDb.java index 85fda8d4a1..98396eef9c 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDb.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDb.java @@ -30,6 +30,7 @@ import org.apache.commons.dbcp2.BasicDataSource; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.TskData; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.coordinationservice.CoordinationService; /** * Sqlite implementation of the Central Repository database. @@ -549,11 +550,14 @@ public class SqliteEamDb extends AbstractSqlEamDb { } /** - * Sets an eamArtifact instance as the given knownStatus. If eamArtifact - * exists, it is updated. If eamArtifact does not exist nothing happens + * Sets an eamArtifact instance to the given knownStatus. + * knownStatus should be BAD if the file has been tagged with a notable tag and + * UNKNOWN otherwise. If eamArtifact + * exists, it is updated. If eamArtifact does not exist it is added with the + * given status. * * @param eamArtifact Artifact containing exactly one (1) ArtifactInstance. - * @param knownStatus The known status of the artifact + * @param knownStatus The status to change the artifact to. Should never be KNOWN */ @Override public void setArtifactInstanceKnownStatus(CorrelationAttribute eamArtifact, TskData.FileKnown knownStatus) throws EamDbException { @@ -806,15 +810,17 @@ public class SqliteEamDb extends AbstractSqlEamDb { /** * Get all reference sets * + * @param correlationType Type of sets to return + * * @return List of all reference sets in the central repository * * @throws EamDbException */ @Override - public List getAllReferenceSets() throws EamDbException{ + public List getAllReferenceSets(CorrelationAttribute.Type correlationType) throws EamDbException { try{ acquireSharedLock(); - return super.getAllReferenceSets(); + return super.getAllReferenceSets(correlationType); } finally { releaseSharedLock(); } @@ -986,6 +992,34 @@ public class SqliteEamDb extends AbstractSqlEamDb { } } + /** + * Upgrade the schema of the database (if needed) + * @throws EamDbException + */ + @Override + public void upgradeSchema() throws EamDbException, SQLException { + try{ + acquireExclusiveLock(); + super.upgradeSchema(); + } finally { + releaseExclusiveLock(); + } + } + + /** + * Gets an exclusive lock (if applicable). + * Will return the lock if successful, null if unsuccessful because locking + * isn't supported, and throw an exception if we should have been able to get the + * lock but failed (meaning the database is in use). + * @return the lock, or null if locking is not supported + * @throws EamDbException if the coordination service is running but we fail to get the lock + */ + @Override + public CoordinationService.Lock getExclusiveMultiUserDbLock() throws EamDbException{ + // Multiple users are not supported for SQLite + return null; + } + /** * Acquire the lock that provides exclusive access to the case database. * Call this method in a try block with a call to diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDbSettings.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDbSettings.java old mode 100755 new mode 100644 index c7a3730e46..f006cc7e24 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDbSettings.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDbSettings.java @@ -85,8 +85,6 @@ public final class SqliteEamDbSettings { } catch (NumberFormatException ex) { this.bulkThreshold = DEFAULT_BULK_THRESHHOLD; } - - } public void saveSettings() { @@ -300,6 +298,7 @@ public final class SqliteEamDbSettings { createReferenceSetsTable.append("version text NOT NULL,"); createReferenceSetsTable.append("known_status integer NOT NULL,"); createReferenceSetsTable.append("read_only boolean NOT NULL,"); + createReferenceSetsTable.append("type integer NOT NULL,"); createReferenceSetsTable.append("import_date text NOT NULL,"); createReferenceSetsTable.append("foreign key (org_id) references organizations(id) ON UPDATE SET NULL ON DELETE SET NULL,"); createReferenceSetsTable.append("CONSTRAINT hash_set_unique UNIQUE (set_name, version)"); @@ -434,7 +433,7 @@ public final class SqliteEamDbSettings { } boolean result = EamDbUtil.insertDefaultCorrelationTypes(conn) - && EamDbUtil.insertSchemaVersion(conn) + && EamDbUtil.updateSchemaVersion(conn) && EamDbUtil.insertDefaultOrganization(conn); EamDbUtil.closeConnection(conn); return result; diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java index 88cf1ed59e..b053d9df17 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java @@ -191,7 +191,7 @@ final class CaseEventListener implements PropertyChangeListener { } } - final CorrelationAttribute eamArtifact = EamArtifactUtil.getEamArtifactFromContent(af, + final CorrelationAttribute eamArtifact = EamArtifactUtil.getCorrelationAttributeFromContent(af, knownStatus, comment); if (eamArtifact != null) { @@ -394,7 +394,7 @@ final class CaseEventListener implements PropertyChangeListener { } //if the file will have no tags with a status which would prevent the current status from being changed if (!hasTagWithConflictingKnownStatus) { - final CorrelationAttribute eamArtifact = EamArtifactUtil.getEamArtifactFromContent(contentTag.getContent(), + final CorrelationAttribute eamArtifact = EamArtifactUtil.getCorrelationAttributeFromContent(contentTag.getContent(), tagName.getKnownStatus(), ""); if (eamArtifact != null) { EamDb.getInstance().setArtifactInstanceKnownStatus(eamArtifact, tagName.getKnownStatus()); diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/Installer.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/Installer.java index 8af34bc718..7ca97535d9 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/Installer.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/Installer.java @@ -18,8 +18,13 @@ */ package org.sleuthkit.autopsy.centralrepository.eventlisteners; +import javax.swing.JOptionPane; import org.openide.modules.ModuleInstall; +import org.openide.util.NbBundle; +import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbUtil; +import org.sleuthkit.autopsy.core.RuntimeProperties; import org.sleuthkit.autopsy.coreutils.Logger; /** @@ -40,18 +45,32 @@ public class Installer extends ModuleInstall { } return instance; } - + private Installer() { super(); } - - + + @NbBundle.Messages({"Installer.centralRepoUpgradeFailed.title=Central repository upgrade failed", + "Installer.centralRepoUpgradeFailed.message=Failed to upgrade central repository. It has been disabled." + }) @Override public void restored() { Case.addPropertyChangeListener(pcl); ieListener.installListeners(); - // TODO: create a thread pool to process Runners. + // Perform the database upgrade and inform the user if it fails + if (!EamDbUtil.upgradeDatabase()) { + if (RuntimeProperties.runningWithGUI()) { + WindowManager.getDefault().invokeWhenUIReady(() -> { + JOptionPane.showMessageDialog(null, + NbBundle.getMessage(this.getClass(), + "Installer.centralRepoUpgradeFailed.message"), + NbBundle.getMessage(this.getClass(), + "Installer.centralRepoUpgradeFailed.title"), + JOptionPane.ERROR_MESSAGE); + }); + } + } } @Override diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java index 9e1e36cb8a..09f3c63449 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java @@ -47,7 +47,6 @@ import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.HashUtility; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; -import org.sleuthkit.autopsy.centralrepository.datamodel.EamOrganization; import org.sleuthkit.autopsy.centralrepository.eventlisteners.IngestEventsListener; /** @@ -105,22 +104,21 @@ class IngestModule implements FileIngestModule { return ProcessResult.OK; } - // If unknown to both the hash module and as a globally known artifact in the EAM DB, correlate to other cases - if (af.getKnown() == TskData.FileKnown.UNKNOWN) { - // query db for artifact instances having this MD5 and knownStatus = "Bad". + /* Search the central repo to see if this file was previously + * marked as being bad. Create artifact if it was. */ + if (af.getKnown() != TskData.FileKnown.KNOWN) { try { - // if af.getKnown() is "UNKNOWN" and this artifact instance was marked bad in a previous case, - // create TSK_INTERESTING_FILE artifact on BB. List caseDisplayNames = dbManager.getListCasesHavingArtifactInstancesKnownBad(filesType, md5); if (!caseDisplayNames.isEmpty()) { postCorrelatedBadFileToBlackboard(af, caseDisplayNames); } } catch (EamDbException ex) { - LOGGER.log(Level.SEVERE, "Error counting notable artifacts.", ex); // NON-NLS + LOGGER.log(Level.SEVERE, "Error searching database for artifact.", ex); // NON-NLS return ProcessResult.ERROR; } } + // insert this file into the central repository try { CorrelationAttribute eamArtifact = new CorrelationAttribute(filesType, md5); CorrelationAttributeInstance cefi = new CorrelationAttributeInstance( @@ -128,8 +126,7 @@ class IngestModule implements FileIngestModule { eamDataSource, af.getParentPath() + af.getName(), null, - TskData.FileKnown.UNKNOWN, - CorrelationAttributeInstance.GlobalStatus.LOCAL + TskData.FileKnown.UNKNOWN // NOTE: Known status in the CR is based on tagging, not hashes like the Case Database. ); eamArtifact.addInstance(cefi); dbManager.prepareBulkArtifact(eamArtifact); diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.java index 8b6ce90e96..914d4c4d34 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.java @@ -18,11 +18,14 @@ */ package org.sleuthkit.autopsy.centralrepository.optionspanel; +import java.awt.Cursor; import org.sleuthkit.autopsy.coreutils.Logger; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import javax.swing.JOptionPane; import javax.swing.SwingUtilities; import org.netbeans.spi.options.OptionsPanelController; +import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.corecomponents.OptionsPanel; import org.sleuthkit.autopsy.events.AutopsyEvent; @@ -77,6 +80,32 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i IngestManager.getInstance().addIngestJobEventListener(ingestJobEventListener); ingestStateUpdated(); } + + @Messages({"GlobalSettingsPanel.updateFailed.title=Update failed", + "GlobalSettingsPanel.updateFailed.message=Failed to update database. Central repository has been disabled." + }) + private void updateDatabase(){ + + if(EamDbPlatformEnum.getSelectedPlatform().equals(DISABLED)){ + return; + } + setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + + try { + boolean result = EamDbUtil.upgradeDatabase(); + setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + if(! result){ + JOptionPane.showMessageDialog(null, + NbBundle.getMessage(this.getClass(), + "GlobalSettingsPanel.updateFailed.message"), + NbBundle.getMessage(this.getClass(), + "GlobalSettingsPanel.updateFailed.title"), + JOptionPane.WARNING_MESSAGE); + } + } finally { + setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + } + } /** * This method is called from within the constructor to initialize the form. @@ -315,6 +344,7 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i private void bnDbConfigureActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnDbConfigureActionPerformed store(); EamDbSettingsDialog dialog = new EamDbSettingsDialog(); + updateDatabase(); load(); // reload db settings content and update buttons if (dialog.wasConfigurationChanged()) { firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); @@ -323,8 +353,9 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i private void cbUseCentralRepoActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbUseCentralRepoActionPerformed //if saved setting is disabled checkbox should be disabled already - enableDatabaseConfigureButton(cbUseCentralRepo.isSelected()); - enableButtonSubComponents(cbUseCentralRepo.isSelected() && !EamDbPlatformEnum.getSelectedPlatform().equals(DISABLED)); + store(); + updateDatabase(); + load(); this.ingestStateUpdated(); firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); }//GEN-LAST:event_cbUseCentralRepoActionPerformed diff --git a/Core/src/org/sleuthkit/autopsy/coordinationservice/CoordinationService.java b/Core/src/org/sleuthkit/autopsy/coordinationservice/CoordinationService.java index 2664a32787..5a34a80d58 100755 --- a/Core/src/org/sleuthkit/autopsy/coordinationservice/CoordinationService.java +++ b/Core/src/org/sleuthkit/autopsy/coordinationservice/CoordinationService.java @@ -451,7 +451,8 @@ public final class CoordinationService { CASES("cases"), MANIFESTS("manifests"), - CONFIG("config"); + CONFIG("config"), + CENTRAL_REPO("centralRepository"); private final String displayName; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java index 68aeb01e8c..5a2bb87660 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java @@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.datamodel; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.HashSet; import java.util.List; import javax.swing.Action; @@ -32,8 +33,10 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; import org.sleuthkit.autopsy.directorytree.ViewContextAction; +import org.sleuthkit.autopsy.ingest.runIngestModuleWizard.RunIngestModulesAction; import org.sleuthkit.autopsy.timeline.actions.ViewFileInTimelineAction; import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Directory; import org.sleuthkit.datamodel.TskData.TSK_FS_NAME_FLAG_ENUM; @@ -42,7 +45,7 @@ import org.sleuthkit.datamodel.TskData.TSK_FS_NAME_FLAG_ENUM; * are more directories. */ public class DirectoryNode extends AbstractFsContentNode { - + private static final Logger LOGGER = Logger.getLogger(DirectoryNode.class.getName()); public static final String DOTDOTDIR = NbBundle.getMessage(DirectoryNode.class, "DirectoryNode.parFolder.text"); @@ -88,17 +91,19 @@ public class DirectoryNode extends AbstractFsContentNode { actionsList.add(null); // creates a menu separator } actionsList.add(new NewWindowViewAction(NbBundle.getMessage(this.getClass(), "DirectoryNode.viewInNewWin.text"), this)); - actionsList.add(ViewFileInTimelineAction.createViewFileAction(getContent())); + actionsList.add(ViewFileInTimelineAction.createViewFileAction(content)); actionsList.add(null); // creates a menu separator actionsList.add(ExtractAction.getInstance()); actionsList.add(null); // creates a menu separator + actionsList.add(new RunIngestModulesAction(Collections.singletonList(content))); + actionsList.add(null); // creates a menu separator actionsList.add(AddContentTagAction.getInstance()); - + final Collection selectedFilesList = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); - if(selectedFilesList.size() == 1) { + if (selectedFilesList.size() == 1) { actionsList.add(DeleteFileContentTagAction.getInstance()); } - + actionsList.addAll(ContextMenuExtensionPoint.getActions()); return actionsList.toArray(new Action[actionsList.size()]); } diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java index defd5bfd89..e0c9670a2a 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java @@ -149,6 +149,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat } } }); + Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE, Case.Events.DATA_SOURCE_ADDED), this); this.em.addPropertyChangeListener(this); IngestManager.getInstance().addIngestJobEventListener(this); @@ -642,7 +643,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat * @param newNodes */ @NbBundle.Messages("DirectoryTreeTopComponent.emptyMimeNode.text=Data not available. Run file type identification module.") - private void respondSelection(final Node[] oldNodes, final Node[] newNodes) { + void respondSelection(final Node[] oldNodes, final Node[] newNodes) { if (!Case.isCaseOpen()) { return; } diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExtractUnallocAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExtractUnallocAction.java index 86ad6c967e..bcfa01f997 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExtractUnallocAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExtractUnallocAction.java @@ -147,7 +147,13 @@ final class ExtractUnallocAction extends AbstractAction { uw.execute(); } } else { - logger.log(Level.WARNING, "Tried to get unallocated content from volume ID but " + u.VolumeId + u.llf == null ? "its list of unallocated files was null" : "the volume is locked"); //NON-NLS + if(lockedVols.contains(u.getFileName())){ + logger.log(Level.WARNING, "Tried to get unallocated content but the volume is locked"); // NON_NLS + } else if (u.llf == null){ + logger.log(Level.SEVERE, "Tried to get unallocated content but the list of unallocated files was null"); //NON-NLS + } else { + logger.log(Level.INFO, "No unallocated files found in volume"); //NON-NLS + } } } if (isImage && !copyList.isEmpty()) { @@ -449,7 +455,7 @@ final class ExtractUnallocAction extends AbstractAction { public List visit(Directory dir) { try { for (Content c : dir.getChildren()) { - if (c instanceof VirtualDirectory) { + if ((c instanceof VirtualDirectory) && (c.getName().equals(VirtualDirectory.NAME_UNALLOC))) { return c.accept(this); } } diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java index a1aa1c9a0f..95c5f50c23 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ViewContextAction.java @@ -73,7 +73,7 @@ public class ViewContextAction extends AbstractAction { public ViewContextAction(String displayName, BlackboardArtifactNode artifactNode) { super(displayName); this.content = artifactNode.getLookup().lookup(AbstractFile.class); - if(this.content != null) { + if (this.content != null) { AbstractFile file = (AbstractFile) content; if ((TskData.FileKnown.KNOWN == file.getKnown() && UserPreferences.hideKnownFilesInDataSourcesTree()) || (TskData.TSK_DB_FILES_TYPE_ENUM.SLACK == file.getType() && UserPreferences.hideSlackFilesInDataSourcesTree())) { @@ -122,8 +122,7 @@ public class ViewContextAction extends AbstractAction { @Override @Messages({ "ViewContextAction.errorMessage.cannotFindDirectory=Failed to locate directory.", - "ViewContextAction.errorMessage.cannotSelectDirectory=Failed to select directory in tree.", - }) + "ViewContextAction.errorMessage.cannotSelectDirectory=Failed to select directory in tree.",}) public void actionPerformed(ActionEvent event) { EventQueue.invokeLater(() -> { /* @@ -132,7 +131,6 @@ public class ViewContextAction extends AbstractAction { DirectoryTreeTopComponent treeViewTopComponent = DirectoryTreeTopComponent.findInstance(); ExplorerManager treeViewExplorerMgr = treeViewTopComponent.getExplorerManager(); Node parentTreeViewNode = treeViewExplorerMgr.getRootContext().getChildren().findChild(DataSourcesNode.NAME); - /* * Get the parent content for the content to be selected in the * results view. If the parent content is null, then the specified @@ -204,11 +202,21 @@ public class ViewContextAction extends AbstractAction { undecoratedParentNode.setChildNodeSelectionInfo(new ContentNodeSelectionInfo(content)); TreeView treeView = treeViewTopComponent.getTree(); treeView.expandNode(parentTreeViewNode); - try { - treeViewExplorerMgr.setExploredContextAndSelection(parentTreeViewNode, new Node[]{parentTreeViewNode}); - } catch (PropertyVetoException ex) { - MessageNotifyUtil.Message.error(Bundle.ViewContextAction_errorMessage_cannotSelectDirectory()); - logger.log(Level.SEVERE, "Failed to select the parent node in the tree view", ex); //NON-NLS + if (treeViewTopComponent.getSelectedNode().getDisplayName().equals(parentTreeViewNode.getDisplayName())) { + //In the case where our tree view already has the destination directory selected + //due to an optimization in the ExplorerManager.setExploredContextAndSelection method + //the property change we listen for to call DirectoryTreeTopComponent.respondSelection + //will not be sent so we call it manually ourselves after making + //the directory listing the active tab. + treeViewTopComponent.setDirectoryListingActive(); + treeViewTopComponent.respondSelection(treeViewExplorerMgr.getSelectedNodes(), new Node[]{parentTreeViewNode}); + } else { + try { + treeViewExplorerMgr.setExploredContextAndSelection(parentTreeViewNode, new Node[]{parentTreeViewNode}); + } catch (PropertyVetoException ex) { + MessageNotifyUtil.Message.error(Bundle.ViewContextAction_errorMessage_cannotSelectDirectory()); + logger.log(Level.SEVERE, "Failed to select the parent node in the tree view", ex); //NON-NLS + } } }); } @@ -264,5 +272,5 @@ public class ViewContextAction extends AbstractAction { return parent == null ? lineage : parent.accept(this); } } - + } diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/Bundle.properties b/Core/src/org/sleuthkit/autopsy/filesearch/Bundle.properties index bb91c8e05c..6d83acae14 100755 --- a/Core/src/org/sleuthkit/autopsy/filesearch/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/filesearch/Bundle.properties @@ -12,11 +12,7 @@ DateSearchPanel.createdCheckBox.text=Created DateSearchPanel.accessedCheckBox.text=Accessed DateSearchPanel.changedCheckBox.text=Changed DateSearchPanel.modifiedCheckBox.text=Modified -DateSearchPanel.dateToButtonCalendar.text= -DateSearchPanel.dateToTextField.text= DateSearchPanel.jLabel1.text=to -DateSearchPanel.dateFromTextField.text= -DateSearchPanel.dateFromButtonCalendar.text= NameSearchPanel.nameCheckBox.text=Name: NameSearchPanel.noteNameLabel.text=*Note: Name match is case insensitive and matches any part of the file name. Regular expressions are not currently supported. NameSearchPanel.searchTextField.text= diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchFilter.java b/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchFilter.java index 3291c5ae42..64666e66d9 100755 --- a/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchFilter.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchFilter.java @@ -82,7 +82,7 @@ class DateSearchFilter extends AbstractFileSearchFilter { // convert the date from the selected timezone to get the GMT long fromDate = 0; - String startDateValue = panel.getDateFromTextField().getText(); + String startDateValue = panel.getFromDate(); Calendar startDate = getCalendarDate(startDateValue); if (!startDateValue.isEmpty()) { if (startDate != null) { @@ -91,7 +91,7 @@ class DateSearchFilter extends AbstractFileSearchFilter { } long toDate = 0; - String endDateValue = panel.getDateToTextField().getText(); + String endDateValue = panel.getToDate(); Calendar endDate = getCalendarDate(endDateValue); if (!endDateValue.isEmpty()) { if (endDate != null) { @@ -199,7 +199,7 @@ class DateSearchFilter extends AbstractFileSearchFilter { @Override public void addActionListener(ActionListener l) { - getComponent().addActionListener(l); + getComponent().addDateChangeListener(); } @Override @@ -210,8 +210,8 @@ class DateSearchFilter extends AbstractFileSearchFilter { public boolean isValid() { DateSearchPanel panel = this.getComponent(); - Calendar startDate = getCalendarDate(panel.getDateFromTextField().getText()); - Calendar endDate = getCalendarDate(panel.getDateToTextField().getText()); + Calendar startDate = getCalendarDate(panel.getFromDate()); + Calendar endDate = getCalendarDate(panel.getToDate()); if ((startDate != null && startDate.after(endDate)) || (endDate != null && endDate.before(startDate))) { setLastError(Bundle.DateSearchFilter_errorMessage_endDateBeforeStartDate()); diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchPanel.form b/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchPanel.form index 59082745da..0d2d2b3d19 100755 --- a/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchPanel.form +++ b/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchPanel.form @@ -55,28 +55,11 @@ - - - - - - - - - - - - - - - - - - - - - - + + + + + @@ -98,27 +81,31 @@ + + + + + + + + + + - - - - - + + - - - - - - - - + + + + + @@ -147,20 +134,6 @@ - - - - - - - - - - - - - - @@ -199,36 +172,22 @@ - - - - - - - - - - - - - - - - - - - - - + + + + + + + @@ -275,25 +234,23 @@ - - - - - - + - + + + + + - - - - - - + - + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchPanel.java b/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchPanel.java index b9f490041b..1c38b7e35b 100755 --- a/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchPanel.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchPanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011 Basis Technology Corp. + * Copyright 2011-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,22 +21,28 @@ package org.sleuthkit.autopsy.filesearch; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.text.DateFormat; -import java.text.ParseException; -import java.util.Date; import java.util.List; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JFormattedTextField; import javax.swing.JMenuItem; import javax.swing.JPopupMenu; -import javax.swing.event.DocumentEvent; -import javax.swing.event.DocumentListener; +import com.github.lgooddatepicker.components.DatePicker; +import com.github.lgooddatepicker.optionalusertools.PickerUtilities; +import com.github.lgooddatepicker.components.DatePickerSettings; +import com.github.lgooddatepicker.optionalusertools.DateChangeListener; +import com.github.lgooddatepicker.zinternaltools.DateChangeEvent; +import java.text.ParseException; +import java.time.Instant; +import java.util.Date; /** * Subpanel with controls for file data filtering. */ class DateSearchPanel extends javax.swing.JPanel { + private final DatePickerSettings fromDateSettings = new DatePickerSettings(); + private final DatePickerSettings toDateSettings = new DatePickerSettings(); DateFormat dateFormat; List timeZones; @@ -49,10 +55,11 @@ class DateSearchPanel extends javax.swing.JPanel { } private void customizeComponents() { - - dateFromTextField.setComponentPopupMenu(rightClickMenu); - dateToTextField.setComponentPopupMenu(rightClickMenu); - + fromDateSettings.setFormatForDatesCommonEra(PickerUtilities.createFormatterFromPatternString("MM/dd/yyyy", fromDateSettings.getLocale())); + toDateSettings.setFormatForDatesCommonEra(PickerUtilities.createFormatterFromPatternString("MM/dd/yyyy", toDateSettings.getLocale())); + fromDateSettings.setAllowKeyboardEditing(false); + toDateSettings.setAllowKeyboardEditing(false); + ActionListener actList = new ActionListener() { @Override public void actionPerformed(ActionEvent e) { @@ -77,41 +84,7 @@ class DateSearchPanel extends javax.swing.JPanel { copyMenuItem.addActionListener(actList); pasteMenuItem.addActionListener(actList); selectAllMenuItem.addActionListener(actList); - this.dateFromTextField.getDocument().addDocumentListener(new DocumentListener() { - @Override - public void insertUpdate(DocumentEvent e) { - firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null); - } - - @Override - public void removeUpdate(DocumentEvent e) { - firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null); - } - - @Override - public void changedUpdate(DocumentEvent e) { - firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null); - } - }); - - this.dateToTextField.getDocument().addDocumentListener(new DocumentListener() { - @Override - public void insertUpdate(DocumentEvent e) { - firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null); - } - - @Override - public void removeUpdate(DocumentEvent e) { - firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null); - } - - @Override - public void changedUpdate(DocumentEvent e) { - firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null); - } - }); - - + this.setComponentsEnabled(); } @@ -131,12 +104,12 @@ class DateSearchPanel extends javax.swing.JPanel { return dateCheckBox; } - JFormattedTextField getDateFromTextField() { - return dateFromTextField; + String getFromDate() { + return fromDatePicker.getText(); } - JFormattedTextField getDateToTextField() { - return dateToTextField; + String getToDate() { + return toDatePicker.getText(); } JCheckBox getModifiedCheckBox() { @@ -157,11 +130,9 @@ class DateSearchPanel extends javax.swing.JPanel { private void setComponentsEnabled() { boolean enable = this.dateCheckBox.isSelected(); - this.dateFromTextField.setEnabled(enable); - this.dateFromButtonCalendar.setEnabled(enable); + this.fromDatePicker.setEnabled(enable); this.jLabel1.setEnabled(enable); - this.dateToTextField.setEnabled(enable); - this.dateToButtonCalendar.setEnabled(enable); + this.toDatePicker.setEnabled(enable); this.jLabel2.setEnabled(enable); this.jLabel3.setEnabled(enable); this.jLabel4.setEnabled(enable); @@ -186,21 +157,19 @@ class DateSearchPanel extends javax.swing.JPanel { copyMenuItem = new javax.swing.JMenuItem(); pasteMenuItem = new javax.swing.JMenuItem(); selectAllMenuItem = new javax.swing.JMenuItem(); - dateToTextField = new JFormattedTextField(this.dateFormat); jLabel1 = new javax.swing.JLabel(); jLabel4 = new javax.swing.JLabel(); dateCheckBox = new javax.swing.JCheckBox(); timeZoneComboBox = new JComboBox<>(this.timeZones.toArray(new String[this.timeZones.size()])); timeZoneComboBox.setRenderer(new DateSearchFilter.ComboBoxRenderer()); jLabel3 = new javax.swing.JLabel(); - dateFromTextField = new JFormattedTextField(this.dateFormat); jLabel2 = new javax.swing.JLabel(); modifiedCheckBox = new javax.swing.JCheckBox(); changedCheckBox = new javax.swing.JCheckBox(); accessedCheckBox = new javax.swing.JCheckBox(); createdCheckBox = new javax.swing.JCheckBox(); - dateFromButtonCalendar = new org.jbundle.thin.base.screen.jcalendarbutton.JCalendarButton(); - dateToButtonCalendar = new org.jbundle.thin.base.screen.jcalendarbutton.JCalendarButton(); + fromDatePicker = new DatePicker(fromDateSettings); + toDatePicker = new DatePicker(toDateSettings); cutMenuItem.setText(org.openide.util.NbBundle.getMessage(DateSearchPanel.class, "DateSearchPanel.cutMenuItem.text")); // NOI18N rightClickMenu.add(cutMenuItem); @@ -214,14 +183,6 @@ class DateSearchPanel extends javax.swing.JPanel { selectAllMenuItem.setText(org.openide.util.NbBundle.getMessage(DateSearchPanel.class, "DateSearchPanel.selectAllMenuItem.text")); // NOI18N rightClickMenu.add(selectAllMenuItem); - dateToTextField.setEditable(false); - dateToTextField.setText(org.openide.util.NbBundle.getMessage(DateSearchPanel.class, "DateSearchPanel.dateToTextField.text")); // NOI18N - dateToTextField.addFocusListener(new java.awt.event.FocusAdapter() { - public void focusLost(java.awt.event.FocusEvent evt) { - dateToTextFieldFocusLost(evt); - } - }); - jLabel1.setText(org.openide.util.NbBundle.getMessage(DateSearchPanel.class, "DateSearchPanel.jLabel1.text")); // NOI18N jLabel4.setText(org.openide.util.NbBundle.getMessage(DateSearchPanel.class, "DateSearchPanel.jLabel4.text")); // NOI18N @@ -233,19 +194,11 @@ class DateSearchPanel extends javax.swing.JPanel { } }); - jLabel3.setFont(new java.awt.Font("Tahoma", 0, 10)); // NOI18N jLabel3.setText(org.openide.util.NbBundle.getMessage(DateSearchPanel.class, "DateSearchPanel.jLabel3.text")); // NOI18N + jLabel3.setFont(new java.awt.Font("Tahoma", 0, 10)); // NOI18N - dateFromTextField.setEditable(false); - dateFromTextField.setText(org.openide.util.NbBundle.getMessage(DateSearchPanel.class, "DateSearchPanel.dateFromTextField.text")); // NOI18N - dateFromTextField.addFocusListener(new java.awt.event.FocusAdapter() { - public void focusLost(java.awt.event.FocusEvent evt) { - dateFromTextFieldFocusLost(evt); - } - }); - - jLabel2.setFont(new java.awt.Font("Tahoma", 0, 10)); // NOI18N jLabel2.setText(org.openide.util.NbBundle.getMessage(DateSearchPanel.class, "DateSearchPanel.jLabel2.text")); // NOI18N + jLabel2.setFont(new java.awt.Font("Tahoma", 0, 10)); // NOI18N modifiedCheckBox.setSelected(true); modifiedCheckBox.setText(org.openide.util.NbBundle.getMessage(DateSearchPanel.class, "DateSearchPanel.modifiedCheckBox.text")); // NOI18N @@ -279,17 +232,25 @@ class DateSearchPanel extends javax.swing.JPanel { } }); - dateFromButtonCalendar.setText(org.openide.util.NbBundle.getMessage(DateSearchPanel.class, "DateSearchPanel.dateFromButtonCalendar.text")); // NOI18N - dateFromButtonCalendar.addPropertyChangeListener(new java.beans.PropertyChangeListener() { + fromDatePicker.addFocusListener(new java.awt.event.FocusAdapter() { + public void focusLost(java.awt.event.FocusEvent evt) { + fromDatePickerFocusLost(evt); + } + }); + fromDatePicker.addPropertyChangeListener(new java.beans.PropertyChangeListener() { public void propertyChange(java.beans.PropertyChangeEvent evt) { - dateFromPopupChanged(evt); + fromDatePickerPropertyChange(evt); } }); - dateToButtonCalendar.setText(org.openide.util.NbBundle.getMessage(DateSearchPanel.class, "DateSearchPanel.dateToButtonCalendar.text")); // NOI18N - dateToButtonCalendar.addPropertyChangeListener(new java.beans.PropertyChangeListener() { + toDatePicker.addFocusListener(new java.awt.event.FocusAdapter() { + public void focusLost(java.awt.event.FocusEvent evt) { + toDatePickerFocusLost(evt); + } + }); + toDatePicker.addPropertyChangeListener(new java.beans.PropertyChangeListener() { public void propertyChange(java.beans.PropertyChangeEvent evt) { - dateToPopupChanged(evt); + toDatePickerPropertyChange(evt); } }); @@ -298,25 +259,11 @@ class DateSearchPanel extends javax.swing.JPanel { layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addGroup(layout.createSequentialGroup() - .addComponent(dateCheckBox) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(dateFromTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 92, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(0, 0, 0) - .addComponent(dateFromButtonCalendar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(jLabel1) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(dateToTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 92, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(0, 0, 0) - .addComponent(dateToButtonCalendar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addContainerGap() - .addComponent(jLabel2) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(jLabel3))) - .addContainerGap(26, Short.MAX_VALUE)) + .addContainerGap() + .addComponent(jLabel2) + .addGap(18, 18, 18) + .addComponent(jLabel3) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() .addGap(0, 0, Short.MAX_VALUE) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -333,23 +280,28 @@ class DateSearchPanel extends javax.swing.JPanel { .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(changedCheckBox))) .addGap(33, 33, 33)) + .addGroup(layout.createSequentialGroup() + .addComponent(dateCheckBox) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(fromDatePicker, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 10, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(10, 10, 10) + .addComponent(toDatePicker, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap()) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) .addGroup(layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(dateCheckBox) - .addComponent(dateFromTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(dateCheckBox) .addGap(18, 18, 18)) .addGroup(layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(dateToButtonCalendar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(jLabel1) - .addComponent(dateToTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addComponent(dateFromButtonCalendar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jLabel1) + .addComponent(fromDatePicker, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(toDatePicker, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(jLabel3) @@ -369,45 +321,6 @@ class DateSearchPanel extends javax.swing.JPanel { ); }// //GEN-END:initComponents - private void dateFromTextFieldFocusLost(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_dateFromTextFieldFocusLost - // set the "from" calendar button to listen to change in the text field - String fromDateString = this.dateFromTextField.getText(); - if (!fromDateString.equals("")) { - try { - Date fromDate = dateFormat.parse(fromDateString); - dateFromButtonCalendar.setTargetDate(fromDate); - } catch (ParseException ex) { - // for now, no need to show the error message to the user her - } - } - }//GEN-LAST:event_dateFromTextFieldFocusLost - - private void dateToTextFieldFocusLost(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_dateToTextFieldFocusLost - // set the "to" calendar button to listen to change in the text field - String toDateString = this.dateToTextField.getText(); - if (!toDateString.equals("")) { - try { - Date toDate = dateFormat.parse(toDateString); - dateToButtonCalendar.setTargetDate(toDate); - } catch (ParseException ex) { - // for now, no need to show the error message to the user here - } - } - }//GEN-LAST:event_dateToTextFieldFocusLost - - private void dateFromPopupChanged(java.beans.PropertyChangeEvent evt) {//GEN-FIRST:event_dateFromPopupChanged - if (evt.getNewValue() instanceof Date) { - setFromDate((Date) evt.getNewValue()); - } - }//GEN-LAST:event_dateFromPopupChanged - - private void dateToPopupChanged(java.beans.PropertyChangeEvent evt) {//GEN-FIRST:event_dateToPopupChanged - if (evt.getNewValue() instanceof Date) { - setToDate((Date) evt.getNewValue()); - } - - }//GEN-LAST:event_dateToPopupChanged - private void dateCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_dateCheckBoxActionPerformed this.setComponentsEnabled(); firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null); @@ -429,6 +342,44 @@ class DateSearchPanel extends javax.swing.JPanel { firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null); }//GEN-LAST:event_changedCheckBoxActionPerformed + private void fromDatePickerPropertyChange(java.beans.PropertyChangeEvent evt) {//GEN-FIRST:event_fromDatePickerPropertyChange + if (evt.getNewValue() instanceof Date) { + setFromDate((Date) evt.getNewValue()); + } + }//GEN-LAST:event_fromDatePickerPropertyChange + + private void toDatePickerPropertyChange(java.beans.PropertyChangeEvent evt) {//GEN-FIRST:event_toDatePickerPropertyChange + if (evt.getNewValue() instanceof Date) { + setToDate((Date) evt.getNewValue()); + } + }//GEN-LAST:event_toDatePickerPropertyChange + + private void fromDatePickerFocusLost(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_fromDatePickerFocusLost + // set the "from" calendar button to listen to change in the text field + String fromDateString = this.fromDatePicker.getText(); + if (!fromDateString.equals("")) { + try { + Date fromDate = dateFormat.parse(fromDateString); + fromDatePicker.setDate(fromDate.toInstant().atZone(dateFormat.getTimeZone().toZoneId()).toLocalDate()); + } catch (ParseException ex) { + // for now, no need to show the error message to the user her + } + } + }//GEN-LAST:event_fromDatePickerFocusLost + + private void toDatePickerFocusLost(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_toDatePickerFocusLost + // set the "to" calendar button to listen to change in the text field + String toDateString = this.toDatePicker.getText(); + if (!toDateString.equals("")) { + try { + Date toDate = dateFormat.parse(toDateString); + toDatePicker.setDate(toDate.toInstant().atZone(dateFormat.getTimeZone().toZoneId()).toLocalDate()); + } catch (ParseException ex) { + // for now, no need to show the error message to the user here + } + } + }//GEN-LAST:event_toDatePickerFocusLost + /** * Validate and set the datetime field on the screen given a datetime * string. @@ -437,12 +388,18 @@ class DateSearchPanel extends javax.swing.JPanel { */ private void setFromDate(Date date) { String dateStringResult = ""; + Instant ins = null; if (date != null) { dateStringResult = dateFormat.format(date); + ins = date.toInstant(); } - dateFromTextField.setText(dateStringResult); - dateFromButtonCalendar.setTargetDate(date); + fromDatePicker.setText(dateStringResult); + if (ins != null) { + fromDatePicker.setDate(ins.atZone(dateFormat.getTimeZone().toZoneId()).toLocalDate()); + } else { + fromDatePicker.setDate(null); + } } /** @@ -452,13 +409,19 @@ class DateSearchPanel extends javax.swing.JPanel { */ private void setToDate(Date date) { String dateStringResult = ""; + Instant ins = null; if (date != null) { dateStringResult = dateFormat.format(date); + ins = date.toInstant(); + } + toDatePicker.setText(dateStringResult); + if (ins != null) { + toDatePicker.setDate(ins.atZone(dateFormat.getTimeZone().toZoneId()).toLocalDate()); + } else { + toDatePicker.setDate(null); } - dateToTextField.setText(dateStringResult); - dateToButtonCalendar.setTargetDate(date); } - + boolean isValidSearch() { return this.accessedCheckBox.isSelected() || this.changedCheckBox.isSelected() || @@ -472,10 +435,7 @@ class DateSearchPanel extends javax.swing.JPanel { private javax.swing.JCheckBox createdCheckBox; private javax.swing.JMenuItem cutMenuItem; private javax.swing.JCheckBox dateCheckBox; - private org.jbundle.thin.base.screen.jcalendarbutton.JCalendarButton dateFromButtonCalendar; - private javax.swing.JFormattedTextField dateFromTextField; - private org.jbundle.thin.base.screen.jcalendarbutton.JCalendarButton dateToButtonCalendar; - private javax.swing.JFormattedTextField dateToTextField; + private com.github.lgooddatepicker.components.DatePicker fromDatePicker; private javax.swing.JLabel jLabel1; private javax.swing.JLabel jLabel2; private javax.swing.JLabel jLabel3; @@ -485,10 +445,17 @@ class DateSearchPanel extends javax.swing.JPanel { private javax.swing.JPopupMenu rightClickMenu; private javax.swing.JMenuItem selectAllMenuItem; private javax.swing.JComboBox timeZoneComboBox; + private com.github.lgooddatepicker.components.DatePicker toDatePicker; // End of variables declaration//GEN-END:variables - void addActionListener(ActionListener l) { - dateFromTextField.addActionListener(l); - dateToTextField.addActionListener(l); + void addDateChangeListener() { + DateChangeListener dcl = (DateChangeEvent event) -> { + firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null); + }; + + fromDatePicker.addDateChangeListener(dcl); + toDatePicker.addDateChangeListener(dcl); } + } + diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.form b/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.form index a64489bb01..f6fd00903f 100755 --- a/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.form +++ b/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.form @@ -37,10 +37,7 @@ - - - - + @@ -70,9 +67,6 @@ - - - diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.java b/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.java index f6c72df611..e39070cd70 100755 --- a/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.java @@ -27,6 +27,7 @@ package org.sleuthkit.autopsy.filesearch; import java.awt.Component; import java.awt.Cursor; import java.awt.Dimension; +import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; @@ -110,7 +111,12 @@ class FileSearchPanel extends javax.swing.JPanel { } }); } - + addListenerToAll(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + search(); + } + }); searchButton.setEnabled(isValidSearch()); } @@ -284,11 +290,6 @@ class FileSearchPanel extends javax.swing.JPanel { filterPanel.setLayout(new javax.swing.BoxLayout(filterPanel, javax.swing.BoxLayout.Y_AXIS)); searchButton.setText(org.openide.util.NbBundle.getMessage(FileSearchPanel.class, "FileSearchPanel.searchButton.text")); // NOI18N - searchButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - searchButtonActionPerformed(evt); - } - }); errorLabel.setForeground(new java.awt.Color(255, 51, 51)); errorLabel.setText(org.openide.util.NbBundle.getMessage(FileSearchPanel.class, "FileSearchPanel.errorLabel.text")); // NOI18N @@ -311,17 +312,11 @@ class FileSearchPanel extends javax.swing.JPanel { .addComponent(filterPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 266, Short.MAX_VALUE) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) .addComponent(searchButton) - .addGroup(layout.createSequentialGroup() - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(errorLabel))) + .addComponent(errorLabel)) .addContainerGap()) ); }// //GEN-END:initComponents - private void searchButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_searchButtonActionPerformed - search(); - }//GEN-LAST:event_searchButtonActionPerformed - // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JLabel errorLabel; private javax.swing.JPanel filterPanel; diff --git a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesAction.java b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesAction.java index 2f15a74c64..e97ec1e6ed 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesAction.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/runIngestModuleWizard/RunIngestModulesAction.java @@ -26,6 +26,7 @@ import java.util.List; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.JOptionPane; +import javax.swing.RootPaneContainer; import org.openide.DialogDisplayer; import org.openide.WizardDescriptor; import org.openide.util.NbBundle.Messages; @@ -50,6 +51,7 @@ public final class RunIngestModulesAction extends AbstractAction { * used instead of this wizard and is retained for backwards compatibility. */ private static final String EXECUTION_CONTEXT = "org.sleuthkit.autopsy.ingest.RunIngestModulesDialog"; + /** * Display any warnings that the ingestJobSettings have. * @@ -104,12 +106,15 @@ public final class RunIngestModulesAction extends AbstractAction { * argument in the title format string will be supplied by * WizardDescriptor.Panel.getComponent().getName(). */ - WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + RootPaneContainer root = (RootPaneContainer) WindowManager.getDefault().getMainWindow(); + root.getGlassPane().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + root.getGlassPane().setVisible(true); RunIngestModulesWizardIterator wizard = new RunIngestModulesWizardIterator(EXECUTION_CONTEXT, this.ingestType, this.dataSources); WizardDescriptor wiz = new WizardDescriptor(wizard); wiz.setTitleFormat(new MessageFormat("{0}")); wiz.setTitle(Bundle.RunIngestModulesAction_name()); - WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + root.getGlassPane().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + root.getGlassPane().setVisible(false); if (DialogDisplayer.getDefault().notify(wiz) == WizardDescriptor.FINISH_OPTION) { IngestJobSettings ingestJobSettings = wizard.getIngestJobSettings(); showWarnings(ingestJobSettings); @@ -117,7 +122,6 @@ public final class RunIngestModulesAction extends AbstractAction { } } - @Override public Object clone() throws CloneNotSupportedException { throw new CloneNotSupportedException("Clone is not supported for the RunIngestModulesAction"); diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java index 13dd9bcd63..701b2995a8 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java @@ -31,6 +31,7 @@ import javax.swing.JOptionPane; import org.apache.commons.io.FilenameUtils; import org.openide.util.NbBundle; import org.openide.windows.WindowManager; +import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttribute; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbUtil; @@ -527,7 +528,7 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { try{ int referenceSetID = EamDb.getInstance().newReferenceSet(new EamGlobalSet(selectedOrg.getOrgID(), hashSetNameTextField.getText(), - "", fileKnown, false)); + "", fileKnown, false, EamDb.getInstance().getCorrelationTypeById(CorrelationAttribute.FILES_TYPE_ID))); newHashDb = HashDbManager.getInstance().addExistingCentralRepoHashSet(hashSetNameTextField.getText(), "", referenceSetID, true, sendIngestMessagesCheckbox.isSelected(), type, false); diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java index 34770aa6fa..c032bdc83e 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java @@ -490,7 +490,7 @@ public class HashDbManager implements PropertyChangeListener { List crHashSets = new ArrayList<>(); if(EamDb.isEnabled()){ try{ - List crSets = EamDb.getInstance().getAllReferenceSets(); + List crSets = EamDb.getInstance().getAllReferenceSets(EamDb.getInstance().getCorrelationTypeById(CorrelationAttribute.FILES_TYPE_ID)); for(EamGlobalSet globalSet:crSets){ // Defaults for fields not stored in the central repository: diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ImportCentralRepoDbProgressDialog.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ImportCentralRepoDbProgressDialog.java index 37d3a20009..bbcc503b08 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ImportCentralRepoDbProgressDialog.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ImportCentralRepoDbProgressDialog.java @@ -237,7 +237,8 @@ class ImportCentralRepoDbProgressDialog extends javax.swing.JDialog implements P // Create an empty hashset in the central repository EamDb dbManager = EamDb.getInstance(); - referenceSetID.set(dbManager.newReferenceSet(new EamGlobalSet(orgId, hashSetName, version, knownStatus, readOnly))); + referenceSetID.set(dbManager.newReferenceSet(new EamGlobalSet(orgId, hashSetName, version, knownStatus, + readOnly, EamDb.getInstance().getCorrelationTypeById(CorrelationAttribute.FILES_TYPE_ID)))); // Get the "FILES" content type. This is a database lookup so we // only want to do it once. diff --git a/CoreLibs/ivy.xml b/CoreLibs/ivy.xml index 32c7186ae5..b5de9e9ac2 100755 --- a/CoreLibs/ivy.xml +++ b/CoreLibs/ivy.xml @@ -13,7 +13,6 @@ - diff --git a/CoreLibs/nbproject/project.properties b/CoreLibs/nbproject/project.properties index 4218ccab88..09225d0115 100755 --- a/CoreLibs/nbproject/project.properties +++ b/CoreLibs/nbproject/project.properties @@ -44,7 +44,6 @@ file.reference.imgscalr-lib-4.2-sources.jar=release/modules/ext/imgscalr-lib-4.2 file.reference.imgscalr-lib-4.2.jar=release/modules/ext/imgscalr-lib-4.2.jar file.reference.javaee-api-5.0-2.jar=release/modules/ext/javaee-api-5.0-2.jar file.reference.javassist-3.12.1.GA.jar=release/modules/ext/javassist-3.12.1.GA.jar -file.reference.jcalendarbutton-1.4.6.jar=release/modules/ext/jcalendarbutton-1.4.6.jar file.reference.jfxtras-common-8.0-r4.jar=release/modules/ext/jfxtras-common-8.0-r4.jar file.reference.jfxtras-controls-8.0-r4.jar=release/modules/ext/jfxtras-controls-8.0-r4.jar file.reference.jfxtras-fxml-8.0-r4.jar=release/modules/ext/jfxtras-fxml-8.0-r4.jar diff --git a/CoreLibs/nbproject/project.xml b/CoreLibs/nbproject/project.xml index cc752d4833..5b4cb9fd83 100755 --- a/CoreLibs/nbproject/project.xml +++ b/CoreLibs/nbproject/project.xml @@ -215,7 +215,6 @@ jfxtras.scene.control jfxtras.scene.layout jfxtras.util - net.sourceforge.jcalendarbutton org.apache.avalon.framework org.apache.avalon.framework.activity org.apache.avalon.framework.component @@ -590,7 +589,6 @@ org.hyperic.sigar.vmware org.hyperic.sigar.win32 org.imgscalr - org.jbundle.thin.base.screen.jcalendarbutton org.joda.time org.joda.time.base org.joda.time.chrono @@ -633,7 +631,6 @@ org.slf4j.helpers org.slf4j.impl org.slf4j.spi - org.sourceforge.jcalendarbutton org.w3c.dom org.w3c.dom.css org.w3c.dom.events @@ -770,10 +767,6 @@ ext/poi-excelant-3.15.jar release/modules/ext/poi-excelant-3.15.jar - - ext/jcalendarbutton-1.4.6.jar - release/modules/ext/jcalendarbutton-1.4.6.jar - ext/imageio-psd-3.2.jar release/modules/ext/imageio-psd-3.2.jar diff --git a/Experimental/ivy.xml b/Experimental/ivy.xml index e50fab6472..93d6dafa8d 100755 --- a/Experimental/ivy.xml +++ b/Experimental/ivy.xml @@ -5,7 +5,7 @@ - + diff --git a/Experimental/nbproject/project.properties b/Experimental/nbproject/project.properties index d47542bdb5..1bd0e2fc90 100755 --- a/Experimental/nbproject/project.properties +++ b/Experimental/nbproject/project.properties @@ -1,10 +1,10 @@ file.reference.c3p0-0.9.5.jar=release/modules/ext/c3p0-0.9.5.jar file.reference.jackson-core-2.7.0.jar=release/modules/ext/jackson-core-2.7.0.jar -file.reference.LGoodDatePicker-4.3.1.jar=release/modules/ext/LGoodDatePicker-4.3.1.jar +file.reference.LGoodDatePicker-10.3.1.jar=release/modules/ext/LGoodDatePicker-10.3.1.jar file.reference.mchange-commons-java-0.2.9.jar=release/modules/ext/mchange-commons-java-0.2.9.jar file.reference.postgresql-9.4-1201-jdbc41.jar=release/modules/ext/postgresql-9.4-1201-jdbc41.jar file.reference.tika-core-1.14.jar=release/modules/ext/tika-core-1.14.jar javac.source=1.8 javac.compilerargs=-Xlint -Xlint:-serial -javadoc.reference.LGoodDatePicker-4.3.1.jar=release/modules/ext/LGoodDatePicker-4.3.1-javadoc.jar -source.reference.LGoodDatePicker-4.3.1.jar=release/modules/ext/LGoodDatePicker-4.3.1-sources.jar +javadoc.reference.LGoodDatePicker-10.3.1.jar=release/modules/ext/LGoodDatePicker-10.3.1-javadoc.jar +source.reference.LGoodDatePicker-10.3.1.jar=release/modules/ext/LGoodDatePicker-10.3.1-sources.jar diff --git a/Experimental/nbproject/project.xml b/Experimental/nbproject/project.xml index 78e13b64ed..8293608102 100755 --- a/Experimental/nbproject/project.xml +++ b/Experimental/nbproject/project.xml @@ -145,18 +145,18 @@ org.sleuthkit.autopsy.experimental.autoingest org.sleuthkit.autopsy.experimental.configuration - - ext/mchange-commons-java-0.2.9.jar - release/modules/ext/mchange-commons-java-0.2.9.jar - - - ext/LGoodDatePicker-4.3.1.jar - release/modules/ext/LGoodDatePicker-4.3.1.jar - ext/tika-core-1.14.jar release/modules/ext/tika-core-1.14.jar + + ext/LGoodDatePicker-10.3.1.jar + release/modules/ext/LGoodDatePicker-10.3.1.jar + + + ext/mchange-commons-java-0.2.9.jar + release/modules/ext/mchange-commons-java-0.2.9.jar + ext/jackson-core-2.7.0.jar release/modules/ext/jackson-core-2.7.0.jar diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMetricsDialog.form b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMetricsDialog.form index cbe7b53c2f..1ec767ba21 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMetricsDialog.form +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMetricsDialog.form @@ -31,9 +31,9 @@ - + - + @@ -51,8 +51,10 @@ - - + + + + @@ -103,16 +105,6 @@ - - - - - - - - - - @@ -120,5 +112,12 @@ + + + + + + + diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMetricsDialog.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMetricsDialog.java index af0679be5f..990d04e244 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMetricsDialog.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMetricsDialog.java @@ -18,7 +18,6 @@ */ package org.sleuthkit.autopsy.experimental.autoingest; -import com.github.lgooddatepicker.datepicker.DatePicker; import java.awt.Container; import java.awt.Cursor; import java.awt.Window; @@ -139,8 +138,8 @@ final class AutoIngestMetricsDialog extends javax.swing.JDialog { jScrollPane1 = new javax.swing.JScrollPane(); reportTextArea = new javax.swing.JTextArea(); metricsButton = new javax.swing.JButton(); - datePicker = new DatePicker(); startingDataLabel = new javax.swing.JLabel(); + datePicker = new com.github.lgooddatepicker.components.DatePicker(); setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); setAlwaysOnTop(true); @@ -166,10 +165,10 @@ final class AutoIngestMetricsDialog extends javax.swing.JDialog { } }); - datePicker.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestMetricsDialog.class, "AutoIngestMetricsDialog.datePicker.toolTipText")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(startingDataLabel, org.openide.util.NbBundle.getMessage(AutoIngestMetricsDialog.class, "AutoIngestMetricsDialog.startingDataLabel.text")); // NOI18N + datePicker.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestMetricsDialog.class, "AutoIngestMetricsDialog.datePicker.toolTipText")); // NOI18N + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( @@ -180,9 +179,9 @@ final class AutoIngestMetricsDialog extends javax.swing.JDialog { .addComponent(jScrollPane1) .addGroup(layout.createSequentialGroup() .addComponent(startingDataLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(datePicker, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 7, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(metricsButton)) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() .addGap(0, 0, Short.MAX_VALUE) @@ -195,8 +194,9 @@ final class AutoIngestMetricsDialog extends javax.swing.JDialog { .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(metricsButton) - .addComponent(datePicker, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(startingDataLabel)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(startingDataLabel) + .addComponent(datePicker, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 128, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) @@ -220,7 +220,7 @@ final class AutoIngestMetricsDialog extends javax.swing.JDialog { // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton closeButton; - private com.github.lgooddatepicker.datepicker.DatePicker datePicker; + private com.github.lgooddatepicker.components.DatePicker datePicker; private javax.swing.JScrollPane jScrollPane1; private javax.swing.JButton metricsButton; private javax.swing.JTextArea reportTextArea; diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/FileExporterSettingsPanel.form b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/FileExporterSettingsPanel.form index 7ec8ed3539..4bd74cd7ed 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/FileExporterSettingsPanel.form +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/FileExporterSettingsPanel.form @@ -71,10 +71,10 @@ - + @@ -136,12 +136,12 @@ - - - + + + @@ -161,7 +161,7 @@ - + @@ -173,13 +173,6 @@ - - - - - - - @@ -202,6 +195,13 @@ + + + + + + + @@ -236,7 +236,7 @@ - + @@ -259,20 +259,16 @@ - - - - - - - - - - - - - - + + + + + + + + + + @@ -380,12 +376,12 @@ - - - + + + @@ -396,12 +392,12 @@ - - - + + + @@ -409,15 +405,15 @@ - - - + + + @@ -431,10 +427,10 @@ + - @@ -477,10 +473,10 @@ - + @@ -488,13 +484,13 @@ - + @@ -503,8 +499,8 @@ - + @@ -533,14 +529,6 @@ - - - - - - - - @@ -554,8 +542,8 @@ - + @@ -593,6 +581,14 @@ + + + + + + + + @@ -610,12 +606,12 @@ - - - + + + @@ -630,9 +626,9 @@ - + @@ -700,10 +696,10 @@ + - diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/FileExporterSettingsPanel.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/FileExporterSettingsPanel.java index 64acf1163a..4413d948f4 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/FileExporterSettingsPanel.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/FileExporterSettingsPanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2015 Basis Technology Corp. + * Copyright 2015-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,9 +18,9 @@ */ package org.sleuthkit.autopsy.experimental.autoingest; -import com.github.lgooddatepicker.datetimepicker.DateTimePicker; +import com.github.lgooddatepicker.components.DateTimePicker; import com.github.lgooddatepicker.optionalusertools.PickerUtilities; -import com.github.lgooddatepicker.timepicker.TimePickerSettings; +import com.github.lgooddatepicker.components.TimePickerSettings; import java.awt.Color; import java.awt.Component; import java.awt.event.FocusEvent; @@ -632,7 +632,7 @@ public final class FileExporterSettingsPanel extends JPanel { comboBoxValueType.setEnabled(null == attributeTypeMap.get(artifactConditionToPopulateWith.getAttributeTypeName())); if (valueType == BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DATETIME) { Instant instant = Instant.ofEpochMilli(artifactConditionToPopulateWith.getDateTimeValue().toDate().getTime()); - dateTimePicker.setDateTime(LocalDateTime.ofInstant(instant, ZoneId.systemDefault())); + dateTimePicker.setDateTimeStrict(LocalDateTime.ofInstant(instant, ZoneId.systemDefault())); } else { tbAttributeValue.setText(artifactConditionToPopulateWith.getStringRepresentationOfValue()); } @@ -650,30 +650,30 @@ public final class FileExporterSettingsPanel extends JPanel { mainPanel = new javax.swing.JPanel(); tbRootDirectory = new javax.swing.JTextField(); pnEditRule = new javax.swing.JPanel(); - comboBoxMimeValue = new javax.swing.JComboBox(); + comboBoxMimeValue = new javax.swing.JComboBox<>(); cbMimeType = new javax.swing.JCheckBox(); spFileSizeValue = new javax.swing.JSpinner(); - comboBoxFileSizeUnits = new javax.swing.JComboBox(); + comboBoxFileSizeUnits = new javax.swing.JComboBox<>(); cbFileSize = new javax.swing.JCheckBox(); - comboBoxFileSizeComparison = new javax.swing.JComboBox(); - comboBoxMimeTypeComparison = new javax.swing.JComboBox(); + comboBoxFileSizeComparison = new javax.swing.JComboBox<>(); + comboBoxMimeTypeComparison = new javax.swing.JComboBox<>(); tbRuleName = new javax.swing.JTextField(); bnSaveRule = new javax.swing.JButton(); - comboBoxArtifactName = new javax.swing.JComboBox(); - comboBoxAttributeName = new javax.swing.JComboBox(); - comboBoxAttributeComparison = new javax.swing.JComboBox(); + comboBoxArtifactName = new javax.swing.JComboBox<>(); + comboBoxAttributeName = new javax.swing.JComboBox<>(); + comboBoxAttributeComparison = new javax.swing.JComboBox<>(); tbAttributeValue = new javax.swing.JTextField(); bnAddAttribute = new javax.swing.JButton(); - comboBoxValueType = new javax.swing.JComboBox(); + comboBoxValueType = new javax.swing.JComboBox<>(); cbAttributeType = new javax.swing.JCheckBox(); - dateTimePicker = new DateTimePicker(null, timeSettings); lbArtifact = new javax.swing.JLabel(); lbAttribute = new javax.swing.JLabel(); bnDeleteAttribute = new javax.swing.JButton(); jScrollPane1 = new javax.swing.JScrollPane(); - lsAttributeList = new javax.swing.JList(); + lsAttributeList = new javax.swing.JList<>(); lbRuleName = new javax.swing.JLabel(); lbSaveRuleHelper = new javax.swing.JLabel(); + dateTimePicker = new DateTimePicker(null, timeSettings); bnBrowseReportDirectory = new javax.swing.JButton(); tbReportDirectory = new javax.swing.JTextField(); ruleListScrollPane = new javax.swing.JScrollPane(); @@ -690,11 +690,11 @@ public final class FileExporterSettingsPanel extends JPanel { setBorder(javax.swing.BorderFactory.createEtchedBorder()); setName(org.openide.util.NbBundle.getMessage(FileExporterSettingsPanel.class, "FileExporterSettingsPanel.Title")); // NOI18N - mainPanel.setAutoscrolls(true); mainPanel.setPreferredSize(new java.awt.Dimension(657, 425)); + mainPanel.setAutoscrolls(true); - tbRootDirectory.setToolTipText(org.openide.util.NbBundle.getMessage(FileExporterSettingsPanel.class, "FileExporterSettingsPanel.RuleOutputTooltip_1")); // NOI18N tbRootDirectory.setMaximumSize(new java.awt.Dimension(2000, 2000)); + tbRootDirectory.setToolTipText(org.openide.util.NbBundle.getMessage(FileExporterSettingsPanel.class, "FileExporterSettingsPanel.RuleOutputTooltip_1")); // NOI18N pnEditRule.setBorder(javax.swing.BorderFactory.createEtchedBorder()); pnEditRule.setAutoscrolls(true); @@ -716,7 +716,7 @@ public final class FileExporterSettingsPanel extends JPanel { } }); - spFileSizeValue.setModel(new javax.swing.SpinnerNumberModel(Integer.valueOf(1024), Integer.valueOf(0), null, Integer.valueOf(1))); + spFileSizeValue.setModel(new javax.swing.SpinnerNumberModel(1024, 0, null, 1)); spFileSizeValue.setToolTipText(org.openide.util.NbBundle.getMessage(FileExporterSettingsPanel.class, "FileExporterSettingsPanel.FileSizeValueToolTip_1")); // NOI18N comboBoxFileSizeUnits.setToolTipText(org.openide.util.NbBundle.getMessage(FileExporterSettingsPanel.class, "FileExporterSettingsPanel.FileSizeUnitToolTip_1")); // NOI18N @@ -729,15 +729,15 @@ public final class FileExporterSettingsPanel extends JPanel { } }); - comboBoxFileSizeComparison.setToolTipText(org.openide.util.NbBundle.getMessage(FileExporterSettingsPanel.class, "FileExporterSettingsPanel.FileSizeComparisonTooltip_1")); // NOI18N comboBoxFileSizeComparison.setMinimumSize(new java.awt.Dimension(32, 20)); + comboBoxFileSizeComparison.setToolTipText(org.openide.util.NbBundle.getMessage(FileExporterSettingsPanel.class, "FileExporterSettingsPanel.FileSizeComparisonTooltip_1")); // NOI18N - comboBoxMimeTypeComparison.setToolTipText(org.openide.util.NbBundle.getMessage(FileExporterSettingsPanel.class, "FileExporterSettingsPanel.MimeTypeComparisonTooltip_1")); // NOI18N comboBoxMimeTypeComparison.setMinimumSize(new java.awt.Dimension(32, 20)); + comboBoxMimeTypeComparison.setToolTipText(org.openide.util.NbBundle.getMessage(FileExporterSettingsPanel.class, "FileExporterSettingsPanel.MimeTypeComparisonTooltip_1")); // NOI18N - tbRuleName.setToolTipText(org.openide.util.NbBundle.getMessage(FileExporterSettingsPanel.class, "FileExporterSettingsPanel.CurrentlySelectedRuleNameTooltip_1")); // NOI18N tbRuleName.setMaximumSize(new java.awt.Dimension(10, 1000)); tbRuleName.setPreferredSize(new java.awt.Dimension(733, 20)); + tbRuleName.setToolTipText(org.openide.util.NbBundle.getMessage(FileExporterSettingsPanel.class, "FileExporterSettingsPanel.CurrentlySelectedRuleNameTooltip_1")); // NOI18N tbRuleName.addKeyListener(new java.awt.event.KeyAdapter() { public void keyTyped(java.awt.event.KeyEvent evt) { tbRuleNameKeyTyped(evt); @@ -746,8 +746,8 @@ public final class FileExporterSettingsPanel extends JPanel { bnSaveRule.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/experimental/images/save-icon.png"))); // NOI18N bnSaveRule.setText(org.openide.util.NbBundle.getMessage(FileExporterSettingsPanel.class, "FileExporterSettingsPanel.SaveText")); // NOI18N - bnSaveRule.setToolTipText(org.openide.util.NbBundle.getMessage(FileExporterSettingsPanel.class, "FileExporterSettingsPanel.SaveTooltip_1")); // NOI18N bnSaveRule.setEnabled(false); + bnSaveRule.setToolTipText(org.openide.util.NbBundle.getMessage(FileExporterSettingsPanel.class, "FileExporterSettingsPanel.SaveTooltip_1")); // NOI18N bnSaveRule.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { bnSaveRuleActionPerformed(evt); @@ -772,17 +772,17 @@ public final class FileExporterSettingsPanel extends JPanel { } }); - comboBoxAttributeComparison.setToolTipText("Select the conditional operator"); comboBoxAttributeComparison.setMinimumSize(new java.awt.Dimension(32, 23)); + comboBoxAttributeComparison.setToolTipText("Select the conditional operator"); - tbAttributeValue.setToolTipText("Type a value here"); tbAttributeValue.setMinimumSize(new java.awt.Dimension(6, 23)); tbAttributeValue.setPreferredSize(new java.awt.Dimension(6, 23)); + tbAttributeValue.setToolTipText("Type a value here"); bnAddAttribute.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/experimental/images/left-arrow-16-icon.png"))); // NOI18N bnAddAttribute.setText("Add Attribute"); - bnAddAttribute.setToolTipText("Click to add an attribute to the current rule"); bnAddAttribute.setEnabled(false); + bnAddAttribute.setToolTipText("Click to add an attribute to the current rule"); bnAddAttribute.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { bnAddAttributeActionPerformed(evt); @@ -804,15 +804,13 @@ public final class FileExporterSettingsPanel extends JPanel { } }); - dateTimePicker.setToolTipText("Choose a date and time"); - lbArtifact.setText("Artifact"); lbAttribute.setText("Attribute"); bnDeleteAttribute.setText("Delete Attribute"); - bnDeleteAttribute.setToolTipText("Click to remove the selected attribute"); bnDeleteAttribute.setEnabled(false); + bnDeleteAttribute.setToolTipText("Click to remove the selected attribute"); bnDeleteAttribute.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { bnDeleteAttributeActionPerformed(evt); @@ -829,6 +827,8 @@ public final class FileExporterSettingsPanel extends JPanel { lbSaveRuleHelper.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT); lbSaveRuleHelper.setText("To save, a rule must have a name and at least one condition."); + dateTimePicker.setToolTipText("Choose a date and time"); + javax.swing.GroupLayout pnEditRuleLayout = new javax.swing.GroupLayout(pnEditRule); pnEditRule.setLayout(pnEditRuleLayout); pnEditRuleLayout.setHorizontalGroup( @@ -845,12 +845,6 @@ public final class FileExporterSettingsPanel extends JPanel { .addComponent(lbSaveRuleHelper, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(bnSaveRule, javax.swing.GroupLayout.PREFERRED_SIZE, 101, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(pnEditRuleLayout.createSequentialGroup() - .addComponent(comboBoxAttributeComparison, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(dateTimePicker, javax.swing.GroupLayout.PREFERRED_SIZE, 306, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(tbAttributeValue, javax.swing.GroupLayout.DEFAULT_SIZE, 158, Short.MAX_VALUE)) .addGroup(pnEditRuleLayout.createSequentialGroup() .addGroup(pnEditRuleLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(pnEditRuleLayout.createSequentialGroup() @@ -867,7 +861,13 @@ public final class FileExporterSettingsPanel extends JPanel { .addGroup(pnEditRuleLayout.createSequentialGroup() .addComponent(bnAddAttribute, javax.swing.GroupLayout.PREFERRED_SIZE, 117, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(bnDeleteAttribute))) + .addComponent(bnDeleteAttribute)) + .addGroup(pnEditRuleLayout.createSequentialGroup() + .addComponent(comboBoxAttributeComparison, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(dateTimePicker, javax.swing.GroupLayout.PREFERRED_SIZE, 306, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(tbAttributeValue, javax.swing.GroupLayout.DEFAULT_SIZE, 158, Short.MAX_VALUE))) .addGap(0, 0, Short.MAX_VALUE)))) .addGroup(pnEditRuleLayout.createSequentialGroup() .addGroup(pnEditRuleLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -910,17 +910,15 @@ public final class FileExporterSettingsPanel extends JPanel { .addGap(78, 78, 78) .addComponent(lbAttribute) .addGap(8, 8, 8) - .addGroup(pnEditRuleLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addGroup(pnEditRuleLayout.createSequentialGroup() - .addGroup(pnEditRuleLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(comboBoxAttributeName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(comboBoxArtifactName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(comboBoxValueType, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(pnEditRuleLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(tbAttributeValue, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(dateTimePicker, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) - .addComponent(comboBoxAttributeComparison, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(pnEditRuleLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(comboBoxAttributeName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(comboBoxArtifactName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(comboBoxValueType, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(pnEditRuleLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(tbAttributeValue, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(comboBoxAttributeComparison, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(dateTimePicker, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(pnEditRuleLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(bnAddAttribute) @@ -953,14 +951,14 @@ public final class FileExporterSettingsPanel extends JPanel { } }); - tbReportDirectory.setToolTipText(org.openide.util.NbBundle.getMessage(FileExporterSettingsPanel.class, "FileExporterSettingsPanel.ReportOutputFolderTooltip_1")); // NOI18N tbReportDirectory.setMaximumSize(new java.awt.Dimension(2000, 2000)); + tbReportDirectory.setToolTipText(org.openide.util.NbBundle.getMessage(FileExporterSettingsPanel.class, "FileExporterSettingsPanel.ReportOutputFolderTooltip_1")); // NOI18N javax.swing.tree.DefaultMutableTreeNode treeNode1 = new javax.swing.tree.DefaultMutableTreeNode("root"); trRuleList.setModel(new javax.swing.tree.DefaultTreeModel(treeNode1)); - trRuleList.setToolTipText("This tree shows the rules to collect files for automatic file export"); trRuleList.setName("trRuleList"); // NOI18N trRuleList.setShowsRootHandles(true); + trRuleList.setToolTipText("This tree shows the rules to collect files for automatic file export"); ruleListScrollPane.setViewportView(trRuleList); trRuleList.getAccessibleContext().setAccessibleParent(ruleListScrollPane); @@ -1039,8 +1037,8 @@ public final class FileExporterSettingsPanel extends JPanel { bnDeleteRule.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/experimental/images/minus-icon.png"))); // NOI18N bnDeleteRule.setText(org.openide.util.NbBundle.getMessage(FileExporterSettingsPanel.class, "FileExporterSettingsPanel.DeleteText")); // NOI18N - bnDeleteRule.setToolTipText(org.openide.util.NbBundle.getMessage(FileExporterSettingsPanel.class, "FileExporterSettingsPanel.DeleteTooltip_1")); // NOI18N bnDeleteRule.setEnabled(false); + bnDeleteRule.setToolTipText(org.openide.util.NbBundle.getMessage(FileExporterSettingsPanel.class, "FileExporterSettingsPanel.DeleteTooltip_1")); // NOI18N bnDeleteRule.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { bnDeleteRuleActionPerformed(evt); @@ -1260,7 +1258,7 @@ public final class FileExporterSettingsPanel extends JPanel { } if (intrinsicType == BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DATETIME) { - LocalDateTime localDateTime = dateTimePicker.getDateTime(); + LocalDateTime localDateTime = dateTimePicker.getDateTimeStrict(); if (localDateTime == null) { throw new IllegalArgumentException("Bad date/time combination"); } @@ -2028,7 +2026,7 @@ public final class FileExporterSettingsPanel extends JPanel { private javax.swing.JComboBox comboBoxMimeTypeComparison; private javax.swing.JComboBox comboBoxMimeValue; private javax.swing.JComboBox comboBoxValueType; - private com.github.lgooddatepicker.datetimepicker.DateTimePicker dateTimePicker; + private com.github.lgooddatepicker.components.DateTimePicker dateTimePicker; private javax.swing.JScrollPane jScrollPane1; private javax.swing.JLabel lbArtifact; private javax.swing.JLabel lbAttribute; diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/SearchRunner.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/SearchRunner.java index def0583553..3ffaa01622 100755 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/SearchRunner.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/SearchRunner.java @@ -18,18 +18,22 @@ */ package org.sleuthkit.autopsy.keywordsearch; +import com.google.common.util.concurrent.ThreadFactoryBuilder; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; -import java.util.Timer; -import java.util.TimerTask; import java.util.concurrent.CancellationException; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import static java.util.concurrent.TimeUnit.MILLISECONDS; import java.util.concurrent.atomic.AtomicLong; import java.util.logging.Level; import javax.swing.SwingUtilities; @@ -57,15 +61,20 @@ final class SearchRunner { private static SearchRunner instance = null; private IngestServices services = IngestServices.getInstance(); private Ingester ingester = null; - private volatile boolean updateTimerRunning = false; - private Timer updateTimer; + private long defaultUpdateIntervalMs; + private volatile boolean periodicSearchTaskRunning = false; + private Future jobProcessingTaskFuture; + private final ScheduledThreadPoolExecutor jobProcessingExecutor; + private static final int NUM_SEARCH_SCHEDULING_THREADS = 1; + private static final String SEARCH_SCHEDULER_THREAD_NAME = "periodic-search-scheduler-%d"; // maps a jobID to the search - private Map jobs = new HashMap<>(); //guarded by "this" + private Map jobs = new ConcurrentHashMap<>(); SearchRunner() { + defaultUpdateIntervalMs = ((long) KeywordSearchSettings.getUpdateFrequency().getTime()) * 60 * 1000; ingester = Ingester.getDefault(); - updateTimer = new Timer(NbBundle.getMessage(this.getClass(), "SearchRunner.updateTimer.title.text"), true); // run as a daemon + jobProcessingExecutor = new ScheduledThreadPoolExecutor(NUM_SEARCH_SCHEDULING_THREADS, new ThreadFactoryBuilder().setNameFormat(SEARCH_SCHEDULER_THREAD_NAME).build()); } /** @@ -96,10 +105,12 @@ final class SearchRunner { jobs.get(jobId).incrementModuleReferenceCount(); // start the timer, if needed - if ((jobs.size() > 0) && (updateTimerRunning == false)) { - final long updateIntervalMs = ((long) KeywordSearchSettings.getUpdateFrequency().getTime()) * 60 * 1000; - updateTimer.scheduleAtFixedRate(new UpdateTimerTask(), updateIntervalMs, updateIntervalMs); - updateTimerRunning = true; + if ((jobs.size() > 0) && (periodicSearchTaskRunning == false)) { + // reset the default periodic search frequency to the user setting + logger.log(Level.INFO, "Resetting periodic search time out to default value"); //NON-NLS + defaultUpdateIntervalMs = ((long) KeywordSearchSettings.getUpdateFrequency().getTime()) * 60 * 1000; + jobProcessingTaskFuture = jobProcessingExecutor.schedule(new PeriodicSearchTask(), defaultUpdateIntervalMs, MILLISECONDS); + periodicSearchTaskRunning = true; } } @@ -109,26 +120,33 @@ final class SearchRunner { * * @param jobId */ - public void endJob(long jobId) { + public synchronized void endJob(long jobId) { SearchJobInfo job; boolean readyForFinalSearch = false; - synchronized (this) { - job = jobs.get(jobId); - if (job == null) { - return; - } + job = jobs.get(jobId); + if (job == null) { + return; + } - // Only do final search if this is the last module/thread in this job to call endJob() - if (job.decrementModuleReferenceCount() == 0) { - jobs.remove(jobId); - readyForFinalSearch = true; - } + // Only do final search if this is the last module/thread in this job to call endJob() + if (job.decrementModuleReferenceCount() == 0) { + jobs.remove(jobId); + readyForFinalSearch = true; } if (readyForFinalSearch) { logger.log(Level.INFO, "Commiting search index before final search for search job {0}", job.getJobId()); //NON-NLS commit(); doFinalSearch(job); //this will block until it's done + + // new jobs could have been added while we were doing final search + if (jobs.isEmpty()) { + // no more jobs left. stop the PeriodicSearchTask. + // A new one will be created for future jobs. + logger.log(Level.INFO, "No more search jobs. Stopping periodic search task"); //NON-NLS + periodicSearchTaskRunning = false; + jobProcessingTaskFuture.cancel(true); + } } } @@ -138,24 +156,31 @@ final class SearchRunner { * * @param jobId */ - public void stopJob(long jobId) { - logger.log(Level.INFO, "Stopping job {0}", jobId); //NON-NLS + public synchronized void stopJob(long jobId) { + logger.log(Level.INFO, "Stopping search job {0}", jobId); //NON-NLS commit(); SearchJobInfo job; - synchronized (this) { - job = jobs.get(jobId); - if (job == null) { - return; - } + job = jobs.get(jobId); + if (job == null) { + return; + } - //stop currentSearcher - SearchRunner.Searcher currentSearcher = job.getCurrentSearcher(); - if ((currentSearcher != null) && (!currentSearcher.isDone())) { - currentSearcher.cancel(true); - } + //stop currentSearcher + SearchRunner.Searcher currentSearcher = job.getCurrentSearcher(); + if ((currentSearcher != null) && (!currentSearcher.isDone())) { + logger.log(Level.INFO, "Cancelling search job {0}", jobId); //NON-NLS + currentSearcher.cancel(true); + } - jobs.remove(jobId); + jobs.remove(jobId); + + if (jobs.isEmpty()) { + // no more jobs left. stop the PeriodicSearchTask. + // A new one will be created for future jobs. + logger.log(Level.INFO, "No more search jobs. Stopping periodic search task"); //NON-NLS + periodicSearchTaskRunning = false; + jobProcessingTaskFuture.cancel(true); } } @@ -223,37 +248,81 @@ final class SearchRunner { } /** - * Timer triggered re-search for each job (does a single index commit first) + * Task to perform periodic searches for each job (does a single index commit first) */ - private class UpdateTimerTask extends TimerTask { + private final class PeriodicSearchTask implements Runnable { - private final Logger logger = Logger.getLogger(SearchRunner.UpdateTimerTask.class.getName()); + private final Logger logger = Logger.getLogger(SearchRunner.PeriodicSearchTask.class.getName()); @Override public void run() { // If no jobs then cancel the task. If more job(s) come along, a new task will start up. - if (jobs.isEmpty()) { - this.cancel(); //terminate this timer task - updateTimerRunning = false; + if (jobs.isEmpty() || jobProcessingTaskFuture.isCancelled()) { + logger.log(Level.INFO, "Exiting periodic search task"); //NON-NLS + periodicSearchTaskRunning = false; return; } commit(); - synchronized (SearchRunner.this) { - // Spawn a search thread for each job - for (Entry j : jobs.entrySet()) { - SearchJobInfo job = j.getValue(); - // If no lists or the worker is already running then skip it - if (!job.getKeywordListNames().isEmpty() && !job.isWorkerRunning()) { - logger.log(Level.INFO, "Executing periodic search for search job {0}", job.getJobId()); - Searcher searcher = new Searcher(job); - job.setCurrentSearcher(searcher); //save the ref - searcher.execute(); //start thread - job.setWorkerRunning(true); + logger.log(Level.INFO, "Starting periodic searches"); + final StopWatch stopWatch = new StopWatch(); + stopWatch.start(); + // NOTE: contents of "jobs" ConcurrentHashMap can be modified in stopJob() and endJob() while we are inside this loop + for (Iterator> iterator = jobs.entrySet().iterator(); iterator.hasNext();) { + SearchJobInfo job = iterator.next().getValue(); + + if (jobProcessingTaskFuture.isCancelled()) { + logger.log(Level.INFO, "Search has been cancelled. Exiting periodic search task."); //NON-NLS + periodicSearchTaskRunning = false; + return; + } + + // If no lists or the worker is already running then skip it + if (!job.getKeywordListNames().isEmpty() && !job.isWorkerRunning()) { + // Spawn a search thread for each job + logger.log(Level.INFO, "Executing periodic search for search job {0}", job.getJobId()); + Searcher searcher = new Searcher(job); // SwingWorker + job.setCurrentSearcher(searcher); //save the ref + searcher.execute(); //start thread + job.setWorkerRunning(true); + + try { + // wait for the searcher to finish + searcher.get(); + } catch (InterruptedException | ExecutionException ex) { + logger.log(Level.SEVERE, "Error performing keyword search: {0}", ex.getMessage()); //NON-NLS + services.postMessage(IngestMessage.createErrorMessage(KeywordSearchModuleFactory.getModuleName(), + NbBundle.getMessage(this.getClass(), + "SearchRunner.Searcher.done.err.msg"), ex.getMessage())); + }// catch and ignore if we were cancelled + catch (java.util.concurrent.CancellationException ex) { } } } + stopWatch.stop(); + logger.log(Level.INFO, "All periodic searches cumulatively took {0} secs", stopWatch.getElapsedTimeSecs()); //NON-NLS + + // calculate "hold off" time + final long timeToTextSearchMs = getTimeToNextPeriodicSearch(stopWatch.getElapsedTimeSecs()); // ELDEBUG + + // schedule next PeriodicSearchTask + jobProcessingTaskFuture = jobProcessingExecutor.schedule(new PeriodicSearchTask(), timeToTextSearchMs, MILLISECONDS); + + // exit this thread + return; + } + + + private long getTimeToNextPeriodicSearch(long lastSerchTimeSec) { + // If periodic search takes more than 1/4 of the current periodic search interval, then double the search interval + if (lastSerchTimeSec * 1000 < defaultUpdateIntervalMs / 4) { + return defaultUpdateIntervalMs; + } + // double the search interval + defaultUpdateIntervalMs = defaultUpdateIntervalMs * 2; + logger.log(Level.WARNING, "Last periodic search took {0} sec. Increasing search interval to {1} sec", new Object[]{lastSerchTimeSec, defaultUpdateIntervalMs/1000}); + return defaultUpdateIntervalMs; } } @@ -522,23 +591,6 @@ final class SearchRunner { return null; } - @Override - protected void done() { - // call get to see if there were any errors - try { - logger.log(Level.INFO, "Searcher calling get() on itself in done()"); //NON-NLS - get(); - logger.log(Level.INFO, "Searcher finished calling get() on itself in done()"); //NON-NLS - } catch (InterruptedException | ExecutionException e) { - logger.log(Level.SEVERE, "Error performing keyword search: " + e.getMessage()); //NON-NLS - services.postMessage(IngestMessage.createErrorMessage(KeywordSearchModuleFactory.getModuleName(), - NbBundle.getMessage(this.getClass(), - "SearchRunner.Searcher.done.err.msg"), e.getMessage())); - } // catch and ignore if we were cancelled - catch (java.util.concurrent.CancellationException ex) { - } - } - /** * Sync-up the updated keywords from the currently used lists in the XML */