diff --git a/Core/build.xml b/Core/build.xml index c22d725cce..e75c217d15 100644 --- a/Core/build.xml +++ b/Core/build.xml @@ -17,6 +17,8 @@ + + @@ -52,8 +54,8 @@ - + - - + + diff --git a/Core/nbproject/project.properties b/Core/nbproject/project.properties index ff1f4f81de..8e75908180 100644 --- a/Core/nbproject/project.properties +++ b/Core/nbproject/project.properties @@ -1,6 +1,6 @@ file.reference.activemq-all-5.11.1.jar=release/modules/ext/activemq-all-5.11.1.jar file.reference.c3p0-0.9.5.jar=release/modules/ext/c3p0-0.9.5.jar -file.reference.commons-compress-1.12.jar=release/modules/ext/commons-compress-1.12.jar +file.reference.commons-compress-1.14.jar=release/modules/ext/commons-compress-1.14.jar file.reference.commons-dbcp2-2.1.1.jar=release\\modules\\ext\\commons-dbcp2-2.1.1.jar file.reference.commons-pool2-2.4.2.jar=release\\modules\\ext\\commons-pool2-2.4.2.jar file.reference.jdom-2.0.5-contrib.jar=release/modules/ext/jdom-2.0.5-contrib.jar @@ -9,7 +9,7 @@ file.reference.jgraphx-v3.8.0.jar=release/modules/ext/jgraphx-v3.8.0.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.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.metadata-extractor-2.10.1.jar=release/modules/ext/metadata-extractor-2.10.1.jar file.reference.postgresql-9.4.1211.jre7.jar=release/modules/ext/postgresql-9.4.1211.jre7.jar file.reference.opencv-248.jar=release/modules/ext/opencv-248.jar file.reference.Rejistry-1.0-SNAPSHOT.jar=release/modules/ext/Rejistry-1.0-SNAPSHOT.jar @@ -17,14 +17,14 @@ file.reference.sevenzipjbinding-AllPlatforms.jar=release/modules/ext/sevenzipjbi file.reference.sevenzipjbinding.jar=release/modules/ext/sevenzipjbinding.jar file.reference.sqlite-jdbc-3.8.11.jar=release/modules/ext/sqlite-jdbc-3.8.11.jar file.reference.StixLib.jar=release/modules/ext/StixLib.jar -file.reference.tika-core-1.14.jar=release/modules/ext/tika-core-1.14.jar -file.reference.tika-parsers-1.14.jar=release/modules/ext/tika-parsers-1.14.jar -file.reference.Tsk_DataModel_PostgreSQL.jar=release/modules/ext/Tsk_DataModel_PostgreSQL.jar -file.reference.xmpcore-5.1.2.jar=release/modules/ext/xmpcore-5.1.2.jar +file.reference.sleuthkit-postgresql-4.6.0.jar=release/modules/ext/sleuthkit-postgresql-4.6.0.jar +file.reference.tika-core-1.17.jar=release/modules/ext/tika-core-1.17.jar +file.reference.tika-parsers-1.17.jar=release/modules/ext/tika-parsers-1.17.jar file.reference.curator-client-2.8.0.jar=release/modules/ext/curator-client-2.8.0.jar file.reference.curator-framework-2.8.0.jar=release/modules/ext/curator-framework-2.8.0.jar file.reference.curator-recipes-2.8.0.jar=release/modules/ext/curator-recipes-2.8.0.jar -file.reference.xz-1.5.jar=release/modules/ext/xz-1.5.jar +file.reference.xmpcore-5.1.3.jar=release/modules/ext/xmpcore-5.1.3.jar +file.reference.xz-1.6.jar=release/modules/ext/xz-1.6.jar file.reference.zookeeper-3.4.6.jar=release/modules/ext/zookeeper-3.4.6.jar javac.source=1.8 javac.compilerargs=-Xlint -Xlint:-serial diff --git a/Core/nbproject/project.xml b/Core/nbproject/project.xml index baaf061b92..9f75c01eeb 100644 --- a/Core/nbproject/project.xml +++ b/Core/nbproject/project.xml @@ -286,6 +286,7 @@ + net.sf.sevenzipjbinding net.sf.sevenzipjbinding.impl @@ -329,12 +330,8 @@ release/modules/ext/jdom-2.0.5.jar - ext/tika-core-1.14.jar - release/modules/ext/tika-core-1.14.jar - - - ext/Tsk_DataModel_PostgreSQL.jar - release/modules/ext/Tsk_DataModel_PostgreSQL.jar + ext/sleuthkit-postgresql-4.6.0.jar + release/modules/ext/sleuthkit-postgresql-4.6.0.jar ext/opencv-248.jar @@ -353,8 +350,12 @@ release/modules/ext/jgraphx-v3.8.0.jar - ext/tika-parsers-1.14.jar - release/modules/ext/tika-parsers-1.14.jar + ext/commons-compress-1.14.jar + release/modules/ext/commons-compress-1.14.jar + + + ext/commons-dbcp2-2.1.1.jar + release\modules\ext\commons-dbcp2-2.1.1.jar ext/jython-standalone-2.7.0.jar @@ -377,12 +378,12 @@ release/modules/ext/curator-recipes-2.8.0.jar - ext/xz-1.5.jar - release/modules/ext/xz-1.5.jar + ext/metadata-extractor-2.10.1.jar + release/modules/ext/metadata-extractor-2.10.1.jar - ext/xmpcore-5.1.2.jar - release/modules/ext/xmpcore-5.1.2.jar + ext/tika-core-1.17.jar + release/modules/ext/tika-core-1.17.jar ext/StixLib.jar @@ -392,6 +393,10 @@ ext/curator-client-2.8.0.jar release/modules/ext/curator-client-2.8.0.jar + + ext/tika-parsers-1.17.jar + release/modules/ext/tika-parsers-1.17.jar + ext/sqlite-jdbc-3.8.11.jar release/modules/ext/sqlite-jdbc-3.8.11.jar @@ -400,6 +405,10 @@ ext/activemq-all-5.11.1.jar release/modules/ext/activemq-all-5.11.1.jar + + ext/xz-1.6.jar + release/modules/ext/xz-1.6.jar + ext/Rejistry-1.0-SNAPSHOT.jar release/modules/ext/Rejistry-1.0-SNAPSHOT.jar @@ -412,14 +421,6 @@ ext/commons-pool2-2.4.2.jar release\modules\ext\commons-pool2-2.4.2.jar - - ext/metadata-extractor-2.9.1.jar - release/modules/ext/metadata-extractor-2.9.1.jar - - - ext/commons-compress-1.12.jar - release/modules/ext/commons-compress-1.12.jar - ext/jsoup-1.10.3.jar release/modules/ext/jsoup-1.10.3.jar @@ -432,6 +433,10 @@ ext/c3p0-0.9.5.jar release/modules/ext/c3p0-0.9.5.jar + + ext/xmpcore-5.1.3.jar + release/modules/ext/xmpcore-5.1.3.jar + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties index 1cc822fea5..ab2b5c12dc 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties @@ -223,17 +223,11 @@ ReviewModeCasePanel.MetadataFileHeaderText=Metadata File OpenMultiUserCasePanel.jLabel1.text=Recent Cases OpenMultiUserCasePanel.openButton.text=Open OpenMultiUserCasePanel.cancelButton.text=Cancel -MultiUserCasesPanel.rbWeeks.text=Weeks -MultiUserCasesPanel.rbDays.text=Days -MultiUserCasesPanel.bnShowLog.toolTipText=Display case log file for selected case -MultiUserCasesPanel.bnShowLog.text=&Show Auto Ingest Case Log -MultiUserCasesPanel.rbAllCases.text=Everything -MultiUserCasesPanel.bnRefresh.text=&Refresh MultiUserCasesPanel.bnOpen.text=&Open -MultiUserCasesPanel.rbGroupLabel.text=Show cases created in the last 10: -MultiUserCasesPanel.rbMonths.text=Months CueBannerPanel.newCaseLabel.text=New Case CueBannerPanel.openCaseButton.text= CueBannerPanel.openCaseLabel.text=Open Case MultiUserCasesPanel.bnOpenSingleUserCase.text=Open Single-User Case... CueBannerPanel.newCaseButton.text= +MultiUserCasesPanel.searchLabel.text=Start typing to search by case name +MultiUserCasesPanel.cancelButton.text=Cancel diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseBrowser.form b/Core/src/org/sleuthkit/autopsy/casemodule/CaseBrowser.form new file mode 100644 index 0000000000..edda7a749c --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseBrowser.form @@ -0,0 +1,47 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseBrowser.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseBrowser.java new file mode 100644 index 0000000000..9440ca1356 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseBrowser.java @@ -0,0 +1,296 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2017-2018 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.casemodule; + +import java.awt.Component; +import java.lang.reflect.InvocationTargetException; +import javax.swing.ListSelectionModel; +import javax.swing.event.ListSelectionListener; +import javax.swing.table.TableCellRenderer; +import javax.swing.table.TableColumnModel; +import org.netbeans.swing.etable.ETableColumn; +import org.netbeans.swing.etable.ETableColumnModel; +import org.netbeans.swing.outline.DefaultOutlineModel; +import org.netbeans.swing.outline.Outline; +import org.openide.nodes.Node; +import java.awt.EventQueue; +import java.io.File; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; +import javax.swing.SwingWorker; +import org.openide.explorer.ExplorerManager; +import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.coordinationservice.CaseNodeData; +import org.sleuthkit.autopsy.coordinationservice.CoordinationService; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.datamodel.EmptyNode; + +/** + * A Swing JPanel with a scroll pane child component. The scroll pane contain + * the table of cases. + * + * Used to display a list of multi user cases and allow the user to open one of + * them. + * + */ +class CaseBrowser extends javax.swing.JPanel implements ExplorerManager.Provider { + + private static final long serialVersionUID = 1L; + private final Outline outline; + private ExplorerManager em; + private final org.openide.explorer.view.OutlineView outlineView; + private int originalPathColumnIndex = 0; + private static final Logger LOGGER = Logger.getLogger(CaseBrowser.class.getName()); + private LoadCaseMapWorker tableWorker; + + @Override + public ExplorerManager getExplorerManager() { + return em; + } + + /** + * Creates a new CaseBrowser + */ + CaseBrowser() { + outlineView = new org.openide.explorer.view.OutlineView(); + initComponents(); + + outline = outlineView.getOutline(); + outlineView.setPropertyColumns( + Bundle.CaseNode_column_createdTime(), Bundle.CaseNode_column_createdTime(), + Bundle.CaseNode_column_status(), Bundle.CaseNode_column_status(), + Bundle.CaseNode_column_metadataFilePath(), Bundle.CaseNode_column_metadataFilePath()); + ((DefaultOutlineModel) outline.getOutlineModel()).setNodesColumnLabel(Bundle.CaseNode_column_name()); + customize(); + + } + + /** + * Configures the the table of cases and its columns. + */ + private void customize() { + outline.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + TableColumnModel columnModel = outline.getColumnModel(); + int dateColumnIndex = 0; + for (int index = 0; index < columnModel.getColumnCount(); index++) { + //get indexes for created date column and path column + if (columnModel.getColumn(index).getHeaderValue().toString().equals(Bundle.CaseNode_column_metadataFilePath())) { + originalPathColumnIndex = index; + } else if (columnModel.getColumn(index).getHeaderValue().toString().equals(Bundle.CaseNode_column_createdTime())) { + dateColumnIndex = index; + } + } + //Hide path column by default will need to + ETableColumn column = (ETableColumn) columnModel.getColumn(originalPathColumnIndex); + ((ETableColumnModel) columnModel).setColumnHidden(column, true); + outline.setRootVisible(false); + + //Sort on Created date column in descending order by default + outline.setColumnSorted(dateColumnIndex, false, 1); + if (null == em) { + em = new ExplorerManager(); + } + caseTableScrollPane.setViewportView(outlineView); + this.setVisible(true); + outline.setRowSelectionAllowed(false); + } + + /** + * Add a listener to changes in case selections in the table + * + * @param listener the ListSelectionListener to add + */ + void addListSelectionListener(ListSelectionListener listener) { + outline.getSelectionModel().addListSelectionListener(listener); + } + + String getCasePath() { + int[] selectedRows = outline.getSelectedRows(); + if (selectedRows.length == 1) { + try { + return ((Node.Property) outline.getModel().getValueAt(outline.convertRowIndexToModel(selectedRows[0]), originalPathColumnIndex)).getValue().toString(); + } catch (IllegalAccessException | InvocationTargetException ex) { + LOGGER.log(Level.SEVERE, "Unable to get case path from table.", ex); + } + } + return null; + } + + /** + * Check if a row could be and is selected. + * + * @return true if a row is selected, false if no row is selected + */ + boolean isRowSelected() { + return outline.getRowSelectionAllowed() && outline.getSelectedRows().length > 0; + } + + @NbBundle.Messages({"CaseBrowser.caseListLoading.message=Please Wait..."}) + /** + * Gets the list of cases known to the review mode cases manager and + * refreshes the cases table. + */ + void refresh() { + if (tableWorker == null || tableWorker.isDone()) { + outline.setRowSelectionAllowed(false); + //create a new TableWorker to and execute it in a background thread if one is not currently working + //set the table to display text informing the user that the list is being retreived and disable case selection + EmptyNode emptyNode = new EmptyNode(Bundle.CaseBrowser_caseListLoading_message()); + em.setRootContext(emptyNode); + tableWorker = new LoadCaseMapWorker(); + tableWorker.execute(); + } + + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + caseTableScrollPane = new javax.swing.JScrollPane(); + + setMinimumSize(new java.awt.Dimension(0, 5)); + setPreferredSize(new java.awt.Dimension(5, 5)); + setLayout(new java.awt.BorderLayout()); + + caseTableScrollPane.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); + caseTableScrollPane.setMinimumSize(new java.awt.Dimension(0, 5)); + caseTableScrollPane.setOpaque(false); + caseTableScrollPane.setPreferredSize(new java.awt.Dimension(5, 5)); + add(caseTableScrollPane, java.awt.BorderLayout.CENTER); + }// //GEN-END:initComponents + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JScrollPane caseTableScrollPane; + // End of variables declaration//GEN-END:variables + + /** + * Swingworker to fetch the updated map of cases and their status in a + * background thread + */ + private class LoadCaseMapWorker extends SwingWorker { + + private static final String ALERT_FILE_NAME = "autoingest.alert"; + private Map cases; + + /** + * Gets a list of the cases in the top level case folder + * + * @return List of cases. + * + * @throws CoordinationServiceException + */ + private Map getCases() throws CoordinationService.CoordinationServiceException { + Map casesMap = new HashMap<>(); + List nodeList = CoordinationService.getInstance().getNodeList(CoordinationService.CategoryNode.CASES); + + for (String node : nodeList) { + Path casePath = Paths.get(node); + File caseFolder = casePath.toFile(); + if (caseFolder.exists()) { + /* + * Search for '*.aut' and 'autoingest.alert' files. + */ + File[] fileArray = caseFolder.listFiles(); + if (fileArray == null) { + continue; + } + String autFilePath = null; + boolean alertFileFound = false; + for (File file : fileArray) { + String name = file.getName().toLowerCase(); + if (autFilePath == null && name.endsWith(".aut")) { + autFilePath = file.getAbsolutePath(); + if (!alertFileFound) { + continue; + } + } + if (!alertFileFound && name.endsWith(ALERT_FILE_NAME)) { + alertFileFound = true; + } + if (autFilePath != null && alertFileFound) { + break; + } + } + + if (autFilePath != null) { + try { + boolean hasAlertStatus = false; + if (alertFileFound) { + /* + * When an alert file exists, ignore the node + * data and use the ALERT status. + */ + hasAlertStatus = true; + } else { + byte[] rawData = CoordinationService.getInstance().getNodeData(CoordinationService.CategoryNode.CASES, node); + if (rawData != null && rawData.length > 0) { + /* + * When node data exists, use the status + * stored in the node data. + */ + CaseNodeData caseNodeData = new CaseNodeData(rawData); + if (caseNodeData.getErrorsOccurred()) { + hasAlertStatus = true; + } + } + } + + CaseMetadata caseMetadata = new CaseMetadata(Paths.get(autFilePath)); + casesMap.put(caseMetadata, hasAlertStatus); + } catch (CaseMetadata.CaseMetadataException ex) { + LOGGER.log(Level.SEVERE, String.format("Error reading case metadata file '%s'.", autFilePath), ex); + } catch (InterruptedException | CaseNodeData.InvalidDataException ex) { + LOGGER.log(Level.SEVERE, String.format("Error reading case node data for '%s'.", node), ex); + } + } + } + } + return casesMap; + } + + @Override + protected Void doInBackground() throws Exception { + + try { + cases = getCases(); + } catch (CoordinationService.CoordinationServiceException ex) { + LOGGER.log(Level.SEVERE, "Unexpected exception while refreshing the table.", ex); //NON-NLS + } + return null; + } + + @Override + protected void done() { + EventQueue.invokeLater(() -> { + MultiUserNode caseListNode = new MultiUserNode(cases); + em.setRootContext(caseListNode); + outline.setRowSelectionAllowed(true); + }); + } + } +} diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCaseManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCaseManager.java deleted file mode 100644 index bedc09d799..0000000000 --- a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCaseManager.java +++ /dev/null @@ -1,442 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2011-2017 Basis Technology Corp. - * Contact: carrier sleuthkit org - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.sleuthkit.autopsy.casemodule; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.Date; -import java.util.List; -import java.util.Objects; -import java.util.logging.Level; -import org.sleuthkit.autopsy.coordinationservice.CaseNodeData; -import org.sleuthkit.autopsy.coordinationservice.CoordinationService; -import org.sleuthkit.autopsy.coordinationservice.CoordinationService.CoordinationServiceException; -import org.sleuthkit.autopsy.coreutils.Logger; - -/** - * Handles locating and opening multi-user cases. - */ -final class MultiUserCaseManager { - - private static final Logger LOGGER = Logger.getLogger(MultiUserCaseManager.class.getName()); - private static final String ALERT_FILE_NAME = "autoingest.alert"; - private static MultiUserCaseManager instance; - private CoordinationService coordinationService; - - /** - * Gets the multi-user case manager. - * - * @return The multi-user case manager singleton. - * - * @throws MultiUserCaseManagerException - */ - synchronized static MultiUserCaseManager getInstance() throws MultiUserCaseManager.MultiUserCaseManagerException { - if (null == instance) { - instance = new MultiUserCaseManager(); - } - return instance; - } - - /** - * Constructs an object that handles locating and opening multi-user cases. - * - * @throws MultiUserCaseManagerException - */ - private MultiUserCaseManager() throws MultiUserCaseManagerException { - try { - coordinationService = CoordinationService.getInstance(); - } catch (CoordinationServiceException ex) { - throw new MultiUserCaseManager.MultiUserCaseManagerException("Failed to get the coordination service.", ex); - } - } - - /** - * Gets a list of the cases in the top level case folder - * - * @return List of cases. - * - * @throws CoordinationServiceException - */ - List getCases() throws CoordinationServiceException { - List cases = new ArrayList<>(); - List nodeList = coordinationService.getNodeList(CoordinationService.CategoryNode.CASES); - for (String node : nodeList) { - Path casePath = Paths.get(node); - File caseFolder = casePath.toFile(); - if (caseFolder.exists()) { - /* - * Search for '*.aut' and 'autoingest.alert' files. - */ - File[] fileArray = caseFolder.listFiles(); - if (fileArray == null) { - continue; - } - String autFilePath = null; - boolean alertFileFound = false; - for (File file : fileArray) { - String name = file.getName().toLowerCase(); - if (autFilePath == null && name.endsWith(".aut")) { - autFilePath = file.getAbsolutePath(); - if (!alertFileFound) { - continue; - } - } - if (!alertFileFound && name.endsWith(ALERT_FILE_NAME)) { - alertFileFound = true; - } - if (autFilePath != null && alertFileFound) { - break; - } - } - - if (autFilePath != null) { - try { - CaseStatus caseStatus; - if (alertFileFound) { - /* - * When an alert file exists, ignore the node data - * and use the ALERT status. - */ - caseStatus = CaseStatus.ALERT; - } else { - byte[] rawData = coordinationService.getNodeData(CoordinationService.CategoryNode.CASES, node); - if (rawData != null && rawData.length > 0) { - /* - * When node data exists, use the status stored - * in the node data. - */ - CaseNodeData caseNodeData = new CaseNodeData(rawData); - if (caseNodeData.getErrorsOccurred()) { - caseStatus = CaseStatus.ALERT; - } else { - caseStatus = CaseStatus.OK; - } - } else { - /* - * When no node data is available, use the 'OK' - * status to avoid confusing the end-user. - */ - caseStatus = CaseStatus.OK; - } - } - - CaseMetadata caseMetadata = new CaseMetadata(Paths.get(autFilePath)); - cases.add(new MultiUserCase(casePath, caseMetadata, caseStatus)); - } catch (CaseMetadata.CaseMetadataException | MultiUserCase.MultiUserCaseException ex) { - LOGGER.log(Level.SEVERE, String.format("Error reading case metadata file '%s'.", autFilePath), ex); - } catch (InterruptedException | CaseNodeData.InvalidDataException ex) { - LOGGER.log(Level.SEVERE, String.format("Error reading case node data for '%s'.", node), ex); - } - } - } - } - return cases; - } - - /** - * Opens a multi-user case. - * - * @param caseMetadataFilePath Path to the case metadata file. - * - * @throws CaseActionException - */ - synchronized void openCase(Path caseMetadataFilePath) throws CaseActionException { - /* - * Open the case. - */ - Case.openAsCurrentCase(caseMetadataFilePath.toString()); - } - - /** - * Exception type thrown when there is an error completing a multi-user case - * manager operation. - */ - static final class MultiUserCaseManagerException extends Exception { - - private static final long serialVersionUID = 1L; - - /** - * Constructs an instance of the exception type thrown when there is an - * error completing a multi-user case manager operation. - * - * @param message The exception message. - */ - private MultiUserCaseManagerException(String message) { - super(message); - } - - /** - * Constructs an instance of the exception type thrown when there is an - * error completing a multi-user case manager operation. - * - * @param message The exception message. - * @param cause A Throwable cause for the error. - */ - private MultiUserCaseManagerException(String message, Throwable cause) { - super(message, cause); - } - - } - - /** - * A representation of a multi-user case. - */ - static class MultiUserCase implements Comparable { - - private final Path caseDirectoryPath; - private final String caseDisplayName; - private final String metadataFileName; - private final Date createDate; - private final Date lastAccessedDate; - private CaseStatus status; - - /** - * Constructs a representation of a multi-user case - * - * @param caseDirectoryPath The case directory path. - * @param caseMetadata The case metadata. - * - * @throws MultiUserCaseException If no case metadata (.aut) file is - * found in the case directory. - */ - MultiUserCase(Path caseDirectoryPath, CaseMetadata caseMetadata, CaseStatus status) throws MultiUserCaseException { - this.caseDirectoryPath = caseDirectoryPath; - caseDisplayName = caseMetadata.getCaseDisplayName(); - metadataFileName = caseMetadata.getFilePath().getFileName().toString(); - this.status = status; - BasicFileAttributes fileAttrs = null; - try { - fileAttrs = Files.readAttributes(Paths.get(caseDirectoryPath.toString(), metadataFileName), BasicFileAttributes.class); - } catch (IOException ex) { - LOGGER.log(Level.SEVERE, String.format("Error reading file attributes of case metadata file in %s, will use current time for case createDate/lastModfiedDate", caseDirectoryPath), ex); - } - if (null != fileAttrs) { - createDate = new Date(fileAttrs.creationTime().toMillis()); - lastAccessedDate = new Date(fileAttrs.lastAccessTime().toMillis()); - } else { - createDate = new Date(); - lastAccessedDate = new Date(); - } - } - - /** - * Gets the case directory path. - * - * @return The case directory path. - */ - Path getCaseDirectoryPath() { - return this.caseDirectoryPath; - } - - /** - * Gets the case display name. This may differ from the name supplied to - * the directory or metadata file names if a case has been renamed. - * - * @return The case display name. - */ - String getCaseDisplayName() { - return this.caseDisplayName; - } - - /** - * Gets the creation date for the case, defined as the create time of - * the case metadata file. - * - * @return The case creation date. - */ - Date getCreationDate() { - return this.createDate; - } - - /** - * Gets the last accessed date for the case, defined as the last - * accessed time of the case metadata file. - * - * @return The last accessed date. - */ - Date getLastAccessedDate() { - return this.lastAccessedDate; - } - - /** - * Gets metadata (.aut) file name. - * - * @return The metadata file name. - */ - String getMetadataFileName() { - return this.metadataFileName; - } - - /** - * Gets the status of this case. - * - * @return See CaseStatus enum definition. - */ - CaseStatus getStatus() { - return status; - } - - /** - * Gets the case metadata from a case directory path. - * - * @param caseDirectoryPath The case directory path. - * - * @return Case metadata. - * - * @throws CaseMetadata.CaseMetadataException If the CaseMetadata object - * cannot be constructed. - * @throws MultiUserCaseException If no case metadata (.aut) - * file is found in the case - * directory. - */ - private CaseMetadata getCaseMetadataFromCaseDirectoryPath(Path caseDirectoryPath) throws CaseMetadata.CaseMetadataException, MultiUserCaseException { - CaseMetadata caseMetadata = null; - - File directory = new File(caseDirectoryPath.toString()); - if (directory.isDirectory()) { - File autFile = null; - - /* - * Attempt to find an AUT file via a directory scan. - */ - for (File file : directory.listFiles()) { - if (file.getName().toLowerCase().endsWith(CaseMetadata.getFileExtension()) && file.isFile()) { - autFile = file; - break; - } - } - - if (autFile == null || !autFile.isFile()) { - throw new MultiUserCaseException(String.format("No case metadata (.aut) file found in the case directory '%s'.", caseDirectoryPath.toString())); - } - - caseMetadata = new CaseMetadata(Paths.get(autFile.getAbsolutePath())); - } - - return caseMetadata; - } - - /** - * Indicates whether or not some other object is "equal to" this - * MultiUserCase object. - * - * @param other The other object. - * - * @return True or false. - */ - @Override - public boolean equals(Object other) { - if (!(other instanceof MultiUserCase)) { - return false; - } - if (other == this) { - return true; - } - return this.caseDirectoryPath.toString().equals(((MultiUserCase) other).caseDirectoryPath.toString()); - } - - /** - * Returns a hash code value for this MultiUserCase object. - * - * @return The has code. - */ - @Override - public int hashCode() { - int hash = 7; - hash = 71 * hash + Objects.hashCode(this.caseDirectoryPath); - hash = 71 * hash + Objects.hashCode(this.createDate); - hash = 71 * hash + Objects.hashCode(this.caseDisplayName); - return hash; - } - - /** - * Compares this MultiUserCase object with another MultiUserCase object - * for order. - */ - @Override - public int compareTo(MultiUserCase other) { - return -this.lastAccessedDate.compareTo(other.getLastAccessedDate()); - } - - /** - * Comparator for a descending order sort on date created. - */ - static class LastAccessedDateDescendingComparator implements Comparator { - - /** - * Compares two MultiUserCase objects for order based on last - * accessed date (descending). - * - * @param object The first MultiUserCase object - * @param otherObject The second MultiUserCase object. - * - * @return A negative integer, zero, or a positive integer as the - * first argument is less than, equal to, or greater than - * the second. - */ - @Override - public int compare(MultiUserCase object, MultiUserCase otherObject) { - return -object.getLastAccessedDate().compareTo(otherObject.getLastAccessedDate()); - } - } - - /** - * Exception thrown when there is a problem creating a multi-user case. - */ - final class MultiUserCaseException extends Exception { - - private static final long serialVersionUID = 1L; - - /** - * Constructs an exception to throw when there is a problem creating - * a multi-user case. - * - * @param message The exception message. - */ - private MultiUserCaseException(String message) { - super(message); - } - - /** - * Constructs an exception to throw when there is a problem creating - * a multi-user case. - * - * @param message The exception message. - * @param cause The cause of the exception, if it was an - * exception. - */ - private MultiUserCaseException(String message, Throwable cause) { - super(message, cause); - } - } - - } - - static enum CaseStatus { - OK, - ALERT - } - -} diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.form index 58ef6f79fb..3f897d70c0 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.form @@ -1,10 +1,6 @@
- - - - @@ -26,30 +22,19 @@ - + - + + - + + - - - - - - - - - - - - - + - @@ -59,26 +44,15 @@ - + - - - - - - - - - - - - - - - - + + + + + - + @@ -95,140 +69,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -239,5 +79,26 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.java index e0d63f07d7..a2a2ec13ad 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserCasesPanel.java @@ -19,79 +19,29 @@ package org.sleuthkit.autopsy.casemodule; import java.awt.Cursor; -import java.awt.Desktop; -import java.io.IOException; -import java.nio.file.Path; -import java.nio.file.Paths; import java.util.ArrayList; import java.util.Date; -import java.util.List; import java.util.logging.Level; import javax.swing.JDialog; -import javax.swing.JOptionPane; +import javax.swing.JPanel; import javax.swing.SortOrder; -import javax.swing.SwingWorker; import javax.swing.SwingUtilities; import javax.swing.event.ListSelectionEvent; import javax.swing.table.DefaultTableModel; -import javax.swing.table.TableColumn; import javax.swing.table.TableRowSorter; import org.openide.util.Lookup; -import org.openide.util.NbBundle; -import org.sleuthkit.autopsy.casemodule.MultiUserCaseManager.MultiUserCase; -import org.sleuthkit.autopsy.coordinationservice.CoordinationService; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.guiutils.LongDateCellRenderer; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; -import org.sleuthkit.autopsy.guiutils.GrayableCellRenderer; -import org.sleuthkit.autopsy.guiutils.StatusIconCellRenderer; /** * A panel that allows a user to open cases created by auto ingest. */ -@NbBundle.Messages({"MultiUSerCasesPanel.caseListLoading.message=Retrieving list of cases, please wait..."}) -final class MultiUserCasesPanel extends javax.swing.JPanel { +final class MultiUserCasesPanel extends JPanel{ - private static final long serialVersionUID = 1L; private static final Logger LOGGER = Logger.getLogger(MultiUserCasesPanel.class.getName()); - private static final String LOG_FILE_NAME = "auto_ingest_log.txt"; - private static final int CASE_COL_MIN_WIDTH = 30; - private static final int CASE_COL_MAX_WIDTH = 2000; - private static final int CASE_COL_PREFERRED_WIDTH = 300; - private static final int TIME_COL_MIN_WIDTH = 40; - private static final int TIME_COL_MAX_WIDTH = 250; - private static final int TIME_COL_PREFERRED_WIDTH = 160; - private static final int STATUS_COL_MIN_WIDTH = 55; - private static final int STATUS_COL_MAX_WIDTH = 250; - private static final int STATUS_COL_PREFERRED_WIDTH = 60; - private static final String CASES_POPULATING_MESSAGE = NbBundle.getMessage(MultiUserCasesPanel.class, "MultiUSerCasesPanel.caseListLoading.message"); - - /* - * The JTable table model for the cases table presented by this view is - * defined by the following string, enum, and array. - * - * TODO (RC): Consider unifying this stuff in an enum as in - * AutoIngestDashboard to make it less error prone. - */ - private static final String CASE_HEADER = NbBundle.getMessage(MultiUserCasesPanel.class, "ReviewModeCasePanel.CaseHeaderText"); - private static final String CREATEDTIME_HEADER = NbBundle.getMessage(MultiUserCasesPanel.class, "ReviewModeCasePanel.CreatedTimeHeaderText"); - private static final String STATUS_ICON_HEADER = NbBundle.getMessage(MultiUserCasesPanel.class, "ReviewModeCasePanel.StatusIconHeaderText"); - private static final String OUTPUT_FOLDER_HEADER = NbBundle.getMessage(MultiUserCasesPanel.class, "ReviewModeCasePanel.OutputFolderHeaderText"); - private static final String METADATA_FILE_HEADER = NbBundle.getMessage(MultiUserCasesPanel.class, "ReviewModeCasePanel.MetadataFileHeaderText"); - - enum COLUMN_HEADERS { - - CASE, - CREATEDTIME, - STATUS_ICON, - OUTPUTFOLDER, - METADATA_FILE - } - private final String[] columnNames = {CASE_HEADER, CREATEDTIME_HEADER, STATUS_ICON_HEADER, OUTPUT_FOLDER_HEADER, METADATA_FILE_HEADER}; - private DefaultTableModel caseTableModel; - private JDialog parentDialog; - private LoadTableWorker tableWorker; - private Path currentlySelectedCase; + private static final long serialVersionUID = 1L; + private final JDialog parentDialog; + private final CaseBrowser caseBrowserPanel; /** * Constructs a panel that allows a user to open cases created by automated @@ -99,66 +49,19 @@ final class MultiUserCasesPanel extends javax.swing.JPanel { */ MultiUserCasesPanel(JDialog parentDialog) { this.parentDialog = parentDialog; - caseTableModel = new DefaultTableModel(columnNames, 0) { - private static final long serialVersionUID = 1L; - - @Override - public boolean isCellEditable(int row, int column) { - return false; - } - - @Override - public Class getColumnClass(int col) { - if (this.getColumnName(col).equals(CREATEDTIME_HEADER)) { - return Date.class; - } else { - return super.getColumnClass(col); - } - } - }; - initComponents(); - /* - * Configure the columns of the cases table. - */ - TableColumn theColumn; - theColumn = casesTable.getColumn(CASE_HEADER); - theColumn.setCellRenderer(new GrayableCellRenderer()); - theColumn.setMinWidth(CASE_COL_MIN_WIDTH); - theColumn.setMaxWidth(CASE_COL_MAX_WIDTH); - theColumn.setPreferredWidth(CASE_COL_PREFERRED_WIDTH); - theColumn.setWidth(CASE_COL_PREFERRED_WIDTH); - - theColumn = casesTable.getColumn(CREATEDTIME_HEADER); - theColumn.setCellRenderer(new LongDateCellRenderer()); - theColumn.setMinWidth(TIME_COL_MIN_WIDTH); - theColumn.setMaxWidth(TIME_COL_MAX_WIDTH); - theColumn.setPreferredWidth(TIME_COL_PREFERRED_WIDTH); - theColumn.setWidth(TIME_COL_PREFERRED_WIDTH); - - theColumn = casesTable.getColumn(STATUS_ICON_HEADER); - theColumn.setCellRenderer(new StatusIconCellRenderer()); - theColumn.setMinWidth(STATUS_COL_MIN_WIDTH); - theColumn.setMaxWidth(STATUS_COL_MAX_WIDTH); - theColumn.setPreferredWidth(STATUS_COL_PREFERRED_WIDTH); - theColumn.setWidth(STATUS_COL_PREFERRED_WIDTH); - - casesTable.removeColumn(casesTable.getColumn(OUTPUT_FOLDER_HEADER)); - casesTable.removeColumn(casesTable.getColumn(METADATA_FILE_HEADER)); - casesTable.setRowSorter(new RowSorter<>(caseTableModel)); - casesTable.getRowSorter().toggleSortOrder(casesTable.getColumn(CREATEDTIME_HEADER).getModelIndex()); + caseBrowserPanel = new CaseBrowser(); + caseExplorerScrollPane.add(caseBrowserPanel); + caseExplorerScrollPane.setViewportView(caseBrowserPanel); /* * Listen for row selection changes and set button state for the current * selection. */ - casesTable.getSelectionModel().addListSelectionListener((ListSelectionEvent e) -> { - //Ignore extra messages. - if (e.getValueIsAdjusting()) { - return; - } + caseBrowserPanel.addListSelectionListener((ListSelectionEvent e) -> { setButtons(); }); + } /** @@ -166,87 +69,15 @@ final class MultiUserCasesPanel extends javax.swing.JPanel { * refreshes the cases table. */ void refresh() { - if (tableWorker == null || tableWorker.isDone()) { - //create a new TableWorker to and execute it in a background thread if one is not currently working - currentlySelectedCase = getSelectedCase(); - //set the table to display text informing the user that the list is being retreived and disable case selection - caseTableModel.setRowCount(0); - casesTable.setRowSelectionAllowed(false); - caseTableModel.addRow(new Object[]{CASES_POPULATING_MESSAGE, null, null, "", ""}); - tableWorker = new LoadTableWorker(); - tableWorker.execute(); - } - } - - /** - * Gets the current selection in the cases table. - * - * @return A path representing the current selected case, null if there is - * no selection. - */ - private Path getSelectedCase() { - try { - int selectedRow = casesTable.getSelectedRow(); - if (selectedRow >= 0 && selectedRow < casesTable.getRowCount()) { - return Paths.get(caseTableModel.getValueAt(casesTable.convertRowIndexToModel(selectedRow), COLUMN_HEADERS.CASE.ordinal()).toString()); - } - } catch (Exception ignored) { - return null; - } - return null; - } - - /** - * Sets the current selection in the cases table. - * - * @param path The case folder path of the case to select. - */ - private void setSelectedCase(Path path) { - if (path != null) { - try { - for (int row = 0; row < casesTable.getRowCount(); ++row) { - Path temp = Paths.get(caseTableModel.getValueAt(casesTable.convertRowIndexToModel(row), COLUMN_HEADERS.CASE.ordinal()).toString()); - if (temp.compareTo(path) == 0) { // found it - casesTable.setRowSelectionInterval(row, row); - return; - } - } - } catch (Exception ignored) { - casesTable.clearSelection(); - } - } - casesTable.clearSelection(); + caseBrowserPanel.refresh(); } /** * Enables/disables the Open and Show Log buttons based on the case selected * in the cases table. */ - private void setButtons() { - boolean openEnabled = casesTable.getRowSelectionAllowed() && casesTable.getSelectedRow() >= 0 && casesTable.getSelectedRow() < casesTable.getRowCount(); - bnOpen.setEnabled(openEnabled); - - Path pathToLog = getSelectedCaseLogFilePath(); - boolean showLogEnabled = openEnabled && pathToLog != null && pathToLog.toFile().exists(); - bnShowLog.setEnabled(showLogEnabled); - } - - /** - * Retrieves the log file path for the selected case in the cases table. - * - * @return The case log path. - */ - private Path getSelectedCaseLogFilePath() { - Path retValue = null; - - int selectedRow = casesTable.getSelectedRow(); - int rowCount = casesTable.getRowCount(); - if (selectedRow >= 0 && selectedRow < rowCount) { - String caseDirectory = (String) caseTableModel.getValueAt(casesTable.convertRowIndexToModel(selectedRow), COLUMN_HEADERS.OUTPUTFOLDER.ordinal()); - retValue = Paths.get(caseDirectory, LOG_FILE_NAME); - } - - return retValue; + void setButtons() { + bnOpen.setEnabled(caseBrowserPanel.isRowSelected()); } /** @@ -254,56 +85,34 @@ final class MultiUserCasesPanel extends javax.swing.JPanel { * * @param caseMetadataFilePath The path to the case metadata file. */ - private void openCase(Path caseMetadataFilePath) { - setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + private void openCase(String caseMetadataFilePath) { + if (caseMetadataFilePath != null) { + setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - StartupWindowProvider.getInstance().close(); - if (parentDialog != null) { - parentDialog.setVisible(false); - } - new Thread(() -> { - try { - MultiUserCaseManager.getInstance().openCase(caseMetadataFilePath); - } catch (CaseActionException | MultiUserCaseManager.MultiUserCaseManagerException ex) { - if (null != ex.getCause() && !(ex.getCause() instanceof CaseActionCancelledException)) { - LOGGER.log(Level.SEVERE, String.format("Error opening case with metadata file path %s", caseMetadataFilePath), ex); //NON-NLS - MessageNotifyUtil.Message.error(ex.getCause().getLocalizedMessage()); - } - SwingUtilities.invokeLater(() -> { - //GUI changes done back on the EDT - StartupWindowProvider.getInstance().open(); - }); - } finally { - SwingUtilities.invokeLater(() -> { - //GUI changes done back on the EDT - setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); - }); + StartupWindowProvider.getInstance().close(); + if (parentDialog != null) { + parentDialog.setVisible(false); } - }).start(); - } - - /** - * Indicates whether or not a time satisfies a time filter defined by this - * panel's time filter radio buttons. - * - * @param currentTime The current date and time in milliseconds from the - * Unix epoch. - * @param inputTime The date and time to be tested as milliseconds from - * the Unix epoch. - */ - private boolean passesTimeFilter(long currentTime, long inputTime) { - long numberOfUnits = 10; - long multiplier = 1; - if (rbAllCases.isSelected()) { - return true; - } else if (rbMonths.isSelected()) { - multiplier = 31; - } else if (rbWeeks.isSelected()) { - multiplier = 7; - } else if (rbDays.isSelected()) { - multiplier = 1; + new Thread(() -> { + try { + Case.openAsCurrentCase(caseMetadataFilePath); + } catch (CaseActionException ex) { + if (null != ex.getCause() && !(ex.getCause() instanceof CaseActionCancelledException)) { + LOGGER.log(Level.SEVERE, String.format("Error opening case with metadata file path %s", caseMetadataFilePath), ex); //NON-NLS + MessageNotifyUtil.Message.error(ex.getCause().getLocalizedMessage()); + } + SwingUtilities.invokeLater(() -> { + //GUI changes done back on the EDT + StartupWindowProvider.getInstance().open(); + }); + } finally { + SwingUtilities.invokeLater(() -> { + //GUI changes done back on the EDT + setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + }); + } + }).start(); } - return ((currentTime - inputTime) / (1000 * 60 * 60 * 24)) < (numberOfUnits * multiplier); } /** @@ -345,19 +154,11 @@ final class MultiUserCasesPanel extends javax.swing.JPanel { // //GEN-BEGIN:initComponents private void initComponents() { - rbGroupHistoryLength = new javax.swing.ButtonGroup(); bnOpen = new javax.swing.JButton(); - scrollPaneTable = new javax.swing.JScrollPane(); - casesTable = new javax.swing.JTable(); - bnRefresh = new javax.swing.JButton(); - panelFilter = new javax.swing.JPanel(); - rbAllCases = new javax.swing.JRadioButton(); - bnShowLog = new javax.swing.JButton(); - rbDays = new javax.swing.JRadioButton(); - rbWeeks = new javax.swing.JRadioButton(); - rbMonths = new javax.swing.JRadioButton(); - rbGroupLabel = new javax.swing.JLabel(); bnOpenSingleUserCase = new javax.swing.JButton(); + cancelButton = new javax.swing.JButton(); + searchLabel = new javax.swing.JLabel(); + caseExplorerScrollPane = new javax.swing.JScrollPane(); setName("Completed Cases"); // NOI18N setPreferredSize(new java.awt.Dimension(960, 485)); @@ -370,84 +171,6 @@ final class MultiUserCasesPanel extends javax.swing.JPanel { } }); - casesTable.setModel(caseTableModel); - casesTable.setRowHeight(20); - casesTable.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); - casesTable.addMouseListener(new java.awt.event.MouseAdapter() { - public void mouseClicked(java.awt.event.MouseEvent evt) { - casesTableMouseClicked(evt); - } - }); - scrollPaneTable.setViewportView(casesTable); - - org.openide.awt.Mnemonics.setLocalizedText(bnRefresh, org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "MultiUserCasesPanel.bnRefresh.text")); // NOI18N - bnRefresh.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - bnRefreshActionPerformed(evt); - } - }); - - rbGroupHistoryLength.add(rbAllCases); - rbAllCases.setSelected(true); - org.openide.awt.Mnemonics.setLocalizedText(rbAllCases, org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "MultiUserCasesPanel.rbAllCases.text")); // NOI18N - rbAllCases.addItemListener(new java.awt.event.ItemListener() { - public void itemStateChanged(java.awt.event.ItemEvent evt) { - rbAllCasesItemStateChanged(evt); - } - }); - - javax.swing.GroupLayout panelFilterLayout = new javax.swing.GroupLayout(panelFilter); - panelFilter.setLayout(panelFilterLayout); - panelFilterLayout.setHorizontalGroup( - panelFilterLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(panelFilterLayout.createSequentialGroup() - .addComponent(rbAllCases) - .addGap(0, 0, Short.MAX_VALUE)) - ); - panelFilterLayout.setVerticalGroup( - panelFilterLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, panelFilterLayout.createSequentialGroup() - .addGap(0, 0, 0) - .addComponent(rbAllCases)) - ); - - org.openide.awt.Mnemonics.setLocalizedText(bnShowLog, org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "MultiUserCasesPanel.bnShowLog.text")); // NOI18N - bnShowLog.setToolTipText(org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "MultiUserCasesPanel.bnShowLog.toolTipText")); // NOI18N - bnShowLog.setEnabled(false); - bnShowLog.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - bnShowLogActionPerformed(evt); - } - }); - - rbGroupHistoryLength.add(rbDays); - org.openide.awt.Mnemonics.setLocalizedText(rbDays, org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "MultiUserCasesPanel.rbDays.text")); // NOI18N - rbDays.setName(""); // NOI18N - rbDays.addItemListener(new java.awt.event.ItemListener() { - public void itemStateChanged(java.awt.event.ItemEvent evt) { - rbDaysItemStateChanged(evt); - } - }); - - rbGroupHistoryLength.add(rbWeeks); - org.openide.awt.Mnemonics.setLocalizedText(rbWeeks, org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "MultiUserCasesPanel.rbWeeks.text")); // NOI18N - rbWeeks.addItemListener(new java.awt.event.ItemListener() { - public void itemStateChanged(java.awt.event.ItemEvent evt) { - rbWeeksItemStateChanged(evt); - } - }); - - rbGroupHistoryLength.add(rbMonths); - org.openide.awt.Mnemonics.setLocalizedText(rbMonths, org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "MultiUserCasesPanel.rbMonths.text")); // NOI18N - rbMonths.addItemListener(new java.awt.event.ItemListener() { - public void itemStateChanged(java.awt.event.ItemEvent evt) { - rbMonthsItemStateChanged(evt); - } - }); - - rbGroupLabel.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(rbGroupLabel, org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "MultiUserCasesPanel.rbGroupLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(bnOpenSingleUserCase, org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "MultiUserCasesPanel.bnOpenSingleUserCase.text")); // NOI18N bnOpenSingleUserCase.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { @@ -455,55 +178,45 @@ final class MultiUserCasesPanel extends javax.swing.JPanel { } }); + org.openide.awt.Mnemonics.setLocalizedText(cancelButton, org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "MultiUserCasesPanel.cancelButton.text")); // NOI18N + cancelButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + cancelButtonActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(searchLabel, org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "MultiUserCasesPanel.searchLabel.text")); // NOI18N + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() .addContainerGap() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(caseExplorerScrollPane) .addGroup(layout.createSequentialGroup() - .addGap(4, 4, 4) + .addComponent(searchLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 555, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 175, Short.MAX_VALUE) .addComponent(bnOpen, javax.swing.GroupLayout.PREFERRED_SIZE, 80, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(bnOpenSingleUserCase) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(bnShowLog) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 13, Short.MAX_VALUE) - .addComponent(rbGroupLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(rbDays) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(rbWeeks) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(rbMonths) - .addGap(0, 0, 0) - .addComponent(panelFilter, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(14, 14, 14) - .addComponent(bnRefresh)) - .addComponent(scrollPaneTable)) + .addComponent(cancelButton))) .addContainerGap()) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addGap(6, 6, 6) - .addComponent(scrollPaneTable, javax.swing.GroupLayout.PREFERRED_SIZE, 450, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(caseExplorerScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 450, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(bnOpen) - .addComponent(bnOpenSingleUserCase) - .addComponent(bnShowLog)) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(rbDays) - .addComponent(rbWeeks) - .addComponent(rbMonths) - .addComponent(rbGroupLabel)) - .addComponent(panelFilter, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addComponent(bnRefresh, javax.swing.GroupLayout.Alignment.TRAILING)) - .addGap(0, 0, 0)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(cancelButton) + .addComponent(bnOpen) + .addComponent(bnOpenSingleUserCase) + .addComponent(searchLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); }// //GEN-END:initComponents @@ -513,129 +226,24 @@ final class MultiUserCasesPanel extends javax.swing.JPanel { * @param evt -- The event that caused this to be called */ private void bnOpenActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnOpenActionPerformed - int modelRow = casesTable.convertRowIndexToModel(casesTable.getSelectedRow()); - String caseDirectory = (String) caseTableModel.getValueAt(modelRow, COLUMN_HEADERS.OUTPUTFOLDER.ordinal()); - Path caseMetadataFilePath = Paths.get(caseDirectory, (String) caseTableModel.getValueAt(modelRow, COLUMN_HEADERS.METADATA_FILE.ordinal())); - openCase(caseMetadataFilePath); + openCase(caseBrowserPanel.getCasePath()); }//GEN-LAST:event_bnOpenActionPerformed - /** - * Refresh button action - * - * @param evt -- The event that caused this to be called - */ - private void bnRefreshActionPerformed(java.awt.event.ActionEvent evt) { - refresh(); - } - - private void rbDaysItemStateChanged(java.awt.event.ItemEvent evt) { - if (rbDays.isSelected()) { - refresh(); - } - } - - private void rbAllCasesItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_rbAllCasesItemStateChanged - if (rbAllCases.isSelected()) { - refresh(); - } - }//GEN-LAST:event_rbAllCasesItemStateChanged - - private void rbMonthsItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_rbMonthsItemStateChanged - if (rbMonths.isSelected()) { - refresh(); - } - }//GEN-LAST:event_rbMonthsItemStateChanged - - private void rbWeeksItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_rbWeeksItemStateChanged - if (rbWeeks.isSelected()) { - refresh(); - } - }//GEN-LAST:event_rbWeeksItemStateChanged - - private void bnShowLogActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnShowLogActionPerformed - Path pathToLog = getSelectedCaseLogFilePath(); - if (pathToLog != null) { - try { - if (pathToLog.toFile().exists()) { - Desktop.getDesktop().edit(pathToLog.toFile()); - - } else { - JOptionPane.showMessageDialog(this, org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "DisplayLogDialog.cannotFindLog"), - org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "DisplayLogDialog.unableToShowLogFile"), JOptionPane.ERROR_MESSAGE); - } - } catch (IOException ex) { - LOGGER.log(Level.SEVERE, String.format("Error attempting to open case auto ingest log file %s", pathToLog), ex); - JOptionPane.showMessageDialog(this, - org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "DisplayLogDialog.cannotOpenLog"), - org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "DisplayLogDialog.unableToShowLogFile"), - JOptionPane.PLAIN_MESSAGE); - } - } - }//GEN-LAST:event_bnShowLogActionPerformed - - private void casesTableMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_casesTableMouseClicked - if (evt.getClickCount() == 2 && casesTable.getRowSelectionAllowed() && casesTable.getSelectedRow() >= 0 && casesTable.getSelectedRow() < casesTable.getRowCount()) { - int modelRow = casesTable.convertRowIndexToModel(casesTable.getSelectedRow()); - String caseDirectory = (String) caseTableModel.getValueAt(modelRow, COLUMN_HEADERS.OUTPUTFOLDER.ordinal()); - Path caseMetadataFilePath = Paths.get(caseDirectory, (String) caseTableModel.getValueAt(modelRow, COLUMN_HEADERS.METADATA_FILE.ordinal())); - openCase(caseMetadataFilePath); - } - }//GEN-LAST:event_casesTableMouseClicked - private void bnOpenSingleUserCaseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnOpenSingleUserCaseActionPerformed Lookup.getDefault().lookup(CaseOpenAction.class).openCaseSelectionWindow(); }//GEN-LAST:event_bnOpenSingleUserCaseActionPerformed + private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed + if (parentDialog != null) { + parentDialog.setVisible(false); + } + }//GEN-LAST:event_cancelButtonActionPerformed + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton bnOpen; private javax.swing.JButton bnOpenSingleUserCase; - private javax.swing.JButton bnRefresh; - private javax.swing.JButton bnShowLog; - private javax.swing.JTable casesTable; - private javax.swing.JPanel panelFilter; - private javax.swing.JRadioButton rbAllCases; - private javax.swing.JRadioButton rbDays; - private javax.swing.ButtonGroup rbGroupHistoryLength; - private javax.swing.JLabel rbGroupLabel; - private javax.swing.JRadioButton rbMonths; - private javax.swing.JRadioButton rbWeeks; - private javax.swing.JScrollPane scrollPaneTable; + private javax.swing.JButton cancelButton; + private javax.swing.JScrollPane caseExplorerScrollPane; + private javax.swing.JLabel searchLabel; // End of variables declaration//GEN-END:variables - - private class LoadTableWorker extends SwingWorker { - - private List cases; - - @Override - protected Void doInBackground() throws Exception { - - try { - MultiUserCaseManager manager = MultiUserCaseManager.getInstance(); - cases = manager.getCases(); - } catch (MultiUserCaseManager.MultiUserCaseManagerException | CoordinationService.CoordinationServiceException ex) { - LOGGER.log(Level.SEVERE, "Unexpected exception while refreshing the table.", ex); //NON-NLS - } - return null; - } - - @Override - protected void done() { - caseTableModel.setRowCount(0); - long now = new Date().getTime(); - for (MultiUserCase autoIngestCase : cases) { - if (autoIngestCase.getCreationDate() != null && passesTimeFilter(now, autoIngestCase.getCreationDate().getTime())) { - caseTableModel.addRow(new Object[]{ - autoIngestCase.getCaseDisplayName(), - autoIngestCase.getCreationDate(), - (MultiUserCaseManager.CaseStatus.OK != autoIngestCase.getStatus()) ? StatusIconCellRenderer.Status.WARNING : StatusIconCellRenderer.Status.OK, - autoIngestCase.getCaseDirectoryPath().toString(), - autoIngestCase.getMetadataFileName()}); - } - } - //ensure the cases are able to be selected - casesTable.setRowSelectionAllowed(true); - setSelectedCase(currentlySelectedCase); - setButtons(); - } - } } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserNode.java b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserNode.java new file mode 100644 index 0000000000..9443ae35e9 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/MultiUserNode.java @@ -0,0 +1,241 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2017-2018 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.casemodule; + +import java.awt.Desktop; +import java.awt.event.ActionEvent; +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.logging.Level; +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.JOptionPane; +import javax.swing.SwingUtilities; +import org.openide.nodes.AbstractNode; +import org.openide.nodes.ChildFactory; +import org.openide.nodes.Children; +import org.openide.nodes.Node; +import org.openide.nodes.Sheet; +import org.openide.util.NbBundle.Messages; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; +import org.sleuthkit.autopsy.datamodel.NodeProperty; + +/** + * A root node containing child nodes of the multi user cases + */ +final class MultiUserNode extends AbstractNode { + + @Messages({"CaseNode.column.name=Name", + "CaseNode.column.createdTime=Created Time", + "CaseNode.column.status=Status", + "CaseNode.column.metadataFilePath=Path"}) + private static final Logger LOGGER = Logger.getLogger(MultiUserNode.class.getName()); + private static final String LOG_FILE_NAME = "auto_ingest_log.txt"; + + /** + * Provides a root node with children which each represent a case. + * + * @param caseMap the map of cases and a boolean indicating if they have an + * alert + */ + MultiUserNode(Map caseMap) { + super(Children.create(new MultiUserNodeChildren(caseMap), true)); + } + + static class MultiUserNodeChildren extends ChildFactory> { + + private final Map caseMap; + + MultiUserNodeChildren(Map caseMap) { + this.caseMap = caseMap; + } + + @Override + protected boolean createKeys(List> list) { + if (caseMap != null && caseMap.size() > 0) { + list.addAll(caseMap.entrySet()); + } + return true; + } + + @Override + protected Node createNodeForKey(Entry key) { + return new MultiUserCaseNode(key); + } + + } + + /** + * A node which represents a single multi user case. + */ + static final class MultiUserCaseNode extends AbstractNode { + + private final String caseName; + private final String caseCreatedDate; + private final String caseMetadataFilePath; + private final boolean caseHasAlert; + private final Path caseLogFilePath; + + MultiUserCaseNode(Entry multiUserCase) { + super(Children.LEAF); + caseName = multiUserCase.getKey().getCaseDisplayName(); + caseCreatedDate = multiUserCase.getKey().getCreatedDate(); + caseHasAlert = multiUserCase.getValue(); + super.setName(caseName); + setName(caseName); + setDisplayName(caseName); + caseMetadataFilePath = multiUserCase.getKey().getFilePath().toString(); + caseLogFilePath = Paths.get(multiUserCase.getKey().getCaseDirectory(), LOG_FILE_NAME); + } + + /** + * Returns action to open the Case represented by this node + * @return an action which will open the current case + */ + @Override + public Action getPreferredAction() { + return new OpenMultiUserCaseAction(caseMetadataFilePath); + } + + @Messages({"MultiUserNode.AlertColumn.text=Alert"}) //text to display when there is an alert present + @Override + protected Sheet createSheet() { + Sheet s = super.createSheet(); + Sheet.Set ss = s.get(Sheet.PROPERTIES); + if (ss == null) { + ss = Sheet.createPropertiesSet(); + s.put(ss); + } + ss.put(new NodeProperty<>(Bundle.CaseNode_column_name(), Bundle.CaseNode_column_name(), Bundle.CaseNode_column_name(), + caseName)); + ss.put(new NodeProperty<>(Bundle.CaseNode_column_createdTime(), Bundle.CaseNode_column_createdTime(), Bundle.CaseNode_column_createdTime(), + caseCreatedDate)); + ss.put(new NodeProperty<>(Bundle.CaseNode_column_status(), Bundle.CaseNode_column_status(), Bundle.CaseNode_column_status(), + (caseHasAlert == true ? Bundle.MultiUserNode_AlertColumn_text() : ""))); + ss.put(new NodeProperty<>(Bundle.CaseNode_column_metadataFilePath(), Bundle.CaseNode_column_metadataFilePath(), Bundle.CaseNode_column_metadataFilePath(), + caseMetadataFilePath)); + return s; + } + + @Override + public Action[] getActions(boolean context) { + List actions = new ArrayList<>(); + actions.add(new OpenMultiUserCaseAction(caseMetadataFilePath)); //open case context menu option + actions.add(new OpenCaseLogAction(caseLogFilePath)); + return actions.toArray(new Action[actions.size()]); + } + } + + @Messages({"MultiUserNode.OpenMultiUserCaseAction.text=Open Case"}) + /** + * An action that opens the specified case and hides the multi user case + * panel. + */ + private static final class OpenMultiUserCaseAction extends AbstractAction { + + private static final long serialVersionUID = 1L; + + private final String caseMetadataFilePath; + + OpenMultiUserCaseAction(String path) { + super(Bundle.MultiUserNode_OpenMultiUserCaseAction_text()); + caseMetadataFilePath = path; + } + + @Override + public void actionPerformed(ActionEvent e) { + StartupWindowProvider.getInstance().close(); + MultiUserCasesDialog.getInstance().setVisible(false); + new Thread( + () -> { + try { + Case.openAsCurrentCase(caseMetadataFilePath); + } catch (CaseActionException ex) { + if (null != ex.getCause() && !(ex.getCause() instanceof CaseActionCancelledException)) { + LOGGER.log(Level.SEVERE, String.format("Error opening case with metadata file path %s", caseMetadataFilePath), ex); //NON-NLS + MessageNotifyUtil.Message.error(ex.getCause().getLocalizedMessage()); + } + SwingUtilities.invokeLater(() -> { + //GUI changes done back on the EDT + StartupWindowProvider.getInstance().open(); + MultiUserCasesDialog.getInstance().setVisible(true); + }); + } + } + ).start(); + } + + @Override + public Object clone() throws CloneNotSupportedException { + return super.clone(); //To change body of generated methods, choose Tools | Templates. + } + } + + @Messages({"MultiUserNode.OpenCaseLogAction.text=Open Log File"}) + /** + * An action that opens the specified case and hides the multi user case + * panel. + */ + private static final class OpenCaseLogAction extends AbstractAction { + + private static final long serialVersionUID = 1L; + + private final Path pathToLog; + + OpenCaseLogAction(Path caseLogFilePath) { + super(Bundle.MultiUserNode_OpenCaseLogAction_text()); + pathToLog = caseLogFilePath; + this.setEnabled(caseLogFilePath != null && caseLogFilePath.toFile().exists()); + } + + @Override + public void actionPerformed(ActionEvent e) { + + if (pathToLog != null) { + try { + if (pathToLog.toFile().exists()) { + Desktop.getDesktop().edit(pathToLog.toFile()); + + } else { + JOptionPane.showMessageDialog(MultiUserCasesDialog.getInstance(), org.openide.util.NbBundle.getMessage(MultiUserNode.class, "DisplayLogDialog.cannotFindLog"), + org.openide.util.NbBundle.getMessage(MultiUserNode.class, "DisplayLogDialog.unableToShowLogFile"), JOptionPane.ERROR_MESSAGE); + } + } catch (IOException ex) { + LOGGER.log(Level.SEVERE, String.format("Error attempting to open case auto ingest log file %s", pathToLog), ex); + JOptionPane.showMessageDialog(MultiUserCasesDialog.getInstance(), + org.openide.util.NbBundle.getMessage(MultiUserNode.class, "DisplayLogDialog.cannotOpenLog"), + org.openide.util.NbBundle.getMessage(MultiUserNode.class, "DisplayLogDialog.unableToShowLogFile"), + JOptionPane.PLAIN_MESSAGE); + } + } + } + + @Override + public Object clone() throws CloneNotSupportedException { + return super.clone(); //To change body of generated methods, choose Tools | Templates. + } + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties index 45916b87b3..8267587395 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties @@ -33,3 +33,7 @@ MessageContentViewer.directionText.text=direction MessageContentViewer.ccLabel.text=CC: MessageContentViewer.attachmentsPanel.TabConstraints.tabTitle=Attachments MessageContentViewer.viewInNewWindowButton.text=View in New Window +JPEGViewerDummy.jLabel1.text=You are looking at a JPEG file: +JPEGViewerDummy.jTextField1.text=jTextField1 +SQLiteViewer.jLabel1.text=Table +SQLiteViewer.numEntriesField.text=num Entries diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/FileTypeViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/FileTypeViewer.java new file mode 100644 index 0000000000..f4a677c4f4 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/FileTypeViewer.java @@ -0,0 +1,50 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2018 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.contentviewers; + +import java.awt.Component; +import java.util.List; +import org.sleuthkit.datamodel.AbstractFile; + +/** + * Defines an interface for application specific content viewer + * + */ +interface FileTypeViewer { + + /** + * Returns list of MIME types supported by this viewer + */ + List getSupportedMIMETypes(); + + /** + * Display the given file's content in the view panel + */ + void setFile(AbstractFile file); + + /** + * Returns panel + */ + Component getComponent(); + + /** + * Clears the data in the panel + */ + void resetComponent(); +} diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/FileViewer.form b/Core/src/org/sleuthkit/autopsy/contentviewers/FileViewer.form new file mode 100644 index 0000000000..d07831cafe --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/FileViewer.form @@ -0,0 +1,41 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/FileViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/FileViewer.java new file mode 100644 index 0000000000..0d17ce2cd6 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/FileViewer.java @@ -0,0 +1,235 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2018 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.contentviewers; + +import com.google.common.base.Strings; +import java.awt.Component; +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Level; +import org.openide.nodes.Node; +import org.openide.util.NbBundle; +import org.openide.util.lookup.ServiceProvider; +import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector; +import org.sleuthkit.datamodel.AbstractFile; + +/** + * Generic Application content viewer + */ +@ServiceProvider(service = DataContentViewer.class, position = 5) +public class FileViewer extends javax.swing.JPanel implements DataContentViewer { + + private static final int CONFIDENCE_LEVEL = 7; + private static final long serialVersionUID = 1L; + private static final Logger LOGGER = Logger.getLogger(FileViewer.class.getName()); + + private final Map mimeTypeToViewerMap = new HashMap<>(); + + // TBD: This hardcoded list of viewers should be replaced with a dynamic lookup + private static final FileTypeViewer[] KNOWN_VIEWERS = new FileTypeViewer[]{ + // new JPEGViewerDummy(), // this if for testing only + new SQLiteViewer() + }; + + private FileTypeViewer lastViewer; + + /** + * Creates new form ApplicationContentViewer + */ + public FileViewer() { + + // init the mimetype to viewer map + for (FileTypeViewer cv : KNOWN_VIEWERS) { + cv.getSupportedMIMETypes().forEach((mimeType) -> { + if (mimeTypeToViewerMap.containsKey(mimeType) == false) { + mimeTypeToViewerMap.put(mimeType, cv); + } else { + LOGGER.log(Level.WARNING, "Duplicate viewer for mimtype: {0}", mimeType); //NON-NLS + } + }); + } + + initComponents(); + + LOGGER.log(Level.INFO, "Created ApplicationContentViewer instance: {0}", this); //NON-NLS + } + + /** + * Get the FileTypeViewer for a given mimetype + * + * @param mimeType + * + * @return FileTypeViewer, null if no known content viewer supports the mimetype + */ + private FileTypeViewer getSupportingViewer(String mimeType) { + return mimeTypeToViewerMap.get(mimeType); + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + setLayout(new javax.swing.OverlayLayout(this)); + }// //GEN-END:initComponents + + + // Variables declaration - do not modify//GEN-BEGIN:variables + // End of variables declaration//GEN-END:variables + + @Override + public void setNode(Node selectedNode) { + + resetComponent(); + + if (selectedNode == null) { + return; + } + + AbstractFile file = selectedNode.getLookup().lookup(AbstractFile.class); + if (file == null) { + return; + } + + String mimeType = file.getMIMEType(); + if (Strings.isNullOrEmpty(mimeType)) { + LOGGER.log(Level.INFO, "Mimetype not known for file: {0}", file.getName()); //NON-NLS + try { + FileTypeDetector fileTypeDetector = new FileTypeDetector(); + mimeType = fileTypeDetector.detectMIMEType(file); + }catch (FileTypeDetector.FileTypeDetectorInitException ex) { + LOGGER.log(Level.SEVERE, "Failed to initialize FileTypeDetector.", ex); //NON-NLS + return; + } + } + + if (mimeType.equalsIgnoreCase("application/octet-stream")) { + return; + } + else { + FileTypeViewer viewer = getSupportingViewer(mimeType); + if (viewer != null) { + lastViewer = viewer; + + viewer.setFile(file); + this.removeAll(); + this.add(viewer.getComponent()); + this.repaint(); + } + } + + } + + @Override + @NbBundle.Messages("ApplicationContentViewer.title=Application") + public String getTitle() { + return Bundle.ApplicationContentViewer_title(); + } + + @Override + @NbBundle.Messages("ApplicationContentViewer.toolTip=Displays file contents.") + public String getToolTip() { + return Bundle.ApplicationContentViewer_toolTip(); + } + + @Override + public DataContentViewer createInstance() { + return new FileViewer(); + } + + @Override + public Component getComponent() { + return this; + } + + @Override + public void resetComponent() { + + if (lastViewer != null) { + lastViewer.resetComponent(); + } + this.removeAll(); + lastViewer = null; + } + + @Override + public boolean isSupported(Node node) { + + if (node == null) { + return false; + } + + AbstractFile aFile = node.getLookup().lookup(AbstractFile.class); + if (aFile == null) { + return false; + } + + String mimeType = aFile.getMIMEType(); + if (Strings.isNullOrEmpty(mimeType)) { + LOGGER.log(Level.INFO, "Mimetype not known for file: {0}", aFile.getName()); //NON-NLS + try { + FileTypeDetector fileTypeDetector = new FileTypeDetector(); + mimeType = fileTypeDetector.detectMIMEType(aFile); + }catch (FileTypeDetector.FileTypeDetectorInitException ex) { + LOGGER.log(Level.SEVERE, "Failed to initialize FileTypeDetector.", ex); //NON-NLS + return false; + } + } + + if (mimeType.equalsIgnoreCase("application/octet-stream")) { + return false; + } else { + return (getSupportingViewer(mimeType) != null); + } + + } + + @Override + public int isPreferred(Node node) { + AbstractFile file = node.getLookup().lookup(AbstractFile.class); + String mimeType = file.getMIMEType(); + + if (Strings.isNullOrEmpty(mimeType)) { + LOGGER.log(Level.INFO, "Mimetype not known for file: {0}", file.getName()); //NON-NLS + try { + FileTypeDetector fileTypeDetector = new FileTypeDetector(); + mimeType = fileTypeDetector.detectMIMEType(file); + }catch (FileTypeDetector.FileTypeDetectorInitException ex) { + LOGGER.log(Level.SEVERE, "Failed to initialize FileTypeDetector.", ex); //NON-NLS + return 0; + } + } + + if (mimeType.equalsIgnoreCase("application/octet-stream")) { + return 0; + } else { + if (null != getSupportingViewer(mimeType)) { + return CONFIDENCE_LEVEL; + } + } + + return 0; + } +} diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/JPEGViewerDummy.form b/Core/src/org/sleuthkit/autopsy/contentviewers/JPEGViewerDummy.form new file mode 100644 index 0000000000..587dd3c9a0 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/JPEGViewerDummy.form @@ -0,0 +1,58 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/JPEGViewerDummy.java b/Core/src/org/sleuthkit/autopsy/contentviewers/JPEGViewerDummy.java new file mode 100644 index 0000000000..8aea7540e1 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/JPEGViewerDummy.java @@ -0,0 +1,89 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.contentviewers; + +import java.awt.Component; +import java.util.Arrays; +import java.util.List; +import org.sleuthkit.datamodel.AbstractFile; + +public class JPEGViewerDummy extends javax.swing.JPanel implements FileTypeViewer { + + public static final String[] SUPPORTED_MIMETYPES = new String[]{"image/jpeg"}; + + /** + * Creates new form JPEGViewer + */ + public JPEGViewerDummy() { + initComponents(); + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + jLabel1 = new javax.swing.JLabel(); + jTextField1 = new javax.swing.JTextField(); + + org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(JPEGViewerDummy.class, "JPEGViewerDummy.jLabel1.text")); // NOI18N + + jTextField1.setEditable(false); + jTextField1.setText(org.openide.util.NbBundle.getMessage(JPEGViewerDummy.class, "JPEGViewerDummy.jTextField1.text")); // NOI18N + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGap(43, 43, 43) + .addComponent(jLabel1) + .addGap(35, 35, 35) + .addComponent(jTextField1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap(120, Short.MAX_VALUE)) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jLabel1) + .addComponent(jTextField1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addContainerGap(269, Short.MAX_VALUE)) + ); + }// //GEN-END:initComponents + + @Override + public List getSupportedMIMETypes() { + return Arrays.asList(SUPPORTED_MIMETYPES); + } + + @Override + public Component getComponent() { + return this; + } + + @Override + public void resetComponent() { + this.jTextField1.setText(""); + } + + @Override + public void setFile(AbstractFile file) { + this.jTextField1.setText(file.getName()); + } + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JLabel jLabel1; + private javax.swing.JTextField jTextField1; + // End of variables declaration//GEN-END:variables + +} diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.form b/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.form new file mode 100644 index 0000000000..3cdee8658c --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.form @@ -0,0 +1,153 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+
+
+
+
+
diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java new file mode 100644 index 0000000000..fff2f5d781 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java @@ -0,0 +1,395 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2018 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.contentviewers; + +import java.awt.Component; +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.List; +import java.util.logging.Level; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.Statement; +import java.sql.SQLException; +import java.util.Map; +import java.util.TreeMap; +import java.util.concurrent.ExecutionException; +import javax.swing.JComboBox; +import javax.swing.SwingWorker; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.datamodel.ContentUtils; +import org.sleuthkit.datamodel.AbstractFile; + +public class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer { + + public static final String[] SUPPORTED_MIMETYPES = new String[]{"application/x-sqlite3"}; + private static final Logger LOGGER = Logger.getLogger(FileViewer.class.getName()); + private Connection connection = null; + + private String tmpDBPathName = null; + private File tmpDBFile = null; + + // TBD: Change the value to be a Array of ColDefs + Map dbTablesMap = new TreeMap<>(); + + /** + * Creates new form SQLiteViewer + */ + public SQLiteViewer() { + initComponents(); + + customizeComponents(); + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + jHdrPanel = new javax.swing.JPanel(); + tablesDropdownList = new javax.swing.JComboBox<>(); + jLabel1 = new javax.swing.JLabel(); + numEntriesField = new javax.swing.JTextField(); + jTableDataPanel = new javax.swing.JPanel(); + jScrollPane1 = new javax.swing.JScrollPane(); + jTable1 = new javax.swing.JTable(); + + tablesDropdownList.setModel(new javax.swing.DefaultComboBoxModel<>(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" })); + tablesDropdownList.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + tablesDropdownListActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(SQLiteViewer.class, "SQLiteViewer.jLabel1.text")); // NOI18N + + numEntriesField.setEditable(false); + numEntriesField.setText(org.openide.util.NbBundle.getMessage(SQLiteViewer.class, "SQLiteViewer.numEntriesField.text")); // NOI18N + numEntriesField.setBorder(null); + numEntriesField.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + numEntriesFieldActionPerformed(evt); + } + }); + + javax.swing.GroupLayout jHdrPanelLayout = new javax.swing.GroupLayout(jHdrPanel); + jHdrPanel.setLayout(jHdrPanelLayout); + jHdrPanelLayout.setHorizontalGroup( + jHdrPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jHdrPanelLayout.createSequentialGroup() + .addContainerGap() + .addComponent(jLabel1) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(tablesDropdownList, javax.swing.GroupLayout.PREFERRED_SIZE, 130, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(23, 23, 23) + .addComponent(numEntriesField, javax.swing.GroupLayout.PREFERRED_SIZE, 71, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap(130, Short.MAX_VALUE)) + ); + jHdrPanelLayout.setVerticalGroup( + jHdrPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jHdrPanelLayout.createSequentialGroup() + .addContainerGap() + .addGroup(jHdrPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(tablesDropdownList, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(jLabel1) + .addComponent(numEntriesField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addContainerGap(16, Short.MAX_VALUE)) + ); + + jTable1.setModel(new javax.swing.table.DefaultTableModel( + new Object [][] { + {null, null, null, null}, + {null, null, null, null}, + {null, null, null, null}, + {null, null, null, null} + }, + new String [] { + "Title 1", "Title 2", "Title 3", "Title 4" + } + )); + jScrollPane1.setViewportView(jTable1); + + javax.swing.GroupLayout jTableDataPanelLayout = new javax.swing.GroupLayout(jTableDataPanel); + jTableDataPanel.setLayout(jTableDataPanelLayout); + jTableDataPanelLayout.setHorizontalGroup( + jTableDataPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jTableDataPanelLayout.createSequentialGroup() + .addContainerGap() + .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) + .addGap(15, 15, 15)) + ); + jTableDataPanelLayout.setVerticalGroup( + jTableDataPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jTableDataPanelLayout.createSequentialGroup() + .addContainerGap() + .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 275, Short.MAX_VALUE) + .addContainerGap()) + ); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jHdrPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jTableDataPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(jHdrPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(jTableDataPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + }// //GEN-END:initComponents + + private void numEntriesFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_numEntriesFieldActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_numEntriesFieldActionPerformed + + private void tablesDropdownListActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tablesDropdownListActionPerformed + JComboBox cb = (JComboBox) evt.getSource(); + String tableName = (String) cb.getSelectedItem(); + if (null == tableName) { + return; + } + + readTable(tableName); + }//GEN-LAST:event_tablesDropdownListActionPerformed + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JPanel jHdrPanel; + private javax.swing.JLabel jLabel1; + private javax.swing.JScrollPane jScrollPane1; + private javax.swing.JTable jTable1; + private javax.swing.JPanel jTableDataPanel; + private javax.swing.JTextField numEntriesField; + private javax.swing.JComboBox tablesDropdownList; + // End of variables declaration//GEN-END:variables + + @Override + public List getSupportedMIMETypes() { + return Arrays.asList(SUPPORTED_MIMETYPES); + } + + @Override + public void setFile(AbstractFile file) { + processSQLiteFile(file); + } + + @Override + public Component getComponent() { + return this; + } + + @Override + public void resetComponent() { + + dbTablesMap.clear(); + + tablesDropdownList.setEnabled(true); + tablesDropdownList.removeAllItems(); + numEntriesField.setText(""); + + // close DB connection to file + if (null != connection) { + try { + connection.close(); + connection = null; + } catch (SQLException ex) { + LOGGER.log(Level.SEVERE, "Failed to close DB connection to file.", ex); //NON-NLS + } + } + + // delete last temp file + if (null != tmpDBFile) { + tmpDBFile.delete(); + tmpDBFile = null; + } + } + + private void customizeComponents() { + + // add a actionListener to jTablesComboBox + } + + /** + * Process the given SQLite DB file + * + * @param sqliteFile - + * + * @return none + */ + private void processSQLiteFile(AbstractFile sqliteFile) { + + tablesDropdownList.removeAllItems(); + + new SwingWorker() { + @Override + protected Boolean doInBackground() throws Exception { + + try { + // Copy the file to temp folder + tmpDBPathName = Case.getCurrentCase().getTempDirectory() + File.separator + sqliteFile.getName() + "-" + sqliteFile.getId(); + tmpDBFile = new File(tmpDBPathName); + ContentUtils.writeToFile(sqliteFile, tmpDBFile); + + // Open copy using JDBC + Class.forName("org.sqlite.JDBC"); //NON-NLS //load JDBC driver + connection = DriverManager.getConnection("jdbc:sqlite:" + tmpDBPathName); //NON-NLS + + // Read all table names and schema + return getTables(); + } catch (IOException ex) { + LOGGER.log(Level.SEVERE, "Failed to copy DB file.", ex); //NON-NLS + } catch (SQLException ex) { + LOGGER.log(Level.SEVERE, "Failed to Open DB.", ex); //NON-NLS + } catch (ClassNotFoundException ex) { + LOGGER.log(Level.SEVERE, "Failed to initialize JDBC Sqlite.", ex); //NON-NLS + } + return false; + } + + @Override + protected void done() { + super.done(); + try { + boolean status = get(); + if ((status == true) && (dbTablesMap.size() > 0)) { + dbTablesMap.keySet().forEach((tableName) -> { + tablesDropdownList.addItem(tableName); + }); + } else { + // Populate error message + tablesDropdownList.addItem("No tables found"); + tablesDropdownList.setEnabled(false); + } + } catch (InterruptedException | ExecutionException ex) { + LOGGER.log(Level.SEVERE, "Unexpected exception while opening DB file", ex); //NON-NLS + } + } + }.execute(); + + } + + /** + * Gets the table names and their schema from loaded SQLite db file + * + * @return true if success, false otherwise + */ + private boolean getTables() { + + try { + Statement statement = connection.createStatement(); + + ResultSet resultSet = statement.executeQuery( + "SELECT name, sql FROM sqlite_master " + + " WHERE type= 'table' " + + " ORDER BY name;"); //NON-NLS + + while (resultSet.next()) { + String tableName = resultSet.getString("name"); //NON-NLS + String tableSQL = resultSet.getString("sql"); //NON-NLS + + dbTablesMap.put(tableName, tableSQL); + String query = "PRAGMA table_info(" + tableName + ")"; //NON-NLS + ResultSet rs2; + try { + Statement statement2 = connection.createStatement(); + rs2 = statement2.executeQuery(query); + while (rs2.next()) { + + // System.out.println("RAMAN: Col Name = " + rs2.getString("name")); + // System.out.println("RAMAN: Col Type = " + rs2.getString("type")); + + // RAMAN TBD: parse and save the table schema + } + } catch (Exception ex) { + LOGGER.log(Level.WARNING, "Error while trying to get columns from sqlite db." + connection, ex); //NON-NLS + } + } + } catch (Exception e) { + LOGGER.log(Level.SEVERE, "Error getting table names from the DB", e); //NON-NLS + } + return true; + } + + private void readTable(String tableName) { + // TBD: need to handle cancelling if one is already in progress + + new SwingWorker() { + @Override + protected Integer doInBackground() throws Exception { + + try { + Statement statement = connection.createStatement(); + ResultSet resultSet = statement.executeQuery( + "SELECT COUNT(*) as count FROM " + tableName); //NON-NLS + + // TBD: read the rows here and popluate the ExplorerManager. + + return resultSet.getInt("count"); + } catch (SQLException ex) { + LOGGER.log(Level.SEVERE, "Failed to get data for table.", ex); //NON-NLS + } + //NON-NLS + return 0; + } + + @Override + protected void done() { + super.done(); + try { + int numRows = get(); + numEntriesField.setText(numRows + " entries"); + } catch (InterruptedException | ExecutionException ex) { + LOGGER.log(Level.SEVERE, "Unexpected exception while reading table.", ex); //NON-NLS + } + } + }.execute(); + + } + + enum SQLStorageClass { + NULL, + INTEGER, + REAL, + TEXT, + BLOB + }; + + private class SQLColDef { + + private final String colName; + private final SQLStorageClass storageClass; + + SQLColDef(String colName, SQLStorageClass sc) { + this.colName = colName; + this.storageClass = sc; + } + + } +} diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java index e6e8afed52..2713992139 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java @@ -41,7 +41,7 @@ public interface DisplayableItemNodeVisitor { T visit(LocalFileNode dfn); T visit(VirtualDirectoryNode ldn); - + T visit(LocalDirectoryNode ldn); T visit(DirectoryNode dn); diff --git a/Core/src/org/sleuthkit/autopsy/datasourceprocessors/AddRawImageTask.java b/Core/src/org/sleuthkit/autopsy/datasourceprocessors/AddRawImageTask.java index 14a3dc9e2f..3d576eebf0 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourceprocessors/AddRawImageTask.java +++ b/Core/src/org/sleuthkit/autopsy/datasourceprocessors/AddRawImageTask.java @@ -178,7 +178,7 @@ final class AddRawImageTask implements Runnable { logger.log(Level.SEVERE, errorMessage, ex); criticalErrorOccurred = true; } finally { - caseDatabase.releaseSingleUserCaseReadLock(); + caseDatabase.releaseSingleUserCaseWriteLock(); } } diff --git a/Core/src/org/sleuthkit/autopsy/livetriage/Bundle.properties b/Core/src/org/sleuthkit/autopsy/livetriage/Bundle.properties new file mode 100644 index 0000000000..61f522a6b4 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/livetriage/Bundle.properties @@ -0,0 +1,7 @@ +SelectDriveDialog.bnOk.text=Ok +SelectDriveDialog.bnRefresh.text=Refresh +SelectDriveDialog.lbSelectDrive.text=Select the drive to copy the application and script to: +SelectDriveDialog.jLabel1.text=Select drive to use for live triage (may take time to load): +SelectDriveDialog.errorLabel.text=jLabel2 +SelectDriveDialog.bnCancel.text=Cancel +SelectDriveDialog.jTextArea1.text=This feature copies the application and a batch file to a removable drive,\nallowing systems to be analyzed without installing the software or\nimaging the drives.\n\nTo analyze a system, insert the drive and run "RunFromUSB.bat" as\nadministrator, then select the "Local Disk" option on the Add Data Source\npanel. diff --git a/Core/src/org/sleuthkit/autopsy/livetriage/CreateLiveTriageDriveAction.java b/Core/src/org/sleuthkit/autopsy/livetriage/CreateLiveTriageDriveAction.java new file mode 100644 index 0000000000..846632a092 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/livetriage/CreateLiveTriageDriveAction.java @@ -0,0 +1,284 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2018 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.livetriage; + +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.InvalidPathException; +import java.util.logging.Level; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeEvent; +import javax.swing.JOptionPane; +import java.awt.Frame; +import javax.swing.SwingWorker; +import org.apache.commons.io.FileUtils; +import org.openide.awt.ActionID; +import org.openide.awt.ActionReference; +import org.openide.awt.ActionRegistration; +import org.openide.util.HelpCtx; +import org.openide.util.NbBundle; +import org.openide.util.actions.CallableSystemAction; +import org.openide.windows.WindowManager; +import org.sleuthkit.autopsy.core.UserPreferences; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; +import org.sleuthkit.autopsy.coreutils.PlatformUtil; +import org.sleuthkit.autopsy.progress.ModalDialogProgressIndicator; + +@ActionID(category = "Tools", id = "org.sleuthkit.autopsy.livetriage.CreateLiveTriageDriveAction") +@ActionReference(path = "Menu/Tools", position = 1401) +@ActionRegistration(displayName = "#CTL_CreateLiveTriageDriveAction", lazy = false) +@NbBundle.Messages({"CTL_CreateLiveTriageDriveAction=Make Live Triage Drive"}) +public final class CreateLiveTriageDriveAction extends CallableSystemAction implements PropertyChangeListener { + + private static final String DISPLAY_NAME = Bundle.CTL_CreateLiveTriageDriveAction(); + private ModalDialogProgressIndicator progressIndicator = null; + private String drivePath = ""; + private CopyFilesWorker worker; + + @Override + public boolean isEnabled() { + return true; + } + + @NbBundle.Messages({"CreateLiveTriageDriveAction.error.title=Error creating live triage disk", + "CreateLiveTriageDriveAction.exenotfound.message=Executable could not be found", + "CreateLiveTriageDriveAction.batchFileError.message=Error creating batch file", + "CreateLiveTriageDriveAction.appPathError.message=Could not location application directory", + "CreateLiveTriageDriveAction.copyError.message=Could not copy application. Only works on installed version.", + "CreateLiveTriageDriveAction.success.title=Success", + "CreateLiveTriageDriveAction.success.message=Live triage drive created. Use RunFromUSB.bat to run the application" + }) + @Override + @SuppressWarnings("fallthrough") + public void performAction() { + + Frame mainWindow = WindowManager.getDefault().getMainWindow(); + + // If this is an installed version, there should be an 64.exe file in the bin folder + String appName = UserPreferences.getAppName(); + String exeName = appName + "64.exe"; + String installPath = PlatformUtil.getInstallPath(); + + Path exePath = Paths.get(installPath, "bin", exeName); + + if (!exePath.toFile().exists()) { + JOptionPane.showMessageDialog(mainWindow, + Bundle.CreateLiveTriageDriveAction_exenotfound_message(), + Bundle.CreateLiveTriageDriveAction_error_title(), + JOptionPane.ERROR_MESSAGE); + return; + } + + Path applicationBasePath; + try { + applicationBasePath = exePath.getParent().getParent(); + } catch (InvalidPathException ex) { + JOptionPane.showMessageDialog(mainWindow, + Bundle.CreateLiveTriageDriveAction_appPathError_message(), + Bundle.CreateLiveTriageDriveAction_error_title(), + JOptionPane.ERROR_MESSAGE); + return; + } + + SelectDriveDialog driveDialog = new SelectDriveDialog(mainWindow, true); + driveDialog.display(); + + if (!driveDialog.getSelectedDrive().isEmpty()) { + drivePath = driveDialog.getSelectedDrive(); + if (drivePath.startsWith("\\\\.\\")) { + drivePath = drivePath.substring(4); + } + + worker = new CopyFilesWorker(applicationBasePath, drivePath, appName); + worker.addPropertyChangeListener(this); + worker.execute(); + } + } + + @NbBundle.Messages({"# {0} - drivePath", + "CreateLiveTriageDriveAction.progressBar.text=Copying live triage files to {0}", + "CreateLiveTriageDriveAction.progressBar.title=Please wait"}) + @Override + public void propertyChange(PropertyChangeEvent evt) { + + if ("state".equals(evt.getPropertyName()) + && (SwingWorker.StateValue.STARTED.equals(evt.getNewValue()))) { + + // Setup progress bar. + String displayStr = NbBundle.getMessage(this.getClass(), "CreateLiveTriageDriveAction.progressBar.text", + drivePath); + + progressIndicator = new ModalDialogProgressIndicator(WindowManager.getDefault().getMainWindow(), + NbBundle.getMessage(this.getClass(), "CreateLiveTriageDriveAction.progressBar.title")); + progressIndicator.start(displayStr); + + } else if ("state".equals(evt.getPropertyName()) + && (SwingWorker.StateValue.DONE.equals(evt.getNewValue()))) { + if (progressIndicator != null) { + progressIndicator.finish(); + } + + if (worker.hadError()) { + MessageNotifyUtil.Message.error(NbBundle.getMessage(CopyFilesWorker.class, "CopyFilesWorker.error.text")); + } else { + MessageNotifyUtil.Message.info(NbBundle.getMessage(CopyFilesWorker.class, "CopyFilesWorker.done.text")); + } + } + } + + private class CopyFilesWorker extends SwingWorker { + + private final Path sourceFolder; + private final String drivePath; + private final String appName; + private boolean error = false; + + CopyFilesWorker(Path sourceFolder, String drivePath, String appName) { + this.sourceFolder = sourceFolder; + this.drivePath = drivePath; + this.appName = appName; + } + + boolean hadError() { + return error; + } + + @Override + protected Void doInBackground() throws Exception { + + copyBatchFile(drivePath, appName); + copyApplication(sourceFolder, drivePath, appName); + + return null; + } + + @NbBundle.Messages({"CopyFilesWorker.error.text=Error copying live triage files", + "CopyFilesWorker.done.text=Finished creating live triage disk"}) + @Override + protected void done() { + try { + super.get(); + } catch (Exception ex) { + error = true; + Logger.getLogger(CreateLiveTriageDriveAction.class.getName()).log(Level.SEVERE, "Fatal error during live triage drive creation", ex); //NON-NLS + } + } + } + + private void copyApplication(Path sourceFolder, String destBaseFolder, String appName) throws IOException { + + // Create an appName folder in the destination + Path destAppFolder = Paths.get(destBaseFolder, appName); + if (!destAppFolder.toFile().exists()) { + if (!destAppFolder.toFile().mkdirs()) { + throw new IOException("Failed to create directory " + destAppFolder.toString()); + } + } + + // Now copy the files + FileUtils.copyDirectory(sourceFolder.toFile(), destAppFolder.toFile()); + } + + private void copyBatchFile(String destPath, String appName) throws IOException, InvalidPathException { + Path batchFilePath = Paths.get(destPath, "RunFromUSB.bat"); + FileUtils.writeStringToFile(batchFilePath.toFile(), getBatchFileContents(appName), "UTF-8"); + + } + + private String getBatchFileContents(String appName) { + + String batchFile + = "@echo off\n" + + "\n" + + "REM This restores the working directory when using 'Run as administrator'" + + "@setlocal enableextensions\n" + + "@cd /d \"%~dp0\"" + + "\n" + + "SET appName=\"" + appName + "\"\n" + + "\n" + + "REM Create the configData directory. Exit if it does not exist after attempting to create it\n" + + "if not exist configData mkdir configData\n" + + "if not exist configData (\n" + + " echo Error creating directory configData\n" + + " goto end\n" + + ")\n" + + "\n" + + "REM Create the userdir sub directory. Exit if it does not exist after attempting to create it\n" + + "if not exist configData\\userdir mkdir configData\\userdir\n" + + "if not exist configData\\userdir (\n" + + " echo Error creating directory configData\\userdir\n" + + " goto end\n" + + ")\n" + + "\n" + + "REM Create the cachedir sub directory. Exit if it does not exist after attempting to create it\n" + + "REM If it exists to start with, delete it to clear out old data\n" + + "if exist configData\\cachedir rd /s /q configData\\cachedir\n" + + "mkdir configData\\cachedir\n" + + "if not exist configData\\cachedir (\n" + + " echo Error creating directory configData\\cachedir\n" + + " goto end\n" + + ")\n" + + "\n" + + "REM Create the temp sub directory. Exit if it does not exist after attempting to create it\n" + + "REM If it exists to start with, delete it to clear out old data\n" + + "if exist configData\\temp rd /s /q configData\\temp\n" + + "mkdir configData\\temp\n" + + "if not exist configData\\temp (\n" + + " echo Error creating directory configData\\temp\n" + + " goto end\n" + + ")\n" + + "\n" + + "REM Create the cases directory. It's ok if this fails.\n" + + "if not exist cases mkdir cases\n" + + "\n" + + "if exist %appName% (\n" + + " if not exist %appName%\\bin\\%appName%64.exe (\n" + + " echo %appName%\\bin\\%appName%64.exe does not exist\n" + + " goto end\n" + + " )\n" + + " %appName%\\bin\\%appName%64.exe --userdir ..\\configData\\userdir --cachedir ..\\configData\\cachedir -J-Djava.io.tmpdir=..\\configData\\temp\n" + + ") else (\n" + + " echo Could not find %appName% directory\n" + + " goto end\n" + + ")\n" + + "\n" + + ":end\n" + + "\n" + + "REM Keep the cmd window open in case there was an error\n" + + "@pause\n"; + return batchFile; + } + + @Override + public String getName() { + return DISPLAY_NAME; + } + + @Override + public HelpCtx getHelpCtx() { + return HelpCtx.DEFAULT_HELP; + } + + @Override + public boolean asynchronous() { + return false; // run on edt + } +} diff --git a/Core/src/org/sleuthkit/autopsy/livetriage/SelectDriveDialog.form b/Core/src/org/sleuthkit/autopsy/livetriage/SelectDriveDialog.form new file mode 100644 index 0000000000..ee776348dc --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/livetriage/SelectDriveDialog.form @@ -0,0 +1,163 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/livetriage/SelectDriveDialog.java b/Core/src/org/sleuthkit/autopsy/livetriage/SelectDriveDialog.java new file mode 100644 index 0000000000..c13d82d324 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/livetriage/SelectDriveDialog.java @@ -0,0 +1,388 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.livetriage; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CancellationException; +import java.util.logging.Level; +import java.awt.Dimension; +import java.awt.Point; +import javax.swing.SwingWorker; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import javax.swing.event.TableModelListener; +import javax.swing.table.TableModel; +import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.coreutils.LocalDisk; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.coreutils.PlatformUtil; + +/** + * + */ +class SelectDriveDialog extends javax.swing.JDialog { + + private List disks = new ArrayList<>(); + private final LocalDiskModel model = new LocalDiskModel(); + private final java.awt.Frame parent; + private String drivePath = ""; + + /** + * Creates new form SelectDriveDialog + */ + @NbBundle.Messages({"SelectDriveDialog.title=Create Live Triage Drive"}) + SelectDriveDialog(java.awt.Frame parent, boolean modal) { + super(parent, modal); + initComponents(); + this.parent = parent; + + model.loadDisks(); + bnOk.setEnabled(false); + diskTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { + @Override + public void valueChanged(ListSelectionEvent e) { + if (diskTable.getSelectedRow() >= 0 && diskTable.getSelectedRow() < disks.size()) { + bnOk.setEnabled(true); + } else { //The selection changed to nothing valid being selected, such as with ctrl+click + bnOk.setEnabled(false); + } + } + }); + } + + void display() { + this.setTitle(Bundle.SelectDriveDialog_title()); + + final Dimension parentSize = parent.getSize(); + final Point parentLocationOnScreen = parent.getLocationOnScreen(); + final Dimension childSize = this.getSize(); + int x; + int y; + x = (parentSize.width - childSize.width) / 2; + y = (parentSize.height - childSize.height) / 2; + x += parentLocationOnScreen.x; + y += parentLocationOnScreen.y; + + setLocation(x, y); + setVisible(true); + } + + String getSelectedDrive() { + return this.drivePath; + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + jScrollPane1 = new javax.swing.JScrollPane(); + diskTable = new javax.swing.JTable(); + jLabel1 = new javax.swing.JLabel(); + bnRefresh = new javax.swing.JButton(); + bnOk = new javax.swing.JButton(); + errorLabel = new javax.swing.JLabel(); + jSeparator1 = new javax.swing.JSeparator(); + bnCancel = new javax.swing.JButton(); + jScrollPane2 = new javax.swing.JScrollPane(); + jTextArea1 = new javax.swing.JTextArea(); + + setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); + + diskTable.setModel(model); + jScrollPane1.setViewportView(diskTable); + + org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(SelectDriveDialog.class, "SelectDriveDialog.jLabel1.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(bnRefresh, org.openide.util.NbBundle.getMessage(SelectDriveDialog.class, "SelectDriveDialog.bnRefresh.text")); // NOI18N + bnRefresh.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + bnRefreshActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(bnOk, org.openide.util.NbBundle.getMessage(SelectDriveDialog.class, "SelectDriveDialog.bnOk.text")); // NOI18N + bnOk.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + bnOkActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(errorLabel, org.openide.util.NbBundle.getMessage(SelectDriveDialog.class, "SelectDriveDialog.errorLabel.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(bnCancel, org.openide.util.NbBundle.getMessage(SelectDriveDialog.class, "SelectDriveDialog.bnCancel.text")); // NOI18N + bnCancel.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + bnCancelActionPerformed(evt); + } + }); + + jScrollPane2.setBorder(null); + + jTextArea1.setBackground(new java.awt.Color(240, 240, 240)); + jTextArea1.setColumns(20); + jTextArea1.setFont(new java.awt.Font("Tahoma", 0, 11)); // NOI18N + jTextArea1.setRows(5); + jTextArea1.setText(org.openide.util.NbBundle.getMessage(SelectDriveDialog.class, "SelectDriveDialog.jTextArea1.text")); // NOI18N + jTextArea1.setBorder(null); + jScrollPane2.setViewportView(jTextArea1); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addGroup(layout.createSequentialGroup() + .addComponent(bnRefresh, javax.swing.GroupLayout.DEFAULT_SIZE, 112, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 48, Short.MAX_VALUE) + .addComponent(bnOk, javax.swing.GroupLayout.PREFERRED_SIZE, 101, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(bnCancel, javax.swing.GroupLayout.PREFERRED_SIZE, 101, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) + .addComponent(jLabel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jSeparator1) + .addComponent(errorLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jScrollPane2)) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 107, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabel1) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 112, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(bnRefresh) + .addComponent(bnCancel) + .addComponent(bnOk)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(errorLabel) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + + pack(); + }// //GEN-END:initComponents + + private void bnRefreshActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnRefreshActionPerformed + model.loadDisks(); + }//GEN-LAST:event_bnRefreshActionPerformed + + private void bnOkActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnOkActionPerformed + if (diskTable.getSelectedRow() >= 0 && diskTable.getSelectedRow() < disks.size()) { + LocalDisk selectedDisk = disks.get(diskTable.getSelectedRow()); + drivePath = selectedDisk.getPath(); + } else { + drivePath = ""; + } + dispose(); + }//GEN-LAST:event_bnOkActionPerformed + + private void bnCancelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnCancelActionPerformed + dispose(); + }//GEN-LAST:event_bnCancelActionPerformed + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton bnCancel; + private javax.swing.JButton bnOk; + private javax.swing.JButton bnRefresh; + private javax.swing.JTable diskTable; + private javax.swing.JLabel errorLabel; + private javax.swing.JLabel jLabel1; + private javax.swing.JScrollPane jScrollPane1; + private javax.swing.JScrollPane jScrollPane2; + private javax.swing.JSeparator jSeparator1; + private javax.swing.JTextArea jTextArea1; + // End of variables declaration//GEN-END:variables + + /** + * Table model for displaying information from LocalDisk Objects in a table. + */ + @NbBundle.Messages({"SelectDriveDialog.localDiskModel.loading.msg=", + "SelectDriveDialog.localDiskModel.nodrives.msg=Executable could not be found", + "SelectDriveDialog.diskTable.column1.title=Disk Name", + "SelectDriveDialog.diskTable.column2.title=Disk Size", + "SelectDriveDialog.errLabel.disksNotDetected.text=Disks were not detected. On some systems it requires admin privileges", + "SelectDriveDialog.errLabel.disksNotDetected.toolTipText=Disks were not detected." + + }) + private class LocalDiskModel implements TableModel { + + private LocalDiskThread worker = null; + private boolean ready = false; + private volatile boolean loadingDisks = false; + + //private String SELECT = "Select a local disk:"; + private final String LOADING = NbBundle.getMessage(this.getClass(), "SelectDriveDialog.localDiskModel.loading.msg"); + private final String NO_DRIVES = NbBundle.getMessage(this.getClass(), "SelectDriveDialog.localDiskModel.nodrives.msg"); + + private void loadDisks() { + + // if there is a worker already building the lists, then cancel it first. + if (loadingDisks && worker != null) { + worker.cancel(false); + } + + // Clear the lists + errorLabel.setText(""); + diskTable.setEnabled(false); + ready = false; + loadingDisks = true; + worker = new LocalDiskThread(); + worker.execute(); + } + + @Override + public int getRowCount() { + if (disks.isEmpty()) { + return 0; + } + return disks.size(); + } + + @Override + public int getColumnCount() { + return 2; + + } + + @Override + public String getColumnName(int columnIndex) { + switch (columnIndex) { + case 0: + return NbBundle.getMessage(this.getClass(), "SelectDriveDialog.diskTable.column1.title"); + case 1: + return NbBundle.getMessage(this.getClass(), "SelectDriveDialog.diskTable.column2.title"); + default: + return "Unnamed"; //NON-NLS + } + } + + @Override + public Class getColumnClass(int columnIndex) { + return String.class; + } + + @Override + public boolean isCellEditable(int rowIndex, int columnIndex) { + return false; + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + if (ready) { + if (disks.isEmpty()) { + return NO_DRIVES; + } + switch (columnIndex) { + case 0: + return disks.get(rowIndex).getName(); + case 1: + return disks.get(rowIndex).getReadableSize(); + default: + return disks.get(rowIndex).getPath(); + } + } else { + return LOADING; + } + } + + @Override + public void setValueAt(Object aValue, int rowIndex, int columnIndex) { + //setter does nothing they should not be able to modify table + } + + @Override + public void addTableModelListener(TableModelListener l) { + + } + + @Override + public void removeTableModelListener(TableModelListener l) { + + } + + /** + * Gets the lists of physical drives and partitions and combines them + * into a list of disks. + */ + class LocalDiskThread extends SwingWorker { + + private final Logger logger = Logger.getLogger(LocalDiskThread.class.getName()); + private List partitions = new ArrayList<>(); + + @Override + protected Object doInBackground() throws Exception { + // Populate the lists + partitions = new ArrayList<>(); + partitions = PlatformUtil.getPartitions(); + return null; + } + + /** + * Display any error messages that might of occurred when getting + * the lists of physical drives or partitions. + */ + private void displayErrors() { + if (partitions.isEmpty()) { + if (PlatformUtil.isWindowsOS()) { + errorLabel.setText( + NbBundle.getMessage(this.getClass(), "SelectDriveDialog.errLabel.disksNotDetected.text")); + errorLabel.setToolTipText(NbBundle.getMessage(this.getClass(), + "SelectDriveDialog.errLabel.disksNotDetected.toolTipText")); + } else { + errorLabel.setText( + NbBundle.getMessage(this.getClass(), "SelectDriveDialog.errLabel.drivesNotDetected.text")); + errorLabel.setToolTipText(NbBundle.getMessage(this.getClass(), + "SelectDriveDialog.errLabel.drivesNotDetected.toolTipText")); + } + errorLabel.setVisible(true); + diskTable.setEnabled(false); + } + } + + @Override + protected void done() { + try { + super.get(); //block and get all exceptions thrown while doInBackground() + } catch (CancellationException ex) { + logger.log(Level.INFO, "Loading local disks was canceled."); //NON-NLS + } catch (InterruptedException ex) { + logger.log(Level.INFO, "Loading local disks was interrupted."); //NON-NLS + } catch (Exception ex) { + logger.log(Level.SEVERE, "Fatal error when loading local disks", ex); //NON-NLS + } finally { + if (!this.isCancelled()) { + displayErrors(); + worker = null; + loadingDisks = false; + disks = new ArrayList<>(); + disks.addAll(partitions); + if (disks.size() > 0) { + diskTable.setEnabled(true); + diskTable.clearSelection(); + } + ready = true; + } + } + diskTable.revalidate(); + } + } + } +} diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/MSOfficeEmbeddedContentExtractor.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/MSOfficeEmbeddedContentExtractor.java index 4a3a20da07..7fca6a896c 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/MSOfficeEmbeddedContentExtractor.java +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/MSOfficeEmbeddedContentExtractor.java @@ -51,6 +51,7 @@ import org.apache.tika.mime.MimeTypeException; import org.apache.tika.parser.AutoDetectParser; import org.apache.tika.parser.ParseContext; import org.apache.tika.parser.Parser; +import org.apache.tika.parser.microsoft.OfficeParserConfig; import org.apache.tika.sax.BodyContentHandler; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; @@ -231,11 +232,13 @@ class MSOfficeEmbeddedContentExtractor { // write limit (which defaults to 100,000 characters. ContentHandler contentHandler = new BodyContentHandler(-1); - // TODO: this will be needed once we upgrade to Tika 1.16 or later. - // OfficeParserConfig officeParserConfig = new OfficeParserConfig(); - // officeParserConfig.setUseSAXPptxExtractor(true); - // officeParserConfig.setUseSAXDocxExtractor(true); - // parseContext.set(OfficeParserConfig.class, officeParserConfig); + // Use the more memory efficient Tika SAX parsers for DOCX and + // PPTX files (it already uses SAX for XLSX). + OfficeParserConfig officeParserConfig = new OfficeParserConfig(); + officeParserConfig.setUseSAXPptxExtractor(true); + officeParserConfig.setUseSAXDocxExtractor(true); + parseContext.set(OfficeParserConfig.class, officeParserConfig); + EmbeddedDocumentExtractor extractor = new EmbeddedContentExtractor(parseContext); parseContext.set(EmbeddedDocumentExtractor.class, extractor); ReadContentInputStream stream = new ReadContentInputStream(abstractFile); diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeDetector.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeDetector.java index c742110f6b..aaa6dbec11 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeDetector.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeDetector.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2017 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -177,6 +177,8 @@ public class FileTypeDetector { * * @return A MIME type name. If file type could not be detected, or results * were uncertain, octet-stream is returned. + * + */ public String detectMIMEType(AbstractFile file) { /* diff --git a/Core/src/org/sleuthkit/autopsy/modules/stix/STIXReportModule.java b/Core/src/org/sleuthkit/autopsy/modules/stix/STIXReportModule.java index 899de3630c..9d08bf7115 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/stix/STIXReportModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/stix/STIXReportModule.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013 Basis Technology Corp. + * Copyright 2013 - 2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -29,7 +29,7 @@ import java.util.Map; import java.util.logging.Level; import javax.swing.JPanel; import javax.xml.bind.JAXBContext; -import javax.xml.bind.JAXBException; +import javax.xml.bind.JAXBException; import javax.xml.bind.Unmarshaller; import javax.xml.namespace.QName; import org.mitre.cybox.cybox_2.ObjectType; @@ -100,7 +100,7 @@ public class STIXReportModule implements GeneralReportModule { // Start the progress bar and setup the report progressPanel.setIndeterminate(false); progressPanel.start(); - progressPanel.updateStatusLabel(NbBundle.getMessage(this.getClass(), "STIXReportModule.progress.readSTIX")); + progressPanel.updateStatusLabel(NbBundle.getMessage(this.getClass(), "STIXReportModule.progress.readSTIX")); reportPath = baseReportDir + getRelativeFilePath(); File reportFile = new File(reportPath); // Check if the user wants to display all output or just hits diff --git a/Core/src/org/sleuthkit/autopsy/report/Bundle.properties b/Core/src/org/sleuthkit/autopsy/report/Bundle.properties index 09c6fa8906..2da0862826 100644 --- a/Core/src/org/sleuthkit/autopsy/report/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/report/Bundle.properties @@ -47,13 +47,13 @@ ReportBodyFile.getDesc.text=Body file format report with MAC times for every fil ReportBodyFile.getFilePath.text=BodyFile.txt ReportKML.progress.querying=Querying files... ReportKML.progress.loading=Loading files... -ReportKML.getName.text=Google Earth/KML +ReportKML.getName.text=Google Earth KML ReportKML.getDesc.text=KML format report with coordinates for relevant files. This format can be used for google earth views. ReportKML.getFilePath.text=ReportKML.kml ReportBranding.defaultReportTitle.text=Autopsy Forensic Report ReportBranding.defaultReportFooter.text=Powered by Autopsy Open Source Digital Forensics Platform - www.sleuthkit.org ReportExcel.numAartifacts.text=Number of artifacts\: -ReportExcel.getName.text=Results - Excel +ReportExcel.getName.text=Excel Report ReportExcel.getDesc.text=A report about results and tagged items in Excel (XLS) format. ReportExcel.sheetName.text=Summary ReportExcel.cellVal.summary=Summary @@ -177,12 +177,12 @@ ReportGenerator.errors.reportErrorText=Error generating report: ReportHTML.addThumbRows.dataType.title=Tagged Images - {0} ReportHTML.addThumbRows.dataType.msg=Tagged Results and Contents that contain images. ReportHTML.thumbLink.tags=Tags\: -ReportHTML.getName.text=Results - HTML +ReportHTML.getName.text=HTML Report ReportHTML.getDesc.text=A report about results and tagged items in HTML format. ReportHTML.writeIndex.title=for case {0} ReportHTML.writeIndex.noFrames.msg=Your browser is not compatible with our frame setup. -ReportHTML.writeIndex.noFrames.seeNav=Please see the navigation page for artifact links, -ReportHTML.writeIndex.seeSum=and the summary page for a case summary. +ReportHTML.writeIndex.noFrames.seeNav=Please see the navigation page for artifact links, +ReportHTML.writeIndex.seeSum=and the summary page for a case summary. ReportHTML.writeNav.title=Report Navigation ReportHTML.writeNav.h1=Report Navigation ReportHTML.writeNav.summary=Case Summary @@ -190,7 +190,7 @@ ReportHTML.writeSum.title=Case Summary ReportHTML.writeSum.warningMsg=Warning, this report was run before ingest services completed\! # # autopsy/test/scripts/regression.py._html_report_diff() uses reportGenOn.text, caseName, caseNum, -# examiner as a regex signature to skip index.html and summary.html +# examiner as a regex signature to skip report.html and summary.html # ReportHTML.writeSum.reportGenOn.text=HTML Report Generated on {0} ReportHTML.writeSum.caseName=Case\: diff --git a/Core/src/org/sleuthkit/autopsy/report/FileReportText.java b/Core/src/org/sleuthkit/autopsy/report/FileReportText.java index 6b22e4a962..c9a239cf0a 100644 --- a/Core/src/org/sleuthkit/autopsy/report/FileReportText.java +++ b/Core/src/org/sleuthkit/autopsy/report/FileReportText.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013 Basis Technology Corp. + * Copyright 2013 - 2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportBodyFile.java b/Core/src/org/sleuthkit/autopsy/report/ReportBodyFile.java index c495ac2c72..33609f7333 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportBodyFile.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportBodyFile.java @@ -2,7 +2,7 @@ * * Autopsy Forensic Browser * - * Copyright 2012-2014 Basis Technology Corp. + * Copyright 2012-2018 Basis Technology Corp. * * Copyright 2012 42six Solutions. * Contact: aebadirad 42six com @@ -76,7 +76,7 @@ class ReportBodyFile implements GeneralReportModule { progressPanel.setIndeterminate(false); progressPanel.start(); progressPanel.updateStatusLabel(NbBundle.getMessage(this.getClass(), "ReportBodyFile.progress.querying")); - reportPath = baseReportDir + "BodyFile.txt"; //NON-NLS + reportPath = baseReportDir + getRelativeFilePath(); //NON-NLS currentCase = Case.getCurrentCase(); skCase = currentCase.getSleuthkitCase(); diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportExcel.java b/Core/src/org/sleuthkit/autopsy/report/ReportExcel.java index 56de46f04d..19526a0a19 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportExcel.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportExcel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013-2017 Basis Technology Corp. + * Copyright 2013-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -66,7 +66,7 @@ class ReportExcel implements TableReportModule { public void startReport(String baseReportDir) { // Set the path and save it for when the report is written to disk. this.reportPath = baseReportDir + getRelativeFilePath(); - + // Make a workbook. wb = new XSSFWorkbook(); diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java b/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java index afad0d5746..ef20238c48 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013 Basis Technology Corp. + * Copyright 2013 - 2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -63,7 +63,7 @@ class ReportGenerator { */ private ReportProgressPanel progressPanel; - private final String reportPath; + private static final String REPORT_PATH_FMT_STR = "%s" + File.separator + "%s %s %s" + File.separator; private final ReportGenerationPanel reportGenerationPanel = new ReportGenerationPanel(); static final String REPORTS_DIR = "Reports"; //NON-NLS @@ -89,23 +89,10 @@ class ReportGenerator { * Creates a report generator. */ ReportGenerator() { - // Create the root reports directory path of the form: /Reports/ / - DateFormat dateFormat = new SimpleDateFormat("MM-dd-yyyy-HH-mm-ss"); - Date date = new Date(); - String dateNoTime = dateFormat.format(date); - this.reportPath = currentCase.getReportDirectory() + File.separator + currentCase.getDisplayName() + " " + dateNoTime + File.separator; - this.errorList = new ArrayList<>(); - - // Create the root reports directory. - try { - FileUtil.createFolder(new File(this.reportPath)); - } catch (IOException ex) { - errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedMakeRptFolder")); - logger.log(Level.SEVERE, "Failed to make report folder, may be unable to generate reports.", ex); //NON-NLS - } } + /** * Display the progress panels to the user, and add actions to close the * parent dialog. @@ -143,11 +130,12 @@ class ReportGenerator { /** * Run the GeneralReportModules using a SwingWorker. */ - void generateGeneralReport(GeneralReportModule generalReportModule) { + void generateGeneralReport(GeneralReportModule generalReportModule) throws IOException { if (generalReportModule != null) { - setupProgressPanel(generalReportModule); + String reportDir = createReportDirectory(generalReportModule); + setupProgressPanel(generalReportModule, reportDir); ReportWorker worker = new ReportWorker(() -> { - generalReportModule.generateReport(reportPath, progressPanel); + generalReportModule.generateReport(reportDir, progressPanel); }); worker.execute(); displayProgressPanel(); @@ -162,11 +150,12 @@ class ReportGenerator { * @param tagSelections the enabled/disabled state of the tag names * to be included in the report */ - void generateTableReport(TableReportModule tableReport, Map artifactTypeSelections, Map tagNameSelections) { + void generateTableReport(TableReportModule tableReport, Map artifactTypeSelections, Map tagNameSelections) throws IOException { if (tableReport != null && null != artifactTypeSelections) { - setupProgressPanel(tableReport); + String reportDir = createReportDirectory(tableReport); + setupProgressPanel(tableReport, reportDir); ReportWorker worker = new ReportWorker(() -> { - tableReport.startReport(reportPath); + tableReport.startReport(reportDir); TableReportGenerator generator = new TableReportGenerator(artifactTypeSelections, tagNameSelections, progressPanel, tableReport); generator.execute(); tableReport.endReport(); @@ -185,15 +174,16 @@ class ReportGenerator { * @param enabledInfo the Information that should be included about each * file in the report. */ - void generateFileListReport(FileReportModule fileReportModule, Map enabledInfo) { + void generateFileListReport(FileReportModule fileReportModule, Map enabledInfo) throws IOException { if (fileReportModule != null && null != enabledInfo) { + String reportDir = createReportDirectory(fileReportModule); List enabled = new ArrayList<>(); for (Entry e : enabledInfo.entrySet()) { if (e.getValue()) { enabled.add(e.getKey()); } } - setupProgressPanel(fileReportModule); + setupProgressPanel(fileReportModule, reportDir); ReportWorker worker = new ReportWorker(() -> { if (progressPanel.getStatus() != ReportStatus.CANCELED) { progressPanel.start(); @@ -204,7 +194,7 @@ class ReportGenerator { List files = getFiles(); int numFiles = files.size(); if (progressPanel.getStatus() != ReportStatus.CANCELED) { - fileReportModule.startReport(reportPath); + fileReportModule.startReport(reportDir); fileReportModule.startTable(enabled); } progressPanel.setIndeterminate(false); @@ -259,15 +249,31 @@ class ReportGenerator { } } - private void setupProgressPanel(ReportModule module) { + private void setupProgressPanel(ReportModule module, String reportDir) { String reportFilePath = module.getRelativeFilePath(); if (!reportFilePath.isEmpty()) { - this.progressPanel = reportGenerationPanel.addReport(module.getName(), reportPath + reportFilePath); + this.progressPanel = reportGenerationPanel.addReport(module.getName(), reportDir + reportFilePath); } else { this.progressPanel = reportGenerationPanel.addReport(module.getName(), null); } } + private static String createReportDirectory(ReportModule module) throws IOException { + Case currentCase = Case.getCurrentCase(); + // Create the root reports directory path of the form: /Reports/ / + DateFormat dateFormat = new SimpleDateFormat("MM-dd-yyyy-HH-mm-ss"); + Date date = new Date(); + String dateNoTime = dateFormat.format(date); + String reportPath = String.format(REPORT_PATH_FMT_STR, currentCase.getReportDirectory(), currentCase.getDisplayName(), module.getName(), dateNoTime); + // Create the root reports directory. + try { + FileUtil.createFolder(new File(reportPath)); + } catch (IOException ex) { + throw new IOException("Failed to make report folder, unable to generate reports.", ex); + } + return reportPath; + } + private class ReportWorker extends SwingWorker { private final Runnable doInBackground; diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java index 834fb69710..88d9fe44b1 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java @@ -2,7 +2,7 @@ * * Autopsy Forensic Browser * - * Copyright 2012-2014 Basis Technology Corp. + * Copyright 2012-2018 Basis Technology Corp. * * Copyright 2012 42six Solutions. * Contact: aebadirad 42six com @@ -72,6 +72,7 @@ class ReportHTML implements TableReportModule { private static final String THUMBS_REL_PATH = "thumbs" + File.separator; //NON-NLS private static ReportHTML instance; private static final int MAX_THUMBS_PER_PAGE = 1000; + private static final String HTML_SUBDIR = "content"; private Case currentCase; private SleuthkitCase skCase; static Integer THUMBNAIL_COLUMNS = 5; @@ -79,6 +80,7 @@ class ReportHTML implements TableReportModule { private Map dataTypes; private String path; private String thumbsPath; + private String subPath; private String currentDataType; // name of current data type private Integer rowCount; // number of rows (aka artifacts or tags) for the current data type private Writer out; @@ -107,6 +109,7 @@ class ReportHTML implements TableReportModule { path = ""; thumbsPath = ""; + subPath = ""; currentDataType = ""; rowCount = 0; @@ -157,7 +160,7 @@ class ReportHTML implements TableReportModule { if (null != artifactType) { // set the icon file name iconFileName = dataTypeToFileName(artifactType.getDisplayName()) + ".png"; //NON-NLS - iconFilePath = path + File.separator + iconFileName; + iconFilePath = subPath + File.separator + iconFileName; // determine the source image to use switch (artifactType) { @@ -268,7 +271,7 @@ class ReportHTML implements TableReportModule { logger.log(Level.WARNING, "useDataTypeIcon: unhandled artifact type = " + dataType); //NON-NLS in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/star.png"); //NON-NLS iconFileName = "star.png"; //NON-NLS - iconFilePath = path + File.separator + iconFileName; + iconFilePath = subPath + File.separator + iconFileName; break; } } else if (dataType.startsWith(ARTIFACT_TYPE.TSK_ACCOUNT.getDisplayName())) { @@ -281,11 +284,11 @@ class ReportHTML implements TableReportModule { */ in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/accounts.png"); //NON-NLS iconFileName = "accounts.png"; //NON-NLS - iconFilePath = path + File.separator + iconFileName; + iconFilePath = subPath + File.separator + iconFileName; } else { // no defined artifact found for this dataType in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/star.png"); //NON-NLS iconFileName = "star.png"; //NON-NLS - iconFilePath = path + File.separator + iconFileName; + iconFilePath = subPath + File.separator + iconFileName; } try { @@ -325,10 +328,11 @@ class ReportHTML implements TableReportModule { // Refresh the HTML report refresh(); // Setup the path for the HTML report - this.path = baseReportDir + "HTML Report" + File.separator; //NON-NLS - this.thumbsPath = this.path + "thumbs" + File.separator; //NON-NLS + this.path = baseReportDir; //NON-NLS + this.subPath = this.path + HTML_SUBDIR + File.separator; + this.thumbsPath = this.subPath + THUMBS_REL_PATH; //NON-NLS try { - FileUtil.createFolder(new File(this.path)); + FileUtil.createFolder(new File(this.subPath)); FileUtil.createFolder(new File(this.thumbsPath)); } catch (IOException ex) { logger.log(Level.SEVERE, "Unable to make HTML report folder."); //NON-NLS @@ -367,7 +371,7 @@ class ReportHTML implements TableReportModule { public void startDataType(String name, String description) { String title = dataTypeToFileName(name); try { - out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(path + title + ".html"), "UTF-8")); //NON-NLS + out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(subPath + title + ".html"), "UTF-8")); //NON-NLS } catch (FileNotFoundException ex) { logger.log(Level.SEVERE, "File not found: {0}", ex); //NON-NLS } catch (UnsupportedEncodingException ex) { @@ -747,7 +751,7 @@ class ReportHTML implements TableReportModule { // Make a folder for the local file with the same tagName as the tag. StringBuilder localFilePath = new StringBuilder(); // full path - localFilePath.append(path); + localFilePath.append(subPath); localFilePath.append(dirName2); File localFileFolder = new File(localFilePath.toString()); if (!localFileFolder.exists()) { @@ -777,7 +781,7 @@ class ReportHTML implements TableReportModule { } // get the relative path - return localFilePath.toString().substring(path.length()); + return localFilePath.toString().substring(subPath.length()); } /** @@ -795,7 +799,7 @@ class ReportHTML implements TableReportModule { @Override public String getRelativeFilePath() { - return "HTML Report" + File.separator + "index.html"; //NON-NLS + return "report.html"; //NON-NLS } @Override @@ -814,7 +818,7 @@ class ReportHTML implements TableReportModule { private void writeCss() { Writer cssOut = null; try { - cssOut = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(path + "index.css"), "UTF-8")); //NON-NLS NON-NLS + cssOut = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(subPath + "index.css"), "UTF-8")); //NON-NLS NON-NLS String css = "body {margin: 0px; padding: 0px; background: #FFFFFF; font: 13px/20px Arial, Helvetica, sans-serif; color: #535353;}\n" + //NON-NLS "#content {padding: 30px;}\n" @@ -875,7 +879,7 @@ class ReportHTML implements TableReportModule { */ private void writeIndex() { Writer indexOut = null; - String indexFilePath = path + "index.html"; //NON-NLS + String indexFilePath = path + "report.html"; //NON-NLS try { indexOut = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(indexFilePath), "UTF-8")); //NON-NLS StringBuilder index = new StringBuilder(); @@ -883,7 +887,7 @@ class ReportHTML implements TableReportModule { String iconPath = reportBranding.getAgencyLogoPath(); if (iconPath == null) { // use default Autopsy icon if custom icon is not set - iconPath = "favicon.ico"; + iconPath = HTML_SUBDIR + "favicon.ico"; } else { iconPath = Paths.get(reportBranding.getAgencyLogoPath()).getFileName().toString(); //ref to writeNav() for agency_logo } @@ -895,8 +899,8 @@ class ReportHTML implements TableReportModule { index.append("\n"); //NON-NLS index.append("\n"); //NON-NLS index.append("\n"); //NON-NLS - index.append("\n"); //NON-NLS - index.append("\n"); //NON-NLS + index.append("\n"); //NON-NLS + index.append("\n"); //NON-NLS index.append("").append(NbBundle.getMessage(this.getClass(), "ReportHTML.writeIndex.noFrames.msg")).append("<br />\n"); //NON-NLS index.append(NbBundle.getMessage(this.getClass(), "ReportHTML.writeIndex.noFrames.seeNav")).append("<br />\n"); //NON-NLS index.append(NbBundle.getMessage(this.getClass(), "ReportHTML.writeIndex.seeSum")).append("\n"); //NON-NLS @@ -906,7 +910,7 @@ class ReportHTML implements TableReportModule { Case.getCurrentCase().addReport(indexFilePath, NbBundle.getMessage(this.getClass(), "ReportHTML.writeIndex.srcModuleName.text"), ""); } catch (IOException ex) { - logger.log(Level.SEVERE, "Error creating Writer for index.html: {0}", ex); //NON-NLS + logger.log(Level.SEVERE, "Error creating Writer for report.html: {0}", ex); //NON-NLS } catch (TskCoreException ex) { String errorMessage = String.format("Error adding %s to case as a report", indexFilePath); //NON-NLS logger.log(Level.SEVERE, errorMessage, ex); @@ -927,7 +931,7 @@ class ReportHTML implements TableReportModule { private void writeNav() { Writer navOut = null; try { - navOut = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(path + "nav.html"), "UTF-8")); //NON-NLS + navOut = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(subPath + "nav.html"), "UTF-8")); //NON-NLS StringBuilder nav = new StringBuilder(); nav.append("\n\n\t").append( //NON-NLS NbBundle.getMessage(this.getClass(), "ReportHTML.writeNav.title")) @@ -972,24 +976,24 @@ class ReportHTML implements TableReportModule { String generatorLogoPath = reportBranding.getGeneratorLogoPath(); if (generatorLogoPath != null && !generatorLogoPath.isEmpty()) { File from = new File(generatorLogoPath); - File to = new File(path); + File to = new File(subPath); FileUtil.copyFile(FileUtil.toFileObject(from), FileUtil.toFileObject(to), "generator_logo"); //NON-NLS } String agencyLogoPath = reportBranding.getAgencyLogoPath(); if (agencyLogoPath != null && !agencyLogoPath.isEmpty()) { - Path destinationPath = Paths.get(path); + Path destinationPath = Paths.get(subPath); Files.copy(Files.newInputStream(Paths.get(agencyLogoPath)), destinationPath.resolve(Paths.get(agencyLogoPath).getFileName())); //NON-NLS } in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/favicon.ico"); //NON-NLS - output = new FileOutputStream(new File(path + File.separator + "favicon.ico")); + output = new FileOutputStream(new File(subPath + "favicon.ico")); FileUtil.copy(in, output); in.close(); output.close(); in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/summary.png"); //NON-NLS - output = new FileOutputStream(new File(path + File.separator + "summary.png")); + output = new FileOutputStream(new File(subPath + "summary.png")); FileUtil.copy(in, output); in.close(); output.close(); @@ -1019,7 +1023,7 @@ class ReportHTML implements TableReportModule { private void writeSummary() { Writer out = null; try { - out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(path + "summary.html"), "UTF-8")); //NON-NLS + out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(subPath + "summary.html"), "UTF-8")); //NON-NLS StringBuilder head = new StringBuilder(); head.append("<html>\n<head>\n<title>").append( //NON-NLS NbBundle.getMessage(this.getClass(), "ReportHTML.writeSum.title")).append("\n"); //NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportKML.java b/Core/src/org/sleuthkit/autopsy/report/ReportKML.java index a24850c514..f089855e0c 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportKML.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportKML.java @@ -2,7 +2,7 @@ * * Autopsy Forensic Browser * - * Copyright 2014-2016 Basis Technology Corp. + * Copyright 2014-2018 Basis Technology Corp. * contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -104,6 +104,7 @@ class ReportKML implements GeneralReportModule { progressPanel.start(); progressPanel.updateStatusLabel(NbBundle.getMessage(this.getClass(), "ReportKML.progress.querying")); String kmlFileFullPath = baseReportDir + REPORT_KML; //NON-NLS + currentCase = Case.getCurrentCase(); skCase = currentCase.getSleuthkitCase(); diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportWizardAction.java b/Core/src/org/sleuthkit/autopsy/report/ReportWizardAction.java index 49f37008be..618cba2a38 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportWizardAction.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportWizardAction.java @@ -2,7 +2,7 @@ * * Autopsy Forensic Browser * - * Copyright 2013-2015 Basis Technology Corp. + * Copyright 2013-2018 Basis Technology Corp. * * Copyright 2012 42six Solutions. * Contact: aebadirad 42six com @@ -26,12 +26,14 @@ import java.awt.Component; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.beans.PropertyChangeEvent; +import java.io.IOException; import java.text.MessageFormat; import java.util.EnumSet; import java.util.Map; import javax.swing.ImageIcon; import javax.swing.JButton; import org.openide.DialogDisplayer; +import org.openide.NotifyDescriptor; import org.openide.WizardDescriptor; import org.openide.awt.ActionID; import org.openide.awt.ActionReference; @@ -70,12 +72,17 @@ public final class ReportWizardAction extends CallableSystemAction implements Pr TableReportModule tableReport = (TableReportModule) wiz.getProperty("tableModule"); GeneralReportModule generalReport = (GeneralReportModule) wiz.getProperty("generalModule"); FileReportModule fileReport = (FileReportModule) wiz.getProperty("fileModule"); - if (tableReport != null) { - generator.generateTableReport(tableReport, (Map) wiz.getProperty("artifactStates"), (Map) wiz.getProperty("tagStates")); //NON-NLS - } else if (generalReport != null) { - generator.generateGeneralReport(generalReport); - } else if (fileReport != null) { - generator.generateFileListReport(fileReport, (Map) wiz.getProperty("fileReportOptions")); //NON-NLS + try { + if (tableReport != null) { + generator.generateTableReport(tableReport, (Map) wiz.getProperty("artifactStates"), (Map) wiz.getProperty("tagStates")); //NON-NLS + } else if (generalReport != null) { + generator.generateGeneralReport(generalReport); + } else if (fileReport != null) { + generator.generateFileListReport(fileReport, (Map) wiz.getProperty("fileReportOptions")); //NON-NLS + } + } catch (IOException e) { + NotifyDescriptor descriptor = new NotifyDescriptor.Message(e.getMessage(), NotifyDescriptor.ERROR_MESSAGE); + DialogDisplayer.getDefault().notify(descriptor); } } } diff --git a/CoreLibs/ivy.xml b/CoreLibs/ivy.xml index b5de9e9ac2..a5f7aab768 100644 --- a/CoreLibs/ivy.xml +++ b/CoreLibs/ivy.xml @@ -28,8 +28,8 @@ - - + + diff --git a/CoreLibs/nbproject/project.properties b/CoreLibs/nbproject/project.properties index 09225d0115..4031d14fc3 100644 --- a/CoreLibs/nbproject/project.properties +++ b/CoreLibs/nbproject/project.properties @@ -58,11 +58,11 @@ file.reference.logkit-1.0.1.jar=release/modules/ext/logkit-1.0.1.jar file.reference.mail-1.4.3.jar=release/modules/ext/mail-1.4.3.jar file.reference.openjfx-dialogs-1.0.2.jar=release/modules/ext/openjfx-dialogs-1.0.3.jar file.reference.platform-3.4.0.jar=release/modules/ext/platform-3.4.0.jar -file.reference.poi-3.15.jar=release/modules/ext/poi-3.15.jar -file.reference.poi-excelant-3.15.jar=release/modules/ext/poi-excelant-3.15.jar -file.reference.poi-ooxml-3.15.jar=release/modules/ext/poi-ooxml-3.15.jar -file.reference.poi-ooxml-schemas-3.15.jar=release/modules/ext/poi-ooxml-schemas-3.15.jar -file.reference.poi-scratchpad-3.15.jar=release/modules/ext/poi-scratchpad-3.15.jar +file.reference.poi-3.17.jar=release/modules/ext/poi-3.17.jar +file.reference.poi-excelant-3.17.jar=release/modules/ext/poi-excelant-3.17.jar +file.reference.poi-ooxml-3.17.jar=release/modules/ext/poi-ooxml-3.17.jar +file.reference.poi-ooxml-schemas-3.17.jar=release/modules/ext/poi-ooxml-schemas-3.17.jar +file.reference.poi-scratchpad-3.17.jar=release/modules/ext/poi-scratchpad-3.17.jar file.reference.reflections-0.9.8.jar=release/modules/ext/reflections-0.9.8.jar file.reference.servlet-api-2.5.jar=release/modules/ext/servlet-api-2.5.jar file.reference.sigar-1.6.4-sources.jar=release/modules/ext/sigar-1.6.4-sources.jar diff --git a/CoreLibs/nbproject/project.xml b/CoreLibs/nbproject/project.xml index 5b4cb9fd83..ca89b8c1c2 100644 --- a/CoreLibs/nbproject/project.xml +++ b/CoreLibs/nbproject/project.xml @@ -295,17 +295,10 @@ org.apache.log4j.xml org.apache.poi org.apache.poi.common.usermodel + org.apache.poi.common.usermodel.fonts org.apache.poi.ddf org.apache.poi.dev org.apache.poi.extractor - org.apache.poi.hdf.event - org.apache.poi.hdf.extractor - org.apache.poi.hdf.extractor.data - org.apache.poi.hdf.extractor.util - org.apache.poi.hdf.model - org.apache.poi.hdf.model.hdftypes - org.apache.poi.hdf.model.hdftypes.definitions - org.apache.poi.hdf.model.util org.apache.poi.hdgf org.apache.poi.hdgf.chunks org.apache.poi.hdgf.dev @@ -313,6 +306,9 @@ org.apache.poi.hdgf.extractor org.apache.poi.hdgf.pointers org.apache.poi.hdgf.streams + org.apache.poi.hemf.extractor + org.apache.poi.hemf.hemfplus.record + org.apache.poi.hemf.record org.apache.poi.hmef org.apache.poi.hmef.attribute org.apache.poi.hmef.dev @@ -325,7 +321,6 @@ org.apache.poi.hpsf org.apache.poi.hpsf.extractor org.apache.poi.hpsf.wellknown - org.apache.poi.hslf org.apache.poi.hslf.blip org.apache.poi.hslf.dev org.apache.poi.hslf.exceptions @@ -358,7 +353,11 @@ org.apache.poi.hssf.record.crypto org.apache.poi.hssf.record.pivottable org.apache.poi.hssf.usermodel + org.apache.poi.hssf.usermodel.helpers org.apache.poi.hssf.util + org.apache.poi.hwmf.draw + org.apache.poi.hwmf.record + org.apache.poi.hwmf.usermodel org.apache.poi.hwpf org.apache.poi.hwpf.converter org.apache.poi.hwpf.dev @@ -372,18 +371,30 @@ org.apache.poi.openxml4j.opc org.apache.poi.openxml4j.opc.internal org.apache.poi.openxml4j.opc.internal.marshallers - org.apache.poi.openxml4j.opc.internal.signature org.apache.poi.openxml4j.opc.internal.unmarshallers - org.apache.poi.openxml4j.opc.signature org.apache.poi.openxml4j.util org.apache.poi.poifs.common org.apache.poi.poifs.crypt + org.apache.poi.poifs.crypt.agile + org.apache.poi.poifs.crypt.binaryrc4 + org.apache.poi.poifs.crypt.cryptoapi + org.apache.poi.poifs.crypt.dsig + org.apache.poi.poifs.crypt.dsig.facets + org.apache.poi.poifs.crypt.dsig.services + org.apache.poi.poifs.crypt.standard + org.apache.poi.poifs.crypt.temp + org.apache.poi.poifs.crypt.xor org.apache.poi.poifs.dev org.apache.poi.poifs.eventfilesystem org.apache.poi.poifs.filesystem + org.apache.poi.poifs.macros org.apache.poi.poifs.nio org.apache.poi.poifs.property org.apache.poi.poifs.storage + org.apache.poi.sl.draw + org.apache.poi.sl.draw.binding + org.apache.poi.sl.draw.geom + org.apache.poi.sl.image org.apache.poi.sl.usermodel org.apache.poi.ss org.apache.poi.ss.excelant @@ -401,15 +412,27 @@ org.apache.poi.ss.formula.udf org.apache.poi.ss.usermodel org.apache.poi.ss.usermodel.charts + org.apache.poi.ss.usermodel.helpers org.apache.poi.ss.util org.apache.poi.ss.util.cellwalk org.apache.poi.util - org.apache.poi.xslf + org.apache.poi.wp.usermodel + org.apache.poi.xdgf.exceptions + org.apache.poi.xdgf.extractor + org.apache.poi.xdgf.geom + org.apache.poi.xdgf.usermodel + org.apache.poi.xdgf.usermodel.section + org.apache.poi.xdgf.usermodel.section.geometry + org.apache.poi.xdgf.usermodel.shape + org.apache.poi.xdgf.usermodel.shape.exceptions + org.apache.poi.xdgf.util + org.apache.poi.xdgf.xml org.apache.poi.xslf.extractor org.apache.poi.xslf.model - org.apache.poi.xslf.model.geom org.apache.poi.xslf.usermodel org.apache.poi.xslf.util + org.apache.poi.xssf + org.apache.poi.xssf.binary org.apache.poi.xssf.dev org.apache.poi.xssf.eventusermodel org.apache.poi.xssf.extractor @@ -620,6 +643,8 @@ org.openxmlformats.schemas.spreadsheetml.x2006.main.impl org.openxmlformats.schemas.wordprocessingml.x2006.main org.openxmlformats.schemas.wordprocessingml.x2006.main.impl + org.openxmlformats.schemas.xpackage.x2006.digitalSignature + org.openxmlformats.schemas.xpackage.x2006.digitalSignature.impl org.reflections org.reflections.adapters org.reflections.scanners @@ -643,17 +668,10 @@ org.xml.sax.ext org.xml.sax.helpers repackage - schemaorg_apache_xmlbeans.system.sE130CAA0A01A7CDE5A2B4FEB8B311707 schemaorg_apache_xmlbeans.system.sXMLCONFIG schemaorg_apache_xmlbeans.system.sXMLLANG schemaorg_apache_xmlbeans.system.sXMLSCHEMA schemaorg_apache_xmlbeans.system.sXMLTOOLS - schemasMicrosoftComOfficeExcel - schemasMicrosoftComOfficeExcel.impl - schemasMicrosoftComOfficeOffice - schemasMicrosoftComOfficeOffice.impl - schemasMicrosoftComVml - schemasMicrosoftComVml.impl
ext/commons-logging-1.1.2-sources.jar @@ -763,10 +781,6 @@ ext/joda-time-2.4-javadoc.jar release/modules/ext/joda-time-2.4-javadoc.jar - - ext/poi-excelant-3.15.jar - release/modules/ext/poi-excelant-3.15.jar - ext/imageio-psd-3.2.jar release/modules/ext/imageio-psd-3.2.jar @@ -823,10 +837,6 @@ ext/jfxtras-fxml-8.0-r4.jar release/modules/ext/jfxtras-fxml-8.0-r4.jar - - ext/poi-ooxml-3.15.jar - release/modules/ext/poi-ooxml-3.15.jar - ext/joda-time-2.4.jar release/modules/ext/joda-time-2.4.jar @@ -851,18 +861,22 @@ ext/guava-19.0.jar release/modules/ext/guava-19.0.jar + + ext/poi-3.17.jar + release/modules/ext/poi-3.17.jar + + + ext/poi-ooxml-schemas-3.17.jar + release/modules/ext/poi-ooxml-schemas-3.17.jar + + + ext/poi-scratchpad-3.17.jar + release/modules/ext/poi-scratchpad-3.17.jar + ext/commons-io-2.5.jar release/modules/ext/commons-io-2.5.jar - - ext/poi-ooxml-schemas-3.15.jar - release/modules/ext/poi-ooxml-schemas-3.15.jar - - - ext/poi-scratchpad-3.15.jar - release/modules/ext/poi-scratchpad-3.15.jar - ext/imageio-bmp-3.2.jar release/modules/ext/imageio-bmp-3.2.jar @@ -887,6 +901,10 @@ ext/ant-1.8.2.jar release/modules/ext/ant-1.8.2.jar + + ext/poi-excelant-3.17.jar + release/modules/ext/poi-excelant-3.17.jar + ext/javassist-3.12.1.GA.jar release/modules/ext/javassist-3.12.1.GA.jar @@ -899,6 +917,10 @@ ext/commons-logging-1.1.2.jar release/modules/ext/commons-logging-1.1.2.jar + + ext/poi-ooxml-3.17.jar + release/modules/ext/poi-ooxml-3.17.jar + ext/controlsfx-8.40.11.jar release/modules/ext/controlsfx-8.40.11.jar @@ -911,10 +933,6 @@ ext/javaee-api-5.0-2.jar release/modules/ext/javaee-api-5.0-2.jar - - ext/poi-3.15.jar - release/modules/ext/poi-3.15.jar - ext/common-image-3.2.jar release/modules/ext/common-image-3.2.jar diff --git a/Experimental/ivy.xml b/Experimental/ivy.xml index 93d6dafa8d..965af1bc12 100644 --- a/Experimental/ivy.xml +++ b/Experimental/ivy.xml @@ -6,7 +6,7 @@ - + diff --git a/Experimental/nbproject/project.properties b/Experimental/nbproject/project.properties index 1bd0e2fc90..2db8202ab7 100644 --- a/Experimental/nbproject/project.properties +++ b/Experimental/nbproject/project.properties @@ -3,7 +3,7 @@ file.reference.jackson-core-2.7.0.jar=release/modules/ext/jackson-core-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.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 +file.reference.tika-core-1.17.jar=release/modules/ext/tika-core-1.17.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 diff --git a/Experimental/nbproject/project.xml b/Experimental/nbproject/project.xml index 8293608102..f2bf6d1996 100644 --- a/Experimental/nbproject/project.xml +++ b/Experimental/nbproject/project.xml @@ -146,12 +146,12 @@ org.sleuthkit.autopsy.experimental.configuration - 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/LGoodDatePicker-10.3.1.jar - release/modules/ext/LGoodDatePicker-10.3.1.jar + ext/tika-core-1.17.jar + release/modules/ext/tika-core-1.17.jar ext/mchange-commons-java-0.2.9.jar diff --git a/KeywordSearch/ivy.xml b/KeywordSearch/ivy.xml index 3ceb4e6378..fc6aa00269 100644 --- a/KeywordSearch/ivy.xml +++ b/KeywordSearch/ivy.xml @@ -22,7 +22,7 @@ - + diff --git a/KeywordSearch/nbproject/project.properties b/KeywordSearch/nbproject/project.properties index 5aa1b716e0..ddc825b4d4 100644 --- a/KeywordSearch/nbproject/project.properties +++ b/KeywordSearch/nbproject/project.properties @@ -1,6 +1,5 @@ -file.reference.aopalliance-1.0.jar=release/modules/ext/aopalliance-1.0.jar -file.reference.apache-mime4j-core-0.7.2.jar=release/modules/ext/apache-mime4j-core-0.7.2.jar -file.reference.apache-mime4j-dom-0.7.2.jar=release/modules/ext/apache-mime4j-dom-0.7.2.jar +file.reference.apache-mime4j-core-0.8.1.jar=release/modules/ext/apache-mime4j-core-0.8.1.jar +file.reference.apache-mime4j-dom-0.8.1.jar=release/modules/ext/apache-mime4j-dom-0.8.1.jar file.reference.asm-5.0.4.jar=release/modules/ext/asm-5.0.4.jar file.reference.asm-all-3.1.jar=release/modules/ext/asm-all-3.1.jar file.reference.bcmail-jdk15on-1.54.jar=release/modules/ext/bcmail-jdk15on-1.54.jar @@ -15,7 +14,7 @@ file.reference.commons-beanutils-1.9.2.jar=release/modules/ext/commons-beanutils file.reference.commons-codec-1.10.jar=release/modules/ext/commons-codec-1.10.jar file.reference.commons-collections-3.2.2.jar=release/modules/ext/commons-collections-3.2.2.jar file.reference.commons-collections4-4.1.jar=release/modules/ext/commons-collections4-4.1.jar -file.reference.commons-compress-1.12.jar=release/modules/ext/commons-compress-1.12.jar +file.reference.commons-compress-1.14.jar=release/modules/ext/commons-compress-1.14.jar file.reference.commons-csv-1.0.jar=release/modules/ext/commons-csv-1.0.jar file.reference.commons-digester-1.8.1.jar=release/modules/ext/commons-digester-1.8.1.jar file.reference.commons-exec-1.3.jar=release/modules/ext/commons-exec-1.3.jar @@ -26,35 +25,34 @@ file.reference.commons-logging-api-1.1.jar=release/modules/ext/commons-logging-a file.reference.commons-validator-1.5.1-javadoc.jar=release/modules/ext/commons-validator-1.5.1-javadoc.jar file.reference.commons-validator-1.5.1-sources.jar=release/modules/ext/commons-validator-1.5.1-sources.jar file.reference.commons-validator-1.5.1.jar=release/modules/ext/commons-validator-1.5.1.jar -file.reference.commons-vfs2-2.0.jar=release/modules/ext/commons-vfs2-2.0.jar file.reference.ctakes-core-3.2.2.jar=release/modules/ext/ctakes-core-3.2.2.jar file.reference.ctakes-core-res-3.2.2.jar=release/modules/ext/ctakes-core-res-3.2.2.jar file.reference.ctakes-type-system-3.2.2.jar=release/modules/ext/ctakes-type-system-3.2.2.jar file.reference.ctakes-utils-3.2.2.jar=release/modules/ext/ctakes-utils-3.2.2.jar file.reference.curvesapi-1.04.jar=release/modules/ext/curvesapi-1.04.jar -file.reference.cxf-core-3.0.3.jar=release/modules/ext/cxf-core-3.0.3.jar -file.reference.cxf-rt-frontend-jaxrs-3.0.3.jar=release/modules/ext/cxf-rt-frontend-jaxrs-3.0.3.jar -file.reference.cxf-rt-rs-client-3.0.3.jar=release/modules/ext/cxf-rt-rs-client-3.0.3.jar -file.reference.cxf-rt-transports-http-3.0.3.jar=release/modules/ext/cxf-rt-transports-http-3.0.3.jar +file.reference.cxf-core-3.0.16.jar=release/modules/ext/cxf-core-3.0.16.jar +file.reference.cxf-rt-frontend-jaxrs-3.0.16.jar=release/modules/ext/cxf-rt-frontend-jaxrs-3.0.16.jar +file.reference.cxf-rt-rs-client-3.0.16.jar=release/modules/ext/cxf-rt-rs-client-3.0.16.jar +file.reference.cxf-rt-transports-http-3.0.16.jar=release/modules/ext/cxf-rt-transports-http-3.0.16.jar file.reference.ehcache-core-2.6.2.jar=release/modules/ext/ehcache-core-2.6.2.jar file.reference.findstructapi-0.0.1.jar=release/modules/ext/findstructapi-0.0.1.jar -file.reference.fontbox-2.0.3.jar=release/modules/ext/fontbox-2.0.3.jar +file.reference.fontbox-2.0.8.jar=release/modules/ext/fontbox-2.0.8.jar file.reference.geoapi-3.0.0.jar=release/modules/ext/geoapi-3.0.0.jar file.reference.grib-4.5.5.jar=release/modules/ext/grib-4.5.5.jar -file.reference.gson-2.2.4.jar=release/modules/ext/gson-2.2.4.jar +file.reference.gson-2.8.1.jar=release/modules/ext/gson-2.8.1.jar file.reference.guava-17.0.jar=release/modules/ext/guava-17.0.jar file.reference.hamcrest-core-1.3.jar=release/modules/ext/hamcrest-core-1.3.jar -file.reference.httpclient-4.3.1.jar=release/modules/ext/httpclient-4.3.1.jar -file.reference.httpcore-4.3.jar=release/modules/ext/httpcore-4.3.jar +file.reference.httpclient-4.5.4.jar=release/modules/ext/httpclient-4.5.4.jar file.reference.httpcore-4.4.1.jar=release/modules/ext/httpcore-4.4.1.jar -file.reference.httpmime-4.3.1.jar=release/modules/ext/httpmime-4.3.1.jar +file.reference.httpcore-4.4.7.jar=release/modules/ext/httpcore-4.4.7.jar file.reference.httpmime-4.4.1.jar=release/modules/ext/httpmime-4.4.1.jar +file.reference.httpmime-4.5.4.jar=release/modules/ext/httpmime-4.5.4.jar file.reference.httpservices-4.5.5.jar=release/modules/ext/httpservices-4.5.5.jar file.reference.icu4j-3.8.jar=release/modules/ext/icu4j-3.8.jar file.reference.isoparser-1.1.18.jar=release/modules/ext/isoparser-1.1.18.jar -file.reference.jackcess-2.1.4.jar=release/modules/ext/jackcess-2.1.4.jar -file.reference.jackcess-encrypt-2.1.1.jar=release/modules/ext/jackcess-encrypt-2.1.1.jar -file.reference.jackson-core-2.8.1.jar=release/modules/ext/jackson-core-2.8.1.jar +file.reference.jackcess-2.1.8.jar=release/modules/ext/jackcess-2.1.8.jar +file.reference.jackcess-encrypt-2.1.2.jar=release/modules/ext/jackcess-encrypt-2.1.2.jar +file.reference.jackson-core-2.9.2.jar=release/modules/ext/jackson-core-2.9.2.jar file.reference.jakarta-regexp-1.4.jar=release/modules/ext/jakarta-regexp-1.4.jar file.reference.java-libpst-0.8.1.jar=release/modules/ext/java-libpst-0.8.1.jar file.reference.javax.annotation-api-1.2.jar=release/modules/ext/javax.annotation-api-1.2.jar @@ -63,20 +61,17 @@ file.reference.jcip-annotations-1.0.jar=release/modules/ext/jcip-annotations-1.0 file.reference.jcommander-1.35.jar=release/modules/ext/jcommander-1.35.jar file.reference.jdom-1.0.jar=release/modules/ext/jdom-1.0.jar file.reference.jdom2-2.0.4.jar=release/modules/ext/jdom2-2.0.4.jar -file.reference.jempbox-1.8.12.jar=release/modules/ext/jempbox-1.8.12.jar +file.reference.jempbox-1.8.13.jar=release/modules/ext/jempbox-1.8.13.jar file.reference.jericho-html-3.3-javadoc.jar=release/modules/ext/jericho-html-3.3-javadoc.jar file.reference.jericho-html-3.3-sources.jar=release/modules/ext/jericho-html-3.3-sources.jar file.reference.jericho-html-3.3.jar=release/modules/ext/jericho-html-3.3.jar file.reference.jhighlight-1.0.2.jar=release/modules/ext/jhighlight-1.0.2.jar -file.reference.jj2000-5.2.jar=release/modules/ext/jj2000-5.2.jar file.reference.jmatio-1.2.jar=release/modules/ext/jmatio-1.2.jar file.reference.jna-4.1.0.jar=release/modules/ext/jna-4.1.0.jar file.reference.joda-time-2.2.jar=release/modules/ext/joda-time-2.2.jar -file.reference.json-20140107.jar=release/modules/ext/json-20140107.jar file.reference.json-simple-1.1.1.jar=release/modules/ext/json-simple-1.1.1.jar file.reference.jsoup-1.7.2.jar=release/modules/ext/jsoup-1.7.2.jar file.reference.jsr-275-0.9.3.jar=release/modules/ext/jsr-275-0.9.3.jar -file.reference.junit-4.11.jar=release/modules/ext/junit-4.11.jar file.reference.juniversalchardet-1.0.3.jar=release/modules/ext/juniversalchardet-1.0.3.jar file.reference.junrar-0.7.jar=release/modules/ext/junrar-0.7.jar file.reference.jVinci-2.6.0.jar=release/modules/ext/jVinci-2.6.0.jar @@ -88,10 +83,7 @@ file.reference.lucene-core-4.0.0.jar=release/modules/ext/lucene-core-4.0.0.jar file.reference.lucene-queries-4.0.0.jar=release/modules/ext/lucene-queries-4.0.0.jar file.reference.lucene-queryparser-4.0.0.jar=release/modules/ext/lucene-queryparser-4.0.0.jar file.reference.lucene-sandbox-4.0.0.jar=release/modules/ext/lucene-sandbox-4.0.0.jar -file.reference.maven-scm-api-1.4.jar=release/modules/ext/maven-scm-api-1.4.jar -file.reference.maven-scm-provider-svn-commons-1.4.jar=release/modules/ext/maven-scm-provider-svn-commons-1.4.jar -file.reference.maven-scm-provider-svnexe-1.4.jar=release/modules/ext/maven-scm-provider-svnexe-1.4.jar -file.reference.metadata-extractor-2.9.1.jar=release/modules/ext/metadata-extractor-2.9.1.jar +file.reference.metadata-extractor-2.10.1.jar=release/modules/ext/metadata-extractor-2.10.1.jar file.reference.netcdf4-4.5.5.jar=release/modules/ext/netcdf4-4.5.5.jar file.reference.noggit-0.5.jar=release/modules/ext/noggit-0.5.jar file.reference.openaifsm-0.0.1.jar=release/modules/ext/openaifsm-0.0.1.jar @@ -101,18 +93,15 @@ file.reference.org.apache.felix.scr.annotations-1.6.0.jar=release/modules/ext/or file.reference.org.apache.felix.scr.generator-1.1.2.jar=release/modules/ext/org.apache.felix.scr.generator-1.1.2.jar file.reference.org.osgi.compendium-4.0.0.jar=release/modules/ext/org.osgi.compendium-4.0.0.jar file.reference.org.osgi.core-4.0.0.jar=release/modules/ext/org.osgi.core-4.0.0.jar -file.reference.pdfbox-2.0.3.jar=release/modules/ext/pdfbox-2.0.3.jar -file.reference.pdfbox-debugger-2.0.3.jar=release/modules/ext/pdfbox-debugger-2.0.3.jar -file.reference.pdfbox-tools-2.0.3.jar=release/modules/ext/pdfbox-tools-2.0.3.jar -file.reference.plexus-utils-1.5.6.jar=release/modules/ext/plexus-utils-1.5.6.jar -file.reference.poi-3.15.jar=release/modules/ext/poi-3.15.jar -file.reference.poi-ooxml-3.15.jar=release/modules/ext/poi-ooxml-3.15.jar -file.reference.poi-ooxml-schemas-3.15.jar=release/modules/ext/poi-ooxml-schemas-3.15.jar -file.reference.poi-scratchpad-3.15.jar=release/modules/ext/poi-scratchpad-3.15.jar +file.reference.pdfbox-2.0.8.jar=release/modules/ext/pdfbox-2.0.8.jar +file.reference.pdfbox-tools-2.0.8.jar=release/modules/ext/pdfbox-tools-2.0.8.jar +file.reference.poi-3.17.jar=release/modules/ext/poi-3.17.jar +file.reference.poi-ooxml-3.17.jar=release/modules/ext/poi-ooxml-3.17.jar +file.reference.poi-ooxml-schemas-3.17.jar=release/modules/ext/poi-ooxml-schemas-3.17.jar +file.reference.poi-scratchpad-3.17.jar=release/modules/ext/poi-scratchpad-3.17.jar file.reference.protobuf-java-2.5.0.jar=release/modules/ext/protobuf-java-2.5.0.jar file.reference.qdox-1.12.jar=release/modules/ext/qdox-1.12.jar file.reference.quartz-2.2.0.jar=release/modules/ext/quartz-2.2.0.jar -file.reference.regexp-1.3.jar=release/modules/ext/regexp-1.3.jar file.reference.rome-1.5.1.jar=release/modules/ext/rome-1.5.1.jar file.reference.rome-utils-1.5.1.jar=release/modules/ext/rome-utils-1.5.1.jar file.reference.sis-metadata-0.6.jar=release/modules/ext/sis-metadata-0.6.jar @@ -120,24 +109,18 @@ file.reference.sis-netcdf-0.6.jar=release/modules/ext/sis-netcdf-0.6.jar file.reference.sis-referencing-0.6.jar=release/modules/ext/sis-referencing-0.6.jar file.reference.sis-storage-0.6.jar=release/modules/ext/sis-storage-0.6.jar file.reference.sis-utility-0.6.jar=release/modules/ext/sis-utility-0.6.jar -file.reference.slf4j-api-1.7.12.jar=release/modules/ext/slf4j-api-1.7.12.jar +file.reference.slf4j-api-1.7.24.jar=release/modules/ext/slf4j-api-1.7.24.jar file.reference.solr-solrj-4.9.1-javadoc.jar=release/modules/ext/solr-solrj-4.9.1-javadoc.jar file.reference.solr-solrj-4.9.1-sources.jar=release/modules/ext/solr-solrj-4.9.1-sources.jar file.reference.solr-solrj-4.9.1.jar=release/modules/ext/solr-solrj-4.9.1.jar -file.reference.spring-aop-3.1.2.RELEASE.jar=release/modules/ext/spring-aop-3.1.2.RELEASE.jar -file.reference.spring-asm-3.1.2.RELEASE.jar=release/modules/ext/spring-asm-3.1.2.RELEASE.jar -file.reference.spring-beans-3.1.2.RELEASE.jar=release/modules/ext/spring-beans-3.1.2.RELEASE.jar -file.reference.spring-context-3.1.2.RELEASE.jar=release/modules/ext/spring-context-3.1.2.RELEASE.jar -file.reference.spring-core-3.1.2.RELEASE.jar=release/modules/ext/spring-core-3.1.2.RELEASE.jar -file.reference.spring-expression-3.1.2.RELEASE.jar=release/modules/ext/spring-expression-3.1.2.RELEASE.jar -file.reference.sqlite-jdbc-3.8.11.2.jar=release/modules/ext/sqlite-jdbc-3.8.11.2.jar +file.reference.sqlite-jdbc-3.19.3.jar=release/modules/ext/sqlite-jdbc-3.19.3.jar file.reference.sqlwrapper-0.0.1.jar=release/modules/ext/sqlwrapper-0.0.1.jar file.reference.stax2-api-3.1.4.jar=release/modules/ext/stax2-api-3.1.4.jar file.reference.tagsoup-1.2.1.jar=release/modules/ext/tagsoup-1.2.1.jar -file.reference.tika-core-1.14.jar=release/modules/ext/tika-core-1.14.jar -file.reference.tika-parsers-1.14-javadoc.jar=release/modules/ext/tika-parsers-1.14-javadoc.jar -file.reference.tika-parsers-1.14-sources.jar=release/modules/ext/tika-parsers-1.14-sources.jar -file.reference.tika-parsers-1.14.jar=release/modules/ext/tika-parsers-1.14.jar +file.reference.tika-core-1.17.jar=release/modules/ext/tika-core-1.17.jar +file.reference.tika-parsers-1.17-javadoc.jar=release/modules/ext/tika-parsers-1.17-javadoc.jar +file.reference.tika-parsers-1.17-sources.jar=release/modules/ext/tika-parsers-1.17-sources.jar +file.reference.tika-parsers-1.17.jar=release/modules/ext/tika-parsers-1.17.jar file.reference.udunits-4.5.5.jar=release/modules/ext/udunits-4.5.5.jar file.reference.uimafit-core-2.1.0.jar=release/modules/ext/uimafit-core-2.1.0.jar file.reference.uimaj-adapter-vinci-2.6.0.jar=release/modules/ext/uimaj-adapter-vinci-2.6.0.jar @@ -150,9 +133,7 @@ file.reference.vorbis-java-core-0.8.jar=release/modules/ext/vorbis-java-core-0.8 file.reference.vorbis-java-tika-0.8.jar=release/modules/ext/vorbis-java-tika-0.8.jar file.reference.woodstox-core-asl-4.4.1.jar=release/modules/ext/woodstox-core-asl-4.4.1.jar file.reference.xmlbeans-2.6.0.jar=release/modules/ext/xmlbeans-2.6.0.jar -file.reference.xmlschema-core-2.1.0.jar=release/modules/ext/xmlschema-core-2.1.0.jar -file.reference.xmpcore-5.1.2.jar=release/modules/ext/xmpcore-5.1.2.jar -file.reference.xz-1.5.jar=release/modules/ext/xz-1.5.jar +file.reference.xmpcore-5.1.3.jar=release/modules/ext/xmpcore-5.1.3.jar file.reference.zookeeper-3.4.6.jar=release/modules/ext/zookeeper-3.4.6.jar javac.source=1.8 javac.compilerargs=-Xlint -Xlint:-serial diff --git a/KeywordSearch/nbproject/project.xml b/KeywordSearch/nbproject/project.xml index 357c2178e2..db9ada1b1b 100644 --- a/KeywordSearch/nbproject/project.xml +++ b/KeywordSearch/nbproject/project.xml @@ -141,6 +141,10 @@ ext/commons-validator-1.5.1-sources.jar release/modules/ext/commons-validator-1.5.1-sources.jar + + ext/apache-mime4j-dom-0.8.1.jar + release/modules/ext/apache-mime4j-dom-0.8.1.jar + ext/commons-digester-1.8.1.jar release/modules/ext/commons-digester-1.8.1.jar @@ -149,14 +153,14 @@ ext/jwnl-1.3.3.jar release/modules/ext/jwnl-1.3.3.jar - - ext/tika-core-1.14.jar - release/modules/ext/tika-core-1.14.jar - ext/lucene-queryparser-4.0.0.jar release/modules/ext/lucene-queryparser-4.0.0.jar + + ext/httpclient-4.5.4.jar + release/modules/ext/httpclient-4.5.4.jar + ext/uimaj-examples-2.4.0.jar release/modules/ext/uimaj-examples-2.4.0.jar @@ -165,10 +169,6 @@ ext/cdm-4.5.5.jar release/modules/ext/cdm-4.5.5.jar - - ext/gson-2.2.4.jar - release/modules/ext/gson-2.2.4.jar - ext/org.osgi.compendium-4.0.0.jar release/modules/ext/org.osgi.compendium-4.0.0.jar @@ -177,6 +177,10 @@ ext/geoapi-3.0.0.jar release/modules/ext/geoapi-3.0.0.jar + + ext/commons-compress-1.14.jar + release/modules/ext/commons-compress-1.14.jar + ext/hamcrest-core-1.3.jar release/modules/ext/hamcrest-core-1.3.jar @@ -197,30 +201,34 @@ ext/xmlbeans-2.6.0.jar release/modules/ext/xmlbeans-2.6.0.jar - - ext/maven-scm-api-1.4.jar - release/modules/ext/maven-scm-api-1.4.jar - ext/quartz-2.2.0.jar release/modules/ext/quartz-2.2.0.jar - ext/jackcess-2.1.4.jar - release/modules/ext/jackcess-2.1.4.jar - - - ext/slf4j-api-1.7.12.jar - release/modules/ext/slf4j-api-1.7.12.jar + ext/sqlite-jdbc-3.19.3.jar + release/modules/ext/sqlite-jdbc-3.19.3.jar ext/guava-17.0.jar release/modules/ext/guava-17.0.jar + + ext/metadata-extractor-2.10.1.jar + release/modules/ext/metadata-extractor-2.10.1.jar + + + ext/apache-mime4j-core-0.8.1.jar + release/modules/ext/apache-mime4j-core-0.8.1.jar + ext/opennlp-maxent-3.0.3.jar release/modules/ext/opennlp-maxent-3.0.3.jar + + ext/pdfbox-tools-2.0.8.jar + release/modules/ext/pdfbox-tools-2.0.8.jar + ext/jVinci-2.6.0.jar release/modules/ext/jVinci-2.6.0.jar @@ -229,18 +237,14 @@ ext/json-simple-1.1.1.jar release/modules/ext/json-simple-1.1.1.jar + + ext/tika-parsers-1.17.jar + release/modules/ext/tika-parsers-1.17.jar + ext/sis-utility-0.6.jar release/modules/ext/sis-utility-0.6.jar - - ext/jj2000-5.2.jar - release/modules/ext/jj2000-5.2.jar - - - ext/httpclient-4.3.1.jar - release/modules/ext/httpclient-4.3.1.jar - ext/jhighlight-1.0.2.jar release/modules/ext/jhighlight-1.0.2.jar @@ -258,12 +262,12 @@ release/modules/ext/ctakes-utils-3.2.2.jar - ext/apache-mime4j-dom-0.7.2.jar - release/modules/ext/apache-mime4j-dom-0.7.2.jar + ext/cxf-rt-rs-client-3.0.16.jar + release/modules/ext/cxf-rt-rs-client-3.0.16.jar - ext/commons-compress-1.12.jar - release/modules/ext/commons-compress-1.12.jar + ext/jempbox-1.8.13.jar + release/modules/ext/jempbox-1.8.13.jar ext/openaifsm-0.0.1.jar @@ -277,14 +281,18 @@ ext/commons-collections4-4.1.jar release/modules/ext/commons-collections4-4.1.jar - - ext/cxf-rt-rs-client-3.0.3.jar - release/modules/ext/cxf-rt-rs-client-3.0.3.jar - ext/solr-solrj-4.9.1.jar release/modules/ext/solr-solrj-4.9.1.jar + + ext/xmpcore-5.1.3.jar + release/modules/ext/xmpcore-5.1.3.jar + + + ext/jackcess-2.1.8.jar + release/modules/ext/jackcess-2.1.8.jar + ext/findstructapi-0.0.1.jar release/modules/ext/findstructapi-0.0.1.jar @@ -317,6 +325,22 @@ ext/commons-codec-1.10.jar release/modules/ext/commons-codec-1.10.jar + + ext/gson-2.8.1.jar + release/modules/ext/gson-2.8.1.jar + + + ext/poi-ooxml-schemas-3.17.jar + release/modules/ext/poi-ooxml-schemas-3.17.jar + + + ext/poi-scratchpad-3.17.jar + release/modules/ext/poi-scratchpad-3.17.jar + + + ext/poi-3.17.jar + release/modules/ext/poi-3.17.jar + ext/lucene-queries-4.0.0.jar release/modules/ext/lucene-queries-4.0.0.jar @@ -326,45 +350,25 @@ release/modules/ext/bcprov-jdk15on-1.54.jar - ext/poi-ooxml-schemas-3.15.jar - release/modules/ext/poi-ooxml-schemas-3.15.jar - - - ext/poi-scratchpad-3.15.jar - release/modules/ext/poi-scratchpad-3.15.jar + ext/fontbox-2.0.8.jar + release/modules/ext/fontbox-2.0.8.jar ext/solr-solrj-4.9.1-sources.jar release/modules/ext/solr-solrj-4.9.1-sources.jar - - ext/commons-vfs2-2.0.jar - release/modules/ext/commons-vfs2-2.0.jar - - - ext/tika-parsers-1.14.jar - release/modules/ext/tika-parsers-1.14.jar - - - ext/jackcess-encrypt-2.1.1.jar - release/modules/ext/jackcess-encrypt-2.1.1.jar - - - ext/spring-expression-3.1.2.RELEASE.jar - release/modules/ext/spring-expression-3.1.2.RELEASE.jar - ext/lucene-analyzers-common-4.0.0.jar release/modules/ext/lucene-analyzers-common-4.0.0.jar - - ext/tika-parsers-1.14-sources.jar - release/modules/ext/tika-parsers-1.14-sources.jar - ext/javax.ws.rs-api-2.0.1.jar release/modules/ext/javax.ws.rs-api-2.0.1.jar + + ext/httpmime-4.5.4.jar + release/modules/ext/httpmime-4.5.4.jar + ext/junrar-0.7.jar release/modules/ext/junrar-0.7.jar @@ -378,21 +382,13 @@ release/modules/ext/noggit-0.5.jar - ext/xmlschema-core-2.1.0.jar - release/modules/ext/xmlschema-core-2.1.0.jar - - - ext/httpmime-4.3.1.jar - release/modules/ext/httpmime-4.3.1.jar + ext/poi-ooxml-3.17.jar + release/modules/ext/poi-ooxml-3.17.jar ext/jna-4.1.0.jar release/modules/ext/jna-4.1.0.jar - - ext/xz-1.5.jar - release/modules/ext/xz-1.5.jar - ext/qdox-1.12.jar release/modules/ext/qdox-1.12.jar @@ -410,37 +406,17 @@ release/modules/ext/grib-4.5.5.jar - ext/maven-scm-provider-svn-commons-1.4.jar - release/modules/ext/maven-scm-provider-svn-commons-1.4.jar - - - ext/poi-3.15.jar - release/modules/ext/poi-3.15.jar - - - ext/spring-aop-3.1.2.RELEASE.jar - release/modules/ext/spring-aop-3.1.2.RELEASE.jar - - - ext/json-20140107.jar - release/modules/ext/json-20140107.jar + ext/jackson-core-2.9.2.jar + release/modules/ext/jackson-core-2.9.2.jar ext/uimaj-core-2.5.0.jar release/modules/ext/uimaj-core-2.5.0.jar - - ext/pdfbox-2.0.3.jar - release/modules/ext/pdfbox-2.0.3.jar - ext/jmatio-1.2.jar release/modules/ext/jmatio-1.2.jar - - ext/metadata-extractor-2.9.1.jar - release/modules/ext/metadata-extractor-2.9.1.jar - ext/commons-csv-1.0.jar release/modules/ext/commons-csv-1.0.jar @@ -466,21 +442,13 @@ release/modules/ext/httpservices-4.5.5.jar - ext/plexus-utils-1.5.6.jar - release/modules/ext/plexus-utils-1.5.6.jar - - - ext/fontbox-2.0.3.jar - release/modules/ext/fontbox-2.0.3.jar + ext/httpcore-4.4.7.jar + release/modules/ext/httpcore-4.4.7.jar ext/bcmail-jdk15on-1.54.jar release/modules/ext/bcmail-jdk15on-1.54.jar - - ext/spring-beans-3.1.2.RELEASE.jar - release/modules/ext/spring-beans-3.1.2.RELEASE.jar - ext/solr-solrj-4.9.1-javadoc.jar release/modules/ext/solr-solrj-4.9.1-javadoc.jar @@ -490,8 +458,8 @@ release/modules/ext/asm-all-3.1.jar - ext/tika-parsers-1.14-javadoc.jar - release/modules/ext/tika-parsers-1.14-javadoc.jar + ext/tika-parsers-1.17-javadoc.jar + release/modules/ext/tika-parsers-1.17-javadoc.jar ext/icu4j-3.8.jar @@ -501,10 +469,6 @@ ext/curvesapi-1.04.jar release/modules/ext/curvesapi-1.04.jar - - ext/xmpcore-5.1.2.jar - release/modules/ext/xmpcore-5.1.2.jar - ext/sis-referencing-0.6.jar release/modules/ext/sis-referencing-0.6.jar @@ -521,6 +485,10 @@ ext/tagsoup-1.2.1.jar release/modules/ext/tagsoup-1.2.1.jar + + ext/tika-core-1.17.jar + release/modules/ext/tika-core-1.17.jar + ext/lucene-core-4.0.0.jar release/modules/ext/lucene-core-4.0.0.jar @@ -533,10 +501,6 @@ ext/commons-logging-1.2.jar release/modules/ext/commons-logging-1.2.jar - - ext/jackson-core-2.8.1.jar - release/modules/ext/jackson-core-2.8.1.jar - ext/org.osgi.core-4.0.0.jar release/modules/ext/org.osgi.core-4.0.0.jar @@ -545,10 +509,18 @@ ext/c3p0-0.9.1.1.jar release/modules/ext/c3p0-0.9.1.1.jar + + ext/tika-parsers-1.17-sources.jar + release/modules/ext/tika-parsers-1.17-sources.jar + ext/sqlwrapper-0.0.1.jar release/modules/ext/sqlwrapper-0.0.1.jar + + ext/jackcess-encrypt-2.1.2.jar + release/modules/ext/jackcess-encrypt-2.1.2.jar + ext/jericho-html-3.3-javadoc.jar release/modules/ext/jericho-html-3.3-javadoc.jar @@ -557,18 +529,10 @@ ext/udunits-4.5.5.jar release/modules/ext/udunits-4.5.5.jar - - ext/aopalliance-1.0.jar - release/modules/ext/aopalliance-1.0.jar - ext/commons-collections-3.2.2.jar release/modules/ext/commons-collections-3.2.2.jar - - ext/cxf-rt-frontend-jaxrs-3.0.3.jar - release/modules/ext/cxf-rt-frontend-jaxrs-3.0.3.jar - ext/uimaj-document-annotation-2.5.0.jar release/modules/ext/uimaj-document-annotation-2.5.0.jar @@ -577,41 +541,29 @@ ext/woodstox-core-asl-4.4.1.jar release/modules/ext/woodstox-core-asl-4.4.1.jar - - ext/poi-ooxml-3.15.jar - release/modules/ext/poi-ooxml-3.15.jar - ext/org.apache.felix.scr.generator-1.1.2.jar release/modules/ext/org.apache.felix.scr.generator-1.1.2.jar + + ext/pdfbox-2.0.8.jar + release/modules/ext/pdfbox-2.0.8.jar + ext/zookeeper-3.4.6.jar release/modules/ext/zookeeper-3.4.6.jar - ext/cxf-rt-transports-http-3.0.3.jar - release/modules/ext/cxf-rt-transports-http-3.0.3.jar - - - ext/pdfbox-debugger-2.0.3.jar - release/modules/ext/pdfbox-debugger-2.0.3.jar - - - ext/spring-core-3.1.2.RELEASE.jar - release/modules/ext/spring-core-3.1.2.RELEASE.jar + ext/cxf-rt-transports-http-3.0.16.jar + release/modules/ext/cxf-rt-transports-http-3.0.16.jar ext/netcdf4-4.5.5.jar release/modules/ext/netcdf4-4.5.5.jar - ext/spring-asm-3.1.2.RELEASE.jar - release/modules/ext/spring-asm-3.1.2.RELEASE.jar - - - ext/junit-4.11.jar - release/modules/ext/junit-4.11.jar + ext/slf4j-api-1.7.24.jar + release/modules/ext/slf4j-api-1.7.24.jar ext/protobuf-java-2.5.0.jar @@ -642,37 +594,17 @@ release/modules/ext/commons-lang-2.6.jar - ext/sqlite-jdbc-3.8.11.2.jar - release/modules/ext/sqlite-jdbc-3.8.11.2.jar - - - ext/jempbox-1.8.12.jar - release/modules/ext/jempbox-1.8.12.jar - - - ext/maven-scm-provider-svnexe-1.4.jar - release/modules/ext/maven-scm-provider-svnexe-1.4.jar + ext/cxf-core-3.0.16.jar + release/modules/ext/cxf-core-3.0.16.jar ext/opennlp-tools-1.5.3.jar release/modules/ext/opennlp-tools-1.5.3.jar - - ext/apache-mime4j-core-0.7.2.jar - release/modules/ext/apache-mime4j-core-0.7.2.jar - ext/rome-utils-1.5.1.jar release/modules/ext/rome-utils-1.5.1.jar - - ext/httpcore-4.3.jar - release/modules/ext/httpcore-4.3.jar - - - ext/pdfbox-tools-2.0.3.jar - release/modules/ext/pdfbox-tools-2.0.3.jar - ext/sis-storage-0.6.jar release/modules/ext/sis-storage-0.6.jar @@ -689,6 +621,10 @@ ext/uimafit-core-2.1.0.jar release/modules/ext/uimafit-core-2.1.0.jar + + ext/cxf-rt-frontend-jaxrs-3.0.16.jar + release/modules/ext/cxf-rt-frontend-jaxrs-3.0.16.jar + ext/cleartk-util-2.0.0.jar release/modules/ext/cleartk-util-2.0.0.jar @@ -697,14 +633,6 @@ ext/jdom-1.0.jar release/modules/ext/jdom-1.0.jar - - ext/cxf-core-3.0.3.jar - release/modules/ext/cxf-core-3.0.3.jar - - - ext/regexp-1.3.jar - release/modules/ext/regexp-1.3.jar - ext/commons-beanutils-1.9.2.jar release/modules/ext/commons-beanutils-1.9.2.jar @@ -713,10 +641,6 @@ ext/ehcache-core-2.6.2.jar release/modules/ext/ehcache-core-2.6.2.jar - - ext/spring-context-3.1.2.RELEASE.jar - release/modules/ext/spring-context-3.1.2.RELEASE.jar - ext/ctakes-type-system-3.2.2.jar release/modules/ext/ctakes-type-system-3.2.2.jar diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/GlobalListsManagementPanel.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/GlobalListsManagementPanel.java index 8aeb498432..aebf606380 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/GlobalListsManagementPanel.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/GlobalListsManagementPanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2017 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -24,6 +24,7 @@ import java.awt.event.KeyEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.File; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; import javax.swing.JFileChooser; @@ -35,6 +36,8 @@ import javax.swing.table.AbstractTableModel; import org.netbeans.spi.options.OptionsPanelController; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.corecomponents.OptionsPanel; +import org.sleuthkit.autopsy.coreutils.ModuleSettings; +import org.sleuthkit.autopsy.coreutils.PlatformUtil; import org.sleuthkit.autopsy.ingest.IngestManager; /** @@ -45,6 +48,7 @@ class GlobalListsManagementPanel extends javax.swing.JPanel implements OptionsPa private static final long serialVersionUID = 1L; private final KeywordListTableModel tableModel; private final org.sleuthkit.autopsy.keywordsearch.GlobalListSettingsPanel globalListSettingsPanel; + private final static String LAST_KEYWORD_LIST_PATH_KEY = "KeyWordImport_List"; GlobalListsManagementPanel(org.sleuthkit.autopsy.keywordsearch.GlobalListSettingsPanel gsp) { this.globalListSettingsPanel = gsp; @@ -345,8 +349,13 @@ class GlobalListsManagementPanel extends javax.swing.JPanel implements OptionsPa }//GEN-LAST:event_newListButtonActionPerformed private void importButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_importButtonActionPerformed - + String lastBaseDirectory = Paths.get(PlatformUtil.getUserConfigDirectory(), "KeywordList").toString(); + if (ModuleSettings.settingExists(ModuleSettings.MAIN_SETTINGS, LAST_KEYWORD_LIST_PATH_KEY)) { + lastBaseDirectory = ModuleSettings.getConfigSetting(ModuleSettings.MAIN_SETTINGS, LAST_KEYWORD_LIST_PATH_KEY); + } + File importFolder = new File(lastBaseDirectory); JFileChooser chooser = new JFileChooser(); + chooser.setCurrentDirectory(importFolder); final String[] AUTOPSY_EXTENSIONS = new String[]{"xml"}; //NON-NLS final String[] ENCASE_EXTENSIONS = new String[]{"txt"}; //NON-NLS FileNameExtensionFilter autopsyFilter = new FileNameExtensionFilter( @@ -430,7 +439,7 @@ class GlobalListsManagementPanel extends javax.swing.JPanel implements OptionsPa KeywordSearchUtil.displayDialog( NbBundle.getMessage(this.getClass(), "KeywordSearch.listImportFeatureTitle"), NbBundle.getMessage(this.getClass(), "KeywordSearch.kwListFailImportMsg"), KeywordSearchUtil.DIALOG_MESSAGE_TYPE.INFO); } - + ModuleSettings.setConfigSetting(ModuleSettings.MAIN_SETTINGS, LAST_KEYWORD_LIST_PATH_KEY, selFile.getParent()); } tableModel.resync(); diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchResultFactory.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchResultFactory.java index a48b40e756..a8bc995eae 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchResultFactory.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchResultFactory.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2017 Basis Technology Corp. + * Copyright 2011-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -44,6 +44,7 @@ import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode; import static org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode.AbstractFilePropertyType.LOCATION; import org.sleuthkit.autopsy.datamodel.AbstractFsContentNode; +import org.sleuthkit.autopsy.datamodel.EmptyNode; import org.sleuthkit.autopsy.datamodel.KeyValue; import org.sleuthkit.autopsy.datamodel.KeyValueNode; import org.sleuthkit.autopsy.keywordsearch.KeywordSearchResultFactory.KeyValueQueryContent; @@ -63,21 +64,21 @@ import org.sleuthkit.datamodel.TskCoreException; * Responsible for assembling nodes and columns in the right way and performing * lazy queries as needed. */ -class KeywordSearchResultFactory extends ChildFactory { +class KeywordSearchResultFactory extends ChildFactory { - private static final Logger logger = Logger.getLogger(KeywordSearchResultFactory.class.getName()); + private static final Logger LOGGER = Logger.getLogger(KeywordSearchResultFactory.class.getName()); //common properties (superset of all Node properties) to be displayed as columns - static final List COMMON_PROPERTIES = - Stream.concat( + static final List COMMON_PROPERTIES + = Stream.concat( Stream.of( TSK_KEYWORD, TSK_KEYWORD_REGEXP, TSK_KEYWORD_PREVIEW) - .map(BlackboardAttribute.ATTRIBUTE_TYPE::getDisplayName), + .map(BlackboardAttribute.ATTRIBUTE_TYPE::getDisplayName), Arrays.stream(AbstractAbstractFileNode.AbstractFilePropertyType.values()) - .map(Object::toString)) - .collect(Collectors.toList()); + .map(Object::toString)) + .collect(Collectors.toList()); private final Collection queryRequests; @@ -93,7 +94,7 @@ class KeywordSearchResultFactory extends ChildFactory { * @param toPopulate property set map for a Node */ @Override - protected boolean createKeys(List toPopulate) { + protected boolean createKeys(List toPopulate) { for (QueryRequest queryRequest : queryRequests) { /** @@ -130,7 +131,7 @@ class KeywordSearchResultFactory extends ChildFactory { * @return */ @NbBundle.Messages({"KeywordSearchResultFactory.query.exception.msg=Could not perform the query "}) - private boolean createFlatKeys(KeywordSearchQuery queryRequest, List toPopulate) { + private boolean createFlatKeys(KeywordSearchQuery queryRequest, List toPopulate) { /** * Execute the requested query. @@ -139,15 +140,15 @@ class KeywordSearchResultFactory extends ChildFactory { try { queryResults = queryRequest.performQuery(); } catch (KeywordSearchModuleException | NoOpenCoreException ex) { - logger.log(Level.SEVERE, "Could not perform the query " + queryRequest.getQueryString(), ex); //NON-NLS + LOGGER.log(Level.SEVERE, "Could not perform the query " + queryRequest.getQueryString(), ex); //NON-NLS MessageNotifyUtil.Notify.error(Bundle.KeywordSearchResultFactory_query_exception_msg() + queryRequest.getQueryString(), ex.getCause().getMessage()); return false; } - SleuthkitCase tskCase = null; + SleuthkitCase tskCase; try { tskCase = Case.getCurrentCase().getSleuthkitCase(); } catch (IllegalStateException ex) { - logger.log(Level.SEVERE, "There was no case open.", ex); //NON-NLS + LOGGER.log(Level.SEVERE, "There was no case open.", ex); //NON-NLS return false; } @@ -159,16 +160,16 @@ class KeywordSearchResultFactory extends ChildFactory { * Get file properties. */ Map properties = new LinkedHashMap<>(); - Content content = null; - String contentName = ""; + Content content; + String contentName; try { content = tskCase.getContentById(hit.getContentID()); if (content == null) { - logger.log(Level.SEVERE, "There was a error getting content by id."); //NON-NLS + LOGGER.log(Level.SEVERE, "There was a error getting content by id."); //NON-NLS return false; } } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "There was a error getting content by id.", ex); //NON-NLS + LOGGER.log(Level.SEVERE, "There was a error getting content by id.", ex); //NON-NLS return false; } @@ -191,7 +192,7 @@ class KeywordSearchResultFactory extends ChildFactory { try { hitName = tskCase.getBlackboardArtifact(hit.getArtifactID().get()).getDisplayName() + " Artifact"; //NON-NLS } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Error getting blckboard artifact by id", ex); + LOGGER.log(Level.SEVERE, "Error getting blckboard artifact by id", ex); return false; } } else { @@ -202,9 +203,13 @@ class KeywordSearchResultFactory extends ChildFactory { } - // Add all the nodes to toPopulate at once. Minimizes node creation - // EDT threads, which can slow and/or hang the UI on large queries. - toPopulate.addAll(tempList); + if (hitNumber == 0) { + toPopulate.add(new KeyValue("This KeyValue Is Empty", 0)); + } else { + // Add all the nodes to toPopulate at once. Minimizes node creation + // EDT threads, which can slow and/or hang the UI on large queries. + toPopulate.addAll(tempList); + } //write to bb //cannot reuse snippet in BlackboardResultWriter @@ -239,15 +244,25 @@ class KeywordSearchResultFactory extends ChildFactory { return hits.values(); } + @NbBundle.Messages({"KeywordSearchResultFactory.createNodeForKey.noResultsFound.text=No results found."}) @Override - protected Node createNodeForKey(KeyValueQueryContent key) { - final Content content = key.getContent(); - QueryResults hits = key.getHits(); + protected Node createNodeForKey(KeyValue key) { + Node resultNode; - Node kvNode = new KeyValueNode(key, Children.LEAF, Lookups.singleton(content)); + if (key instanceof KeyValueQueryContent) { + final Content content = ((KeyValueQueryContent) key).getContent(); + QueryResults hits = ((KeyValueQueryContent) key).getHits(); - //wrap in KeywordSearchFilterNode for the markup content, might need to override FilterNode for more customization - return new KeywordSearchFilterNode(hits, kvNode); + Node kvNode = new KeyValueNode(key, Children.LEAF, Lookups.singleton(content)); + + //wrap in KeywordSearchFilterNode for the markup content, might need to override FilterNode for more customization + resultNode = new KeywordSearchFilterNode(hits, kvNode); + } else { + resultNode = new EmptyNode("This Node Is Empty"); + resultNode.setDisplayName(NbBundle.getMessage(this.getClass(), "KeywordSearchResultFactory.createNodeForKey.noResultsFound.text")); + } + + return resultNode; } @@ -308,7 +323,7 @@ class KeywordSearchResultFactory extends ChildFactory { */ static class BlackboardResultWriter extends SwingWorker { - private static final List writers = new ArrayList<>(); + private static final List WRITERS = new ArrayList<>(); private ProgressHandle progress; private final KeywordSearchQuery query; private final QueryResults hits; @@ -343,24 +358,24 @@ class KeywordSearchResultFactory extends ChildFactory { try { get(); } catch (InterruptedException | CancellationException ex) { - logger.log(Level.WARNING, "User cancelled writing of ad hoc search query results for '{0}' to the blackboard", query.getQueryString()); //NON-NLS + LOGGER.log(Level.WARNING, "User cancelled writing of ad hoc search query results for '{0}' to the blackboard", query.getQueryString()); //NON-NLS } catch (ExecutionException ex) { - logger.log(Level.SEVERE, "Error writing of ad hoc search query results for " + query.getQueryString() + " to the blackboard", ex); //NON-NLS + LOGGER.log(Level.SEVERE, "Error writing of ad hoc search query results for " + query.getQueryString() + " to the blackboard", ex); //NON-NLS } } private static synchronized void registerWriter(BlackboardResultWriter writer) { - writers.add(writer); + WRITERS.add(writer); } private static synchronized void deregisterWriter(BlackboardResultWriter writer) { - writers.remove(writer); + WRITERS.remove(writer); } static synchronized void stopAllWriters() { - for (BlackboardResultWriter w : writers) { + for (BlackboardResultWriter w : WRITERS) { w.cancel(true); - writers.remove(w); + WRITERS.remove(w); } } } diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TikaTextExtractor.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TikaTextExtractor.java index fcbace158d..4b9c3b17cb 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TikaTextExtractor.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TikaTextExtractor.java @@ -33,7 +33,11 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import org.apache.tika.Tika; import org.apache.tika.metadata.Metadata; +import org.apache.tika.parser.AutoDetectParser; import org.apache.tika.parser.ParseContext; +import org.apache.tika.parser.Parser; +import org.apache.tika.parser.ParsingReader; +import org.apache.tika.parser.microsoft.OfficeParserConfig; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.AbstractFile; @@ -48,6 +52,8 @@ class TikaTextExtractor extends FileTextExtractor { static final private Logger logger = Logger.getLogger(TikaTextExtractor.class.getName()); private final ExecutorService tikaParseExecutor = Executors.newSingleThreadExecutor(); + private final AutoDetectParser parser = new AutoDetectParser(); + private static final List TIKA_SUPPORTED_TYPES = new Tika().getParser().getSupportedTypes(new ParseContext()) .stream() @@ -64,8 +70,18 @@ class TikaTextExtractor extends FileTextExtractor { ReadContentInputStream stream = new ReadContentInputStream(sourceFile); Metadata metadata = new Metadata(); + ParseContext parseContext = new ParseContext(); + parseContext.set(Parser.class, parser); + + // Use the more memory efficient Tika SAX parsers for DOCX and + // PPTX files (it already uses SAX for XLSX). + OfficeParserConfig officeParserConfig = new OfficeParserConfig(); + officeParserConfig.setUseSAXPptxExtractor(true); + officeParserConfig.setUseSAXDocxExtractor(true); + parseContext.set(OfficeParserConfig.class, officeParserConfig); + //Parse the file in a task, a convenient way to have a timeout... - final Future future = tikaParseExecutor.submit(() -> new Tika().parse(stream, metadata)); + final Future future = tikaParseExecutor.submit(() -> new ParsingReader(parser, stream, metadata, parseContext)); try { final Reader tikaReader = future.get(getTimeout(sourceFile.getSize()), TimeUnit.SECONDS); diff --git a/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties b/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties index e0a4c85328..bafc320fad 100644 --- a/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties +++ b/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties @@ -1,5 +1,5 @@ #Updated by build script -#Fri, 05 Jan 2018 10:31:22 -0500 +#Fri, 05 Jan 2018 12:14:19 -0500 LBL_splash_window_title=Starting Autopsy SPLASH_HEIGHT=314 SPLASH_WIDTH=538 diff --git a/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties b/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties index 8f4ccbd194..6097052361 100644 --- a/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties +++ b/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties @@ -1,4 +1,4 @@ #Updated by build script -#Fri, 05 Jan 2018 10:31:22 -0500 +#Fri, 05 Jan 2018 12:14:19 -0500 CTL_MainWindow_Title=Autopsy 4.5.0 CTL_MainWindow_Title_No_Project=Autopsy 4.5.0 diff --git a/test/script/regression.py b/test/script/regression.py index be6515f054..afe1ea4976 100644 --- a/test/script/regression.py +++ b/test/script/regression.py @@ -652,10 +652,10 @@ class TestData(object): # we are looking for is the only one in the self.reports_dir folder html_path = "" for fs in os.listdir(self.reports_dir): - html_path = make_path(self.reports_dir, fs) - if os.path.isdir(html_path): + if "HTML Report" in fs: + html_path = make_path(self.reports_dir, fs) break - return make_path(html_path, os.listdir(html_path)[0]) + return html_path def get_sorted_data_path(self, file_type): """Get the path to the BlackboardDump file that corresponds to the given DBType.