Merge remote-tracking branch 'upstream/release-4.6.0' into 3344_WrongKeywordSearchMessage

This commit is contained in:
U-BASIS\dgrove
2018-02-06 22:43:13 -05:00
51 changed files with 2038 additions and 1397 deletions
+4 -2
View File
@@ -17,6 +17,8 @@
<fileset dir="{basedir}/../../InternalPythonModules"/>
</copy>
</target>
<property name="VERSION" value="4.6.0"/>
<target name="get-thirdparty-dependencies" description="get third-party dependencies">
<!--Copy openCV dependencies to release-->
@@ -52,8 +54,8 @@
<target name="getTSKJars" depends="findTSK">
<property environment="env"/>
<copy file="${env.TSK_HOME}/bindings/java/dist/Tsk_DataModel_PostgreSQL.jar"
tofile="${ext.dir}/Tsk_DataModel_PostgreSQL.jar"/>
<copy file="${env.TSK_HOME}/bindings/java/dist/sleuthkit-postgresql-${VERSION}.jar"
tofile="${ext.dir}/sleuthkit-postgresql-${VERSION}.jar"/>
<copy file="${env.TSK_HOME}/bindings/java/lib/sqlite-jdbc-3.8.11.jar"
tofile="${ext.dir}/sqlite-jdbc-3.8.11.jar"/>
<copy file="${env.TSK_HOME}/bindings/java/lib/postgresql-9.4.1211.jre7.jar"
+1 -1
View File
@@ -16,9 +16,9 @@ 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.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.Tsk_DataModel_PostgreSQL.jar=release/modules/ext/Tsk_DataModel_PostgreSQL.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
+3 -2
View File
@@ -286,6 +286,7 @@
</test-dependency>
</test-type>
</test-dependencies>
<public-packages>
<package>net.sf.sevenzipjbinding</package>
<package>net.sf.sevenzipjbinding.impl</package>
@@ -329,8 +330,8 @@
<binary-origin>release/modules/ext/jdom-2.0.5.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/Tsk_DataModel_PostgreSQL.jar</runtime-relative-path>
<binary-origin>release/modules/ext/Tsk_DataModel_PostgreSQL.jar</binary-origin>
<runtime-relative-path>ext/sleuthkit-postgresql-4.6.0.jar</runtime-relative-path>
<binary-origin>release/modules/ext/sleuthkit-postgresql-4.6.0.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/opencv-248.jar</runtime-relative-path>
@@ -36,10 +36,10 @@ GetTagNameDialog.tagNameExistsTskCore.msg=The {0} tag name already exists in the
OpenLogFolder.error1=Log File Not Found: {0}
OpenLogFolder.CouldNotOpenLogFolder=Could not open log folder
CTL_OpenLogFolder=Open Log Folder
CTL_OpenOutputFolder=Open Output Folder
OpenOutputFolder.error1=Output Folder Not Found\: {0}
OpenOutputFolder.noCaseOpen=No open case, therefore no current output folder available.
OpenOutputFolder.CouldNotOpenOutputFolder=Could not open output folder
CTL_OpenOutputFolder=Open Case Folder
OpenOutputFolder.error1=Case Output Folder Not Found\: {0}
OpenOutputFolder.noCaseOpen=No open case, therefore no current case output folder available.
OpenOutputFolder.CouldNotOpenOutputFolder=Could not open case output folder
ShowIngestProgressSnapshotAction.actionName.text=Get Ingest Progress Snapshot
OpenPythonModulesFolderAction.actionName.text=Python Plugins
OpenPythonModulesFolderAction.errorMsg.folderNotFound=Python plugins folder not found: {0}
@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2017 Basis Technology Corp.
* Copyright 2011-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -35,7 +35,7 @@ import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.coreutils.Logger;
/**
* The action associated with the Tools/Open Output Folder menu item. It opens a
* The action associated with the Tools/Open Case Folder menu item. It opens a
* file explorer window for the root output directory for the currently open
* case. If the case is a single-user case, this is the case directory. If the
* case is a multi-user case, this is a subdirectory of the case directory
@@ -44,7 +44,7 @@ import org.sleuthkit.autopsy.coreutils.Logger;
* This action should only be invoked in the event dispatch thread (EDT).
*/
@ActionRegistration(displayName = "#CTL_OpenOutputFolder", iconInMenu = true, lazy = false)
@ActionReference(path = "Menu/Tools", position = 1850, separatorBefore = 1849)
@ActionReference(path = "Menu/Case", position = 302)
@ActionID(id = "org.sleuthkit.autopsy.actions.OpenOutputFolderAction", category = "Help")
public final class OpenOutputFolderAction extends CallableSystemAction {
@@ -61,7 +61,7 @@ public final class OpenOutputFolderAction extends CallableSystemAction {
try {
Desktop.getDesktop().open(outputDir);
} catch (IOException ex) {
logger.log(Level.SEVERE, String.format("Failed to open output folder %s", outputDir), ex); //NON-NLS
logger.log(Level.SEVERE, String.format("Failed to open case output folder %s", outputDir), ex); //NON-NLS
NotifyDescriptor descriptor = new NotifyDescriptor.Message(
NbBundle.getMessage(this.getClass(), "OpenOutputFolder.CouldNotOpenOutputFolder", outputDir.getAbsolutePath()), NotifyDescriptor.ERROR_MESSAGE);
DialogDisplayer.getDefault().notify(descriptor);
@@ -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=Select any case and start typing to search by case name
MultiUserCasesPanel.cancelButton.text=Cancel
@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<Properties>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[0, 5]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[5, 5]"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,1,-112"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
<SubComponents>
<Container class="javax.swing.JScrollPane" name="caseTableScrollPane">
<Properties>
<Property name="horizontalScrollBarPolicy" type="int" value="31"/>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[0, 5]"/>
</Property>
<Property name="opaque" type="boolean" value="false"/>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[5, 5]"/>
</Property>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
<BorderConstraints direction="Center"/>
</Constraint>
</Constraints>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
</Container>
</SubComponents>
</Form>
@@ -0,0 +1,265 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2017-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.casemodule;
import java.lang.reflect.InvocationTargetException;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionListener;
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.io.IOException;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import javax.swing.SwingWorker;
import org.openide.explorer.ExplorerManager;
import org.openide.util.NbBundle;
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 LoadCaseListWorker 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_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 (user can unhide it)
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);
}
/**
* Get the path to the .aut file for the selected case.
*
* @return the full path to the selected case's .aut file
*/
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 LoadCaseListWorker();
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")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//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);
}// </editor-fold>//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 List of cases in a background thread
*/
private class LoadCaseListWorker extends SwingWorker<Void, Void> {
private List<CaseMetadata> cases;
/**
* Gets a list of the cases in the top level case folder
*
* @return List of cases.
*
* @throws CoordinationServiceException
*/
private List<CaseMetadata> getCases() throws CoordinationService.CoordinationServiceException {
List<CaseMetadata> caseList = new ArrayList<>();
List<String> nodeList = CoordinationService.getInstance().getNodeList(CoordinationService.CategoryNode.CASES);
for (String node : nodeList) {
Path casePath;
try {
casePath = Paths.get(node).toRealPath(LinkOption.NOFOLLOW_LINKS);
File caseFolder = casePath.toFile();
if (caseFolder.exists()) {
/*
* Search for '*.aut' files.
*/
File[] fileArray = caseFolder.listFiles();
if (fileArray == null) {
continue;
}
String autFilePath = null;
for (File file : fileArray) {
String name = file.getName().toLowerCase();
if (autFilePath == null && name.endsWith(".aut")) {
try {
caseList.add(new CaseMetadata(Paths.get(file.getAbsolutePath())));
} catch (CaseMetadata.CaseMetadataException ex) {
LOGGER.log(Level.SEVERE, String.format("Error reading case metadata file '%s'.", autFilePath), ex);
}
break;
}
}
}
} catch (IOException ignore) {
//if a path could not be resolved to a real path do add it to the caseList
}
}
return caseList;
}
@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);
});
}
}
}
@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2017 Basis Technology Corp.
* Copyright 2011-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -61,6 +61,11 @@ class CaseInformationPanel extends javax.swing.JPanel {
@Override
public void stateChanged(ChangeEvent e) {
tabbedPane.getSelectedComponent().setSize(tabbedPane.getSelectedComponent().getPreferredSize());
if (tabbedPane.getSelectedComponent() instanceof CasePropertiesPanel) {
editDetailsButton.setVisible(true);
} else {
editDetailsButton.setVisible(false);
}
}
});
}
@@ -1,442 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2017 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.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<MultiUserCase> getCases() throws CoordinationServiceException {
List<MultiUserCase> cases = new ArrayList<>();
List<String> 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<MultiUserCase> {
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<MultiUserCase> {
/**
* 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
}
}
@@ -1,10 +1,6 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.6" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<NonVisualComponents>
<Component class="javax.swing.ButtonGroup" name="rbGroupHistoryLength">
</Component>
</NonVisualComponents>
<Properties>
<Property name="name" type="java.lang.String" value="Completed Cases" noResource="true"/>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
@@ -26,30 +22,19 @@
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="103" groupAlignment="1" attributes="0">
<Component id="caseExplorerScrollPane" max="32767" attributes="0"/>
<Group type="102" attributes="0">
<EmptySpace min="-2" pref="4" max="-2" attributes="0"/>
<Component id="bnOpen" min="-2" pref="80" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="searchLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace pref="120" max="32767" attributes="0"/>
<Component id="bnOpenSingleUserCase" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="226" max="-2" attributes="0"/>
<Component id="bnOpen" linkSize="1" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="bnShowLog" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
<Component id="rbGroupLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="rbDays" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="rbWeeks" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="rbMonths" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
<Component id="panelFilter" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="14" max="-2" attributes="0"/>
<Component id="bnRefresh" min="-2" max="-2" attributes="0"/>
<Component id="cancelButton" linkSize="1" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="scrollPaneTable" max="32767" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
@@ -59,26 +44,15 @@
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace min="-2" pref="6" max="-2" attributes="0"/>
<Component id="scrollPaneTable" min="-2" pref="450" max="-2" attributes="0"/>
<Component id="caseExplorerScrollPane" min="-2" pref="450" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="103" groupAlignment="3" attributes="0">
<Component id="bnOpen" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="bnOpenSingleUserCase" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="bnShowLog" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="103" groupAlignment="1" attributes="0">
<Group type="103" alignment="1" groupAlignment="3" attributes="0">
<Component id="rbDays" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="rbWeeks" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="rbMonths" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="rbGroupLabel" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="panelFilter" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="bnRefresh" alignment="1" min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="cancelButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="bnOpen" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="bnOpenSingleUserCase" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="searchLabel" alignment="3" max="32767" attributes="0"/>
</Group>
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@@ -90,154 +64,65 @@
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="MultiUserCasesPanel.bnOpen.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[80, 23]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[80, 23]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[80, 23]"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="bnOpenActionPerformed"/>
</Events>
</Component>
<Container class="javax.swing.JScrollPane" name="scrollPaneTable">
<AuxValues>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JTable" name="casesTable">
<Properties>
<Property name="model" type="javax.swing.table.TableModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="caseTableModel" type="code"/>
</Property>
<Property name="rowHeight" type="int" value="20"/>
<Property name="selectionModel" type="javax.swing.ListSelectionModel" editor="org.netbeans.modules.form.editors2.JTableSelectionModelEditor">
<JTableSelectionModel selectionMode="0"/>
</Property>
</Properties>
<Events>
<EventHandler event="mouseClicked" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="casesTableMouseClicked"/>
</Events>
</Component>
</SubComponents>
</Container>
<Component class="javax.swing.JButton" name="bnRefresh">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="MultiUserCasesPanel.bnRefresh.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="bnRefreshActionPerformed"/>
</Events>
</Component>
<Container class="javax.swing.JPanel" name="panelFilter">
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="rbAllCases" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
<Component id="rbAllCases" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JRadioButton" name="rbAllCases">
<Properties>
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
<ComponentRef name="rbGroupHistoryLength"/>
</Property>
<Property name="selected" type="boolean" value="true"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="MultiUserCasesPanel.rbAllCases.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="itemStateChanged" listener="java.awt.event.ItemListener" parameters="java.awt.event.ItemEvent" handler="rbAllCasesItemStateChanged"/>
</Events>
</Component>
</SubComponents>
</Container>
<Component class="javax.swing.JButton" name="bnShowLog">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="MultiUserCasesPanel.bnShowLog.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="MultiUserCasesPanel.bnShowLog.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="bnShowLogActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JRadioButton" name="rbDays">
<Properties>
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
<ComponentRef name="rbGroupHistoryLength"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="MultiUserCasesPanel.rbDays.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="name" type="java.lang.String" value="" noResource="true"/>
</Properties>
<Events>
<EventHandler event="itemStateChanged" listener="java.awt.event.ItemListener" parameters="java.awt.event.ItemEvent" handler="rbDaysItemStateChanged"/>
</Events>
</Component>
<Component class="javax.swing.JRadioButton" name="rbWeeks">
<Properties>
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
<ComponentRef name="rbGroupHistoryLength"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="MultiUserCasesPanel.rbWeeks.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="itemStateChanged" listener="java.awt.event.ItemListener" parameters="java.awt.event.ItemEvent" handler="rbWeeksItemStateChanged"/>
</Events>
</Component>
<Component class="javax.swing.JRadioButton" name="rbMonths">
<Properties>
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
<ComponentRef name="rbGroupHistoryLength"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="MultiUserCasesPanel.rbMonths.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="itemStateChanged" listener="java.awt.event.ItemListener" parameters="java.awt.event.ItemEvent" handler="rbMonthsItemStateChanged"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="rbGroupLabel">
<Properties>
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
<Font name="Tahoma" size="12" style="0"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="MultiUserCasesPanel.rbGroupLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="bnOpenSingleUserCase">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="MultiUserCasesPanel.bnOpenSingleUserCase.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[156, 23]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[156, 23]"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="bnOpenSingleUserCaseActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="cancelButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="MultiUserCasesPanel.cancelButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[80, 23]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[80, 23]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[80, 23]"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cancelButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="searchLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="MultiUserCasesPanel.searchLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Container class="javax.swing.JScrollPane" name="caseExplorerScrollPane">
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
</Container>
</SubComponents>
</Form>
@@ -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,165 +154,80 @@ final class MultiUserCasesPanel extends javax.swing.JPanel {
// <editor-fold defaultstate="collapsed" desc="Generated Code">//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));
org.openide.awt.Mnemonics.setLocalizedText(bnOpen, org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "MultiUserCasesPanel.bnOpen.text")); // NOI18N
bnOpen.setEnabled(false);
bnOpen.setMaximumSize(new java.awt.Dimension(80, 23));
bnOpen.setMinimumSize(new java.awt.Dimension(80, 23));
bnOpen.setPreferredSize(new java.awt.Dimension(80, 23));
bnOpen.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
bnOpenActionPerformed(evt);
}
});
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.setMinimumSize(new java.awt.Dimension(156, 23));
bnOpenSingleUserCase.setPreferredSize(new java.awt.Dimension(156, 23));
bnOpenSingleUserCase.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
bnOpenSingleUserCaseActionPerformed(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(cancelButton, org.openide.util.NbBundle.getMessage(MultiUserCasesPanel.class, "MultiUserCasesPanel.cancelButton.text")); // NOI18N
cancelButton.setMaximumSize(new java.awt.Dimension(80, 23));
cancelButton.setMinimumSize(new java.awt.Dimension(80, 23));
cancelButton.setPreferredSize(new java.awt.Dimension(80, 23));
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(bnOpen, javax.swing.GroupLayout.PREFERRED_SIZE, 80, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(searchLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 120, Short.MAX_VALUE)
.addComponent(bnOpenSingleUserCase, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(226, 226, 226)
.addComponent(bnOpen, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, 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, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))
.addContainerGap())
);
layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {bnOpen, cancelButton});
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, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(bnOpen, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(bnOpenSingleUserCase, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(searchLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addContainerGap())
);
}// </editor-fold>//GEN-END:initComponents
@@ -513,129 +237,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<Void, Void> {
private List<MultiUserCase> 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();
}
}
}
@@ -0,0 +1,232 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2017-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.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.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.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 caseList the list of CaseMetadata objects representing the cases
*/
MultiUserNode(List<CaseMetadata> caseList) {
super(Children.create(new MultiUserNodeChildren(caseList), true));
}
static class MultiUserNodeChildren extends ChildFactory<CaseMetadata> {
private final List<CaseMetadata> caseList;
MultiUserNodeChildren(List<CaseMetadata> caseList) {
this.caseList = caseList;
}
@Override
protected boolean createKeys(List<CaseMetadata> list) {
if (caseList != null && caseList.size() > 0) {
list.addAll(caseList);
}
return true;
}
@Override
protected Node createNodeForKey(CaseMetadata 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 Path caseLogFilePath;
MultiUserCaseNode(CaseMetadata multiUserCase) {
super(Children.LEAF);
caseName = multiUserCase.getCaseDisplayName();
caseCreatedDate = multiUserCase.getCreatedDate();
super.setName(caseName);
setName(caseName);
setDisplayName(caseName);
caseMetadataFilePath = multiUserCase.getFilePath().toString();
caseLogFilePath = Paths.get(multiUserCase.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);
}
@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_metadataFilePath(), Bundle.CaseNode_column_metadataFilePath(), Bundle.CaseNode_column_metadataFilePath(),
caseMetadataFilePath));
return s;
}
@Override
public Action[] getActions(boolean context) {
List<Action> 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.
}
}
}
@@ -2172,7 +2172,7 @@ public abstract class AbstractSqlEamDb implements EamDb {
}
CorrelationAttributeInstance eamArtifactInstance = new CorrelationAttributeInstance(
new CorrelationCase(resultSet.getInt("case_id"), resultSet.getString("case_uid"), resultSet.getString("case_name")),
new CorrelationDataSource(-1, resultSet.getInt("case_id"), resultSet.getString("device_id"), resultSet.getString("name")),
new CorrelationDataSource(resultSet.getInt("case_id"), -1, resultSet.getString("device_id"), resultSet.getString("name")),
resultSet.getString("file_path"),
resultSet.getString("comment"),
TskData.FileKnown.valueOf(resultSet.getByte("known_status"))
@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2014-2017 Basis Technology Corp.
* Copyright 2014-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -67,7 +67,9 @@ public final class UserPreferences {
private static final String APP_NAME = "AppName";
public static final String SETTINGS_PROPERTIES = "AutoIngest";
private static final String MODE = "AutopsyMode"; // NON-NLS
private static final String MAX_NUM_OF_LOG_FILE = "MaximumNumberOfLogFiles";
private static final int LOG_FILE_NUM_INT = 10;
// Prevent instantiation.
private UserPreferences() {
}
@@ -369,4 +371,26 @@ public final class UserPreferences {
preferences.put(APP_NAME, name);
}
/**
* get the maximum number of log files to save
* @return Number of log files
*/
public static int getLogFileCount() {
return preferences.getInt(MAX_NUM_OF_LOG_FILE, LOG_FILE_NUM_INT);
}
/**
* get the default number of log files to save
* @return LOG_FILE_COUNT
*/
public static int getDefaultLogFileCount() {
return LOG_FILE_NUM_INT;
}
/**
* Set the maximum number of log files to save
* @param count number of log files
*/
public static void setLogFileCount(int count) {
preferences.putInt(MAX_NUM_OF_LOG_FILE, count);
}
}
@@ -198,10 +198,10 @@
<file name="org-openide-actions-ToolsAction.shadow_hidden"/>
<file name="org-sleuthkit-autopsy-filesearch-FileSearchAction.shadow">
<attr name="originalFile" stringvalue="Actions/Tools/org-sleuthkit-autopsy-filesearch-FileSearchAction.instance"/>
<attr name="position" intvalue="200"/>
<attr name="position" intvalue="104"/>
</file>
<folder name="RunIngestModules">
<attr name="position" intvalue="201"/>
<attr name="position" intvalue="105"/>
<attr name="SystemFileSystem.localizingBundle" stringvalue="org.sleuthkit.autopsy.ingest.Bundle"/>
<file name="org-sleuthkit-autopsy-ingest-RunIngestAction.shadow">
<attr name="originalFile" stringvalue="Actions/Tools/org-sleuthkit-autopsy-ingest-RunIngestAction.instance"/>
@@ -213,7 +213,7 @@
</file>-->
<file name="org-sleuthkit-autopsy-report-ReportWizardAction-separatorAfter.instance">
<attr name="instanceClass" stringvalue="javax.swing.JSeparator"/>
<attr name="position" intvalue="104"/>
<attr name="position" intvalue="199"/>
</file>
<!--<file name="Separator1.instance_hidden"/>
<file name="Separator3.instance_hidden"/>-->
@@ -24,7 +24,7 @@
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jScrollPane1" alignment="0" max="32767" attributes="0"/>
<Component id="jScrollPane1" alignment="0" pref="1010" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
@@ -44,18 +44,26 @@
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Container class="javax.swing.JPanel" name="jPanel1">
<Properties>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[671, 488]"/>
</Property>
</Properties>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<EmptySpace min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="103" groupAlignment="1" attributes="0">
<Component id="logoPanel" max="32767" attributes="0"/>
<Component id="viewPanel" alignment="0" max="32767" attributes="0"/>
<Component id="runtimePanel" alignment="1" max="32767" attributes="0"/>
<Group type="102" attributes="0">
<Component id="viewPanel" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="runtimePanel" max="32767" attributes="0"/>
</Group>
</Group>
<EmptySpace min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@@ -63,10 +71,11 @@
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
<Component id="viewPanel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="runtimePanel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Component id="viewPanel" max="32767" attributes="0"/>
<Component id="runtimePanel" max="32767" attributes="0"/>
</Group>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="logoPanel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
@@ -245,7 +254,7 @@
<Component id="viewsHideSlackCB" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="useLocalTimeRB" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="32767" attributes="0"/>
<EmptySpace pref="158" max="32767" attributes="0"/>
</Group>
</Group>
</Group>
@@ -436,28 +445,43 @@
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Component id="maxMemoryLabel" min="-2" pref="114" max="-2" attributes="0"/>
<Component id="totalMemoryLabel" pref="0" max="32767" attributes="0"/>
</Group>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Component id="systemMemoryTotal" max="32767" attributes="0"/>
<Component id="memField" pref="37" max="32767" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="maxMemoryUnitsLabel" min="-2" pref="17" max="-2" attributes="0"/>
<Component id="maxMemoryUnitsLabel1" min="-2" pref="17" max="-2" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Component id="totalMemoryLabel" min="-2" pref="114" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="systemMemoryTotal" min="-2" pref="37" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Component id="maxMemoryUnitsLabel1" min="-2" pref="17" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="restartNecessaryWarning" pref="333" max="32767" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<Component id="maxMemoryUnitsLabel" min="-2" pref="17" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="memFieldValidationLabel" min="-2" pref="263" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</Group>
</Group>
<Group type="102" attributes="0">
<Component id="maxMemoryLabel" min="-2" pref="114" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="memField" min="-2" pref="37" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<Component id="maxLogFileCount" min="-2" pref="114" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="logFileCount" min="-2" pref="37" max="-2" attributes="0"/>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Component id="logNumAlert" max="32767" attributes="0"/>
</Group>
</Group>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="restartNecessaryWarning" pref="417" max="32767" attributes="0"/>
<Component id="memFieldValidationLabel" max="32767" attributes="0"/>
</Group>
<EmptySpace max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@@ -466,22 +490,29 @@
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Component id="totalMemoryLabel" min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="maxMemoryUnitsLabel" alignment="3" min="-2" pref="20" max="-2" attributes="0"/>
<Component id="memField" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="memFieldValidationLabel" alignment="0" max="32767" attributes="0"/>
<Component id="maxMemoryLabel" alignment="0" max="32767" attributes="0"/>
</Group>
<EmptySpace type="unrelated" min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Group type="103" alignment="0" groupAlignment="3" attributes="0">
<Component id="restartNecessaryWarning" alignment="3" min="-2" pref="20" max="-2" attributes="0"/>
<Component id="maxMemoryUnitsLabel1" alignment="3" min="-2" pref="20" max="-2" attributes="0"/>
</Group>
<Component id="totalMemoryLabel" alignment="0" max="32767" attributes="0"/>
<Component id="systemMemoryTotal" alignment="0" max="32767" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="1" attributes="0">
<Group type="103" groupAlignment="3" attributes="0">
<Component id="maxMemoryLabel" alignment="3" min="-2" pref="20" max="-2" attributes="0"/>
<Component id="memField" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="maxMemoryUnitsLabel" alignment="3" min="-2" pref="20" max="-2" attributes="0"/>
</Group>
<Component id="memFieldValidationLabel" min="-2" pref="17" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="maxLogFileCount" alignment="3" min="-2" pref="19" max="-2" attributes="0"/>
<Component id="logFileCount" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="logNumAlert" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@@ -545,6 +576,40 @@
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="maxLogFileCount">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.maxLogFileCount.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="logFileCount">
<Properties>
<Property name="horizontalAlignment" type="int" value="11"/>
</Properties>
<Events>
<EventHandler event="keyReleased" listener="java.awt.event.KeyListener" parameters="java.awt.event.KeyEvent" handler="logFileCountKeyReleased"/>
</Events>
</Component>
<Component class="javax.swing.JTextField" name="logNumAlert">
<Properties>
<Property name="editable" type="boolean" value="false"/>
<Property name="font" type="java.awt.Font" editor="org.netbeans.modules.form.editors2.FontEditor">
<FontInfo relative="true">
<Font bold="false" component="logNumAlert" property="font" relativeSize="false" size="11"/>
</FontInfo>
</Property>
<Property name="foreground" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
<Color blue="0" green="0" red="ff" type="rgb"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.logNumAlert.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="null"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Container>
</SubComponents>
@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2017 Basis Technology Corp.
* Copyright 2011-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -73,7 +73,9 @@ import org.sleuthkit.autopsy.report.ReportBranding;
"AutopsyOptionsPanel.browseLogosButton.text=Browse",
"AutopsyOptionsPanel.agencyLogoPathFieldValidationLabel.invalidPath.text=Path is not valid.",
"AutopsyOptionsPanel.agencyLogoPathFieldValidationLabel.invalidImageSpecified.text=Invalid image file specified.",
"AutopsyOptionsPanel.agencyLogoPathFieldValidationLabel.pathNotSet.text=Agency logo path must be set."
"AutopsyOptionsPanel.agencyLogoPathFieldValidationLabel.pathNotSet.text=Agency logo path must be set.",
"AutopsyOptionsPanel.maxLogFileCount.text=Maximum Log Files:",
"AutopsyOptionsPanel.logNumAlert.invalidInput.text=A positive integer is required here."
})
final class AutopsyOptionsPanel extends javax.swing.JPanel {
@@ -110,6 +112,7 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
textFieldListener = new TextFieldListener();
agencyLogoPathField.getDocument().addDocumentListener(textFieldListener);
logFileCount.setText(String.valueOf(UserPreferences.getLogFileCount()));
}
/**
@@ -309,6 +312,7 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
specifyLogoRB.setSelected(!useDefault);
agencyLogoPathField.setEnabled(!useDefault);
browseLogosButton.setEnabled(!useDefault);
logFileCount.setText(String.valueOf(UserPreferences.getLogFileCount()));
try {
updateAgencyLogo(path);
} catch (IOException ex) {
@@ -363,6 +367,7 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
UserPreferences.setHideSlackFilesInDataSourcesTree(dataSourcesHideSlackCB.isSelected());
UserPreferences.setHideSlackFilesInViewsTree(viewsHideSlackCB.isSelected());
UserPreferences.setDisplayTimesInLocalTime(useLocalTimeRB.isSelected());
UserPreferences.setLogFileCount(Integer.parseInt(logFileCount.getText()));
if (!agencyLogoPathField.getText().isEmpty()) {
File file = new File(agencyLogoPathField.getText());
if (file.exists()) {
@@ -394,6 +399,9 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
if (!isMemFieldValid()) {
valid = false;
}
if (!isLogNumFieldValid()) {
valid = false;
}
return valid;
}
@@ -476,6 +484,26 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
return true;
}
/**
* Check if the logFileCount field is valid.
*
* @return true if the logFileCount is valid false if it is not
*/
private boolean isLogNumFieldValid() {
String count = logFileCount.getText();
logNumAlert.setText("");
try {
int count_num = Integer.parseInt(count);
if (count_num < 1) {
logNumAlert.setText(Bundle.AutopsyOptionsPanel_logNumAlert_invalidInput_text());
return false;
}
} catch (NumberFormatException e) {
logNumAlert.setText(Bundle.AutopsyOptionsPanel_logNumAlert_invalidInput_text());
return false;
}
return true;
}
/**
* Listens for registered text fields that have changed and fires a
* PropertyChangeEvent accordingly.
@@ -540,9 +568,14 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
memField = new javax.swing.JTextField();
memFieldValidationLabel = new javax.swing.JLabel();
maxMemoryUnitsLabel1 = new javax.swing.JLabel();
maxLogFileCount = new javax.swing.JLabel();
logFileCount = new javax.swing.JTextField();
logNumAlert = new javax.swing.JTextField();
jScrollPane1.setBorder(null);
jPanel1.setPreferredSize(new java.awt.Dimension(671, 488));
logoPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.logoPanel.border.title"))); // NOI18N
agencyLogoPathField.setText(org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.agencyLogoPathField.text")); // NOI18N
@@ -712,7 +745,7 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
.addComponent(dataSourcesHideSlackCB)
.addComponent(viewsHideSlackCB)
.addComponent(useLocalTimeRB))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))))
.addContainerGap(158, Short.MAX_VALUE))))
.addGroup(viewPanelLayout.createSequentialGroup()
.addGroup(viewPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jLabelHideSlackFiles)
@@ -774,68 +807,103 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
org.openide.awt.Mnemonics.setLocalizedText(maxMemoryUnitsLabel1, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.maxMemoryUnitsLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(maxLogFileCount, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.maxLogFileCount.text")); // NOI18N
logFileCount.setHorizontalAlignment(javax.swing.JTextField.TRAILING);
logFileCount.addKeyListener(new java.awt.event.KeyAdapter() {
public void keyReleased(java.awt.event.KeyEvent evt) {
logFileCountKeyReleased(evt);
}
});
logNumAlert.setEditable(false);
logNumAlert.setFont(logNumAlert.getFont().deriveFont(logNumAlert.getFont().getStyle() & ~java.awt.Font.BOLD, 11));
logNumAlert.setForeground(new java.awt.Color(255, 0, 0));
logNumAlert.setText(org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.logNumAlert.text")); // NOI18N
logNumAlert.setBorder(null);
javax.swing.GroupLayout runtimePanelLayout = new javax.swing.GroupLayout(runtimePanel);
runtimePanel.setLayout(runtimePanelLayout);
runtimePanelLayout.setHorizontalGroup(
runtimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(runtimePanelLayout.createSequentialGroup()
.addContainerGap()
.addGroup(runtimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addComponent(maxMemoryLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 114, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(totalMemoryLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(runtimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addComponent(systemMemoryTotal, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(memField, javax.swing.GroupLayout.DEFAULT_SIZE, 37, Short.MAX_VALUE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(runtimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(maxMemoryUnitsLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 17, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(maxMemoryUnitsLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 17, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGap(18, 18, 18)
.addGroup(runtimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(restartNecessaryWarning, javax.swing.GroupLayout.DEFAULT_SIZE, 417, Short.MAX_VALUE)
.addComponent(memFieldValidationLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addGroup(runtimePanelLayout.createSequentialGroup()
.addComponent(totalMemoryLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 114, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(systemMemoryTotal, javax.swing.GroupLayout.PREFERRED_SIZE, 37, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(2, 2, 2)
.addGroup(runtimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(runtimePanelLayout.createSequentialGroup()
.addComponent(maxMemoryUnitsLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 17, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(restartNecessaryWarning, javax.swing.GroupLayout.DEFAULT_SIZE, 333, Short.MAX_VALUE))
.addGroup(runtimePanelLayout.createSequentialGroup()
.addComponent(maxMemoryUnitsLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 17, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(memFieldValidationLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 263, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(0, 0, Short.MAX_VALUE))))
.addGroup(runtimePanelLayout.createSequentialGroup()
.addComponent(maxMemoryLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 114, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(memField, javax.swing.GroupLayout.PREFERRED_SIZE, 37, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(0, 0, Short.MAX_VALUE))
.addGroup(runtimePanelLayout.createSequentialGroup()
.addComponent(maxLogFileCount, javax.swing.GroupLayout.PREFERRED_SIZE, 114, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(logFileCount, javax.swing.GroupLayout.PREFERRED_SIZE, 37, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(18, 18, 18)
.addComponent(logNumAlert)))
.addContainerGap())
);
runtimePanelLayout.setVerticalGroup(
runtimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(runtimePanelLayout.createSequentialGroup()
.addContainerGap()
.addGroup(runtimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addGroup(runtimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(maxMemoryUnitsLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(memField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(memFieldValidationLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(maxMemoryLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(runtimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addComponent(totalMemoryLabel)
.addGroup(runtimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(restartNecessaryWarning, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(maxMemoryUnitsLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(totalMemoryLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(systemMemoryTotal, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
.addComponent(systemMemoryTotal, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(runtimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addGroup(runtimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(maxMemoryLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(memField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(maxMemoryUnitsLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(memFieldValidationLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 17, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(runtimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(maxLogFileCount, javax.swing.GroupLayout.PREFERRED_SIZE, 19, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(logFileCount, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(logNumAlert, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
jPanel1.setLayout(jPanel1Layout);
jPanel1Layout.setHorizontalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel1Layout.createSequentialGroup()
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
.addContainerGap()
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(logoPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(viewPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(runtimePanel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addGroup(jPanel1Layout.createSequentialGroup()
.addComponent(viewPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(runtimePanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
.addContainerGap())
);
jPanel1Layout.setVerticalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel1Layout.createSequentialGroup()
.addGap(0, 0, 0)
.addComponent(viewPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(runtimePanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addComponent(viewPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(runtimePanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(logoPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap())
);
@@ -846,7 +914,7 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jScrollPane1)
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 1010, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
@@ -854,60 +922,14 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
);
}// </editor-fold>//GEN-END:initComponents
private void useBestViewerRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_useBestViewerRBActionPerformed
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}//GEN-LAST:event_useBestViewerRBActionPerformed
private void keepCurrentViewerRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_keepCurrentViewerRBActionPerformed
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}//GEN-LAST:event_keepCurrentViewerRBActionPerformed
private void dataSourcesHideKnownCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_dataSourcesHideKnownCBActionPerformed
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}//GEN-LAST:event_dataSourcesHideKnownCBActionPerformed
private void viewsHideKnownCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_viewsHideKnownCBActionPerformed
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}//GEN-LAST:event_viewsHideKnownCBActionPerformed
private void useLocalTimeRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_useLocalTimeRBActionPerformed
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}//GEN-LAST:event_useLocalTimeRBActionPerformed
private void useGMTTimeRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_useGMTTimeRBActionPerformed
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}//GEN-LAST:event_useGMTTimeRBActionPerformed
private void dataSourcesHideSlackCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_dataSourcesHideSlackCBActionPerformed
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}//GEN-LAST:event_dataSourcesHideSlackCBActionPerformed
private void viewsHideSlackCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_viewsHideSlackCBActionPerformed
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}//GEN-LAST:event_viewsHideSlackCBActionPerformed
private void browseLogosButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseLogosButtonActionPerformed
String oldLogoPath = agencyLogoPathField.getText();
int returnState = fileChooser.showOpenDialog(this);
if (returnState == JFileChooser.APPROVE_OPTION) {
String path = fileChooser.getSelectedFile().getPath();
try {
updateAgencyLogo(path);
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
} catch (IOException | IndexOutOfBoundsException ex) {
JOptionPane.showMessageDialog(null,
NbBundle.getMessage(this.getClass(),
"AutopsyOptionsPanel.invalidImageFile.msg"),
NbBundle.getMessage(this.getClass(), "AutopsyOptionsPanel.invalidImageFile.title"),
JOptionPane.ERROR_MESSAGE);
try {
updateAgencyLogo(oldLogoPath); //restore previous setting if new one is invalid
} catch (IOException ex1) {
LOGGER.log(Level.WARNING, "Error loading image from previously saved agency logo path", ex1);
}
}
private void logFileCountKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_logFileCountKeyReleased
String count = logFileCount.getText();
if (count.equals(String.valueOf(UserPreferences.getDefaultLogFileCount()))) {
//if it is still the default value don't fire change
return;
}
}//GEN-LAST:event_browseLogosButtonActionPerformed
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}//GEN-LAST:event_logFileCountKeyReleased
private void memFieldKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_memFieldKeyReleased
String memText = memField.getText();
@@ -918,17 +940,37 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}//GEN-LAST:event_memFieldKeyReleased
private void defaultLogoRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_defaultLogoRBActionPerformed
agencyLogoPathField.setEnabled(false);
browseLogosButton.setEnabled(false);
try {
updateAgencyLogo("");
} catch (IOException ex) {
// This should never happen since we're not reading from a file.
LOGGER.log(Level.SEVERE, "Unexpected error occurred while updating the agency logo.", ex);
}
private void useGMTTimeRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_useGMTTimeRBActionPerformed
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}//GEN-LAST:event_defaultLogoRBActionPerformed
}//GEN-LAST:event_useGMTTimeRBActionPerformed
private void useLocalTimeRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_useLocalTimeRBActionPerformed
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}//GEN-LAST:event_useLocalTimeRBActionPerformed
private void viewsHideSlackCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_viewsHideSlackCBActionPerformed
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}//GEN-LAST:event_viewsHideSlackCBActionPerformed
private void dataSourcesHideSlackCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_dataSourcesHideSlackCBActionPerformed
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}//GEN-LAST:event_dataSourcesHideSlackCBActionPerformed
private void viewsHideKnownCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_viewsHideKnownCBActionPerformed
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}//GEN-LAST:event_viewsHideKnownCBActionPerformed
private void dataSourcesHideKnownCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_dataSourcesHideKnownCBActionPerformed
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}//GEN-LAST:event_dataSourcesHideKnownCBActionPerformed
private void keepCurrentViewerRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_keepCurrentViewerRBActionPerformed
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}//GEN-LAST:event_keepCurrentViewerRBActionPerformed
private void useBestViewerRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_useBestViewerRBActionPerformed
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}//GEN-LAST:event_useBestViewerRBActionPerformed
private void specifyLogoRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_specifyLogoRBActionPerformed
agencyLogoPathField.setEnabled(true);
@@ -946,6 +988,41 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}//GEN-LAST:event_specifyLogoRBActionPerformed
private void defaultLogoRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_defaultLogoRBActionPerformed
agencyLogoPathField.setEnabled(false);
browseLogosButton.setEnabled(false);
try {
updateAgencyLogo("");
} catch (IOException ex) {
// This should never happen since we're not reading from a file.
LOGGER.log(Level.SEVERE, "Unexpected error occurred while updating the agency logo.", ex);
}
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}//GEN-LAST:event_defaultLogoRBActionPerformed
private void browseLogosButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseLogosButtonActionPerformed
String oldLogoPath = agencyLogoPathField.getText();
int returnState = fileChooser.showOpenDialog(this);
if (returnState == JFileChooser.APPROVE_OPTION) {
String path = fileChooser.getSelectedFile().getPath();
try {
updateAgencyLogo(path);
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
} catch (IOException | IndexOutOfBoundsException ex) {
JOptionPane.showMessageDialog(null,
NbBundle.getMessage(this.getClass(),
"AutopsyOptionsPanel.invalidImageFile.msg"),
NbBundle.getMessage(this.getClass(), "AutopsyOptionsPanel.invalidImageFile.title"),
JOptionPane.ERROR_MESSAGE);
try {
updateAgencyLogo(oldLogoPath); //restore previous setting if new one is invalid
} catch (IOException ex1) {
LOGGER.log(Level.WARNING, "Error loading image from previously saved agency logo path", ex1);
}
}
}
}//GEN-LAST:event_browseLogosButtonActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JTextField agencyLogoPathField;
private javax.swing.JLabel agencyLogoPathFieldValidationLabel;
@@ -963,8 +1040,11 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
private javax.swing.JPanel jPanel1;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JRadioButton keepCurrentViewerRB;
private javax.swing.JTextField logFileCount;
private javax.swing.JTextField logNumAlert;
private javax.swing.JPanel logoPanel;
private javax.swing.ButtonGroup logoSourceButtonGroup;
private javax.swing.JLabel maxLogFileCount;
private javax.swing.JLabel maxMemoryLabel;
private javax.swing.JLabel maxMemoryUnitsLabel;
private javax.swing.JLabel maxMemoryUnitsLabel1;
@@ -200,3 +200,4 @@ CriterionChooser.ascendingRadio.text=\u25b2 Ascending\n
CriterionChooser.removeButton.text=Remove
CriterionChooser.descendingRadio.text=\u25bc Descending
AutopsyOptionsPanel.agencyLogoPathFieldValidationLabel.text=
AutopsyOptionsPanel.logNumAlert.text=
@@ -151,7 +151,7 @@ public abstract class MediaViewVideoPanel extends JPanel implements FrameCapture
if (AUDIO_EXTENSIONS.contains("." + extension) || getExtensionsList().contains("." + extension)) {
SortedSet<String> mimeTypes = new TreeSet<>(getMimeTypes());
try {
String mimeType = new FileTypeDetector().detectMIMEType(file);
String mimeType = new FileTypeDetector().getMIMEType(file);
return mimeTypes.contains(mimeType);
} catch (FileTypeDetector.FileTypeDetectorInitException ex) {
logger.log(Level.WARNING, "Failed to look up mimetype for " + file.getName() + " using FileTypeDetector. Fallingback on AbstractFile.isMimeType", ex);
@@ -263,7 +263,7 @@ public class ImageUtils {
return true;
} else {
try {
String mimeType = getFileTypeDetector().detectMIMEType(file);
String mimeType = getFileTypeDetector().getMIMEType(file);
if (StringUtils.isNotBlank(mimeTypePrefix) && mimeType.startsWith(mimeTypePrefix)) {
return true;
}
@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2012-2015 Basis Technology Corp.
* Copyright 2012-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -24,68 +24,36 @@ import java.util.logging.FileHandler;
import java.util.logging.Formatter;
import java.util.logging.Handler;
import java.sql.Timestamp;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.LogRecord;
import org.sleuthkit.autopsy.core.UserPreferences;
/**
* Autopsy specialization of the Java Logger class with custom file handlers.
* Autopsy specialization of the Java Logger class with a custom file handler.
* Note that the custom loggers are not obtained from the global log manager.
*/
public final class Logger extends java.util.logging.Logger {
private static final String LOG_ENCODING = PlatformUtil.getLogFileEncoding();
private static final int LOG_SIZE = 0; // In bytes, zero is unlimited
private static final int LOG_FILE_COUNT = 10;
private static final String LOG_WITHOUT_STACK_TRACES = "autopsy.log"; //NON-NLS
private static final String LOG_WITH_STACK_TRACES = "autopsy_traces.log"; //NON-NLS
private static final String LOG_FILE_NAME = "autopsy.log"; //NON-NLS
private static final Map<String, Logger> namesToLoggers = new HashMap<>();
private static final Handler consoleHandler = new java.util.logging.ConsoleHandler();
private static FileHandler userFriendlyHandler = createFileHandlerWithoutTraces(PlatformUtil.getLogDirectory());
private static FileHandler developerFriendlyHandler = createFileHandlerWithTraces(PlatformUtil.getLogDirectory());
/**
* Creates a custom file handler with a custom message formatter that does
* not include stack traces.
*
* @param logDirectory The directory where the log files should reside.
*
* @return A custom file handler.
*/
private static FileHandler createFileHandlerWithoutTraces(String logDirectory) {
String logFilePath = Paths.get(logDirectory, LOG_WITHOUT_STACK_TRACES).toString();
try {
FileHandler fileHandler = new FileHandler(logFilePath, LOG_SIZE, LOG_FILE_COUNT);
fileHandler.setEncoding(LOG_ENCODING);
fileHandler.setFormatter(new Formatter() {
@Override
public String format(LogRecord record) {
return (new Date(record.getMillis())).toString() + " "
+ record.getSourceClassName() + " "
+ record.getSourceMethodName() + "\n"
+ record.getLevel() + ": "
+ this.formatMessage(record) + "\n";
}
});
return fileHandler;
} catch (IOException ex) {
throw new RuntimeException(String.format("Error initializing file handler for %s", logFilePath), ex); //NON-NLS
}
}
private static FileHandler logFileHandler = createFileHandlerWithTraces(PlatformUtil.getLogDirectory());
/**
* Creates a custom file handler with a custom message formatter that
* incldues stack traces.
* includes stack traces.
*
* @param logDirectory The directory where the log files should reside.
*
* @return A custom file handler.
*/
private static FileHandler createFileHandlerWithTraces(String logDirectory) {
String logFilePath = Paths.get(logDirectory, LOG_WITH_STACK_TRACES).toString();
String logFilePath = Paths.get(logDirectory, LOG_FILE_NAME).toString();
try {
FileHandler fileHandler = new FileHandler(logFilePath, LOG_SIZE, LOG_FILE_COUNT);
FileHandler fileHandler = new FileHandler(logFilePath, LOG_SIZE, UserPreferences.getLogFileCount());
fileHandler.setEncoding(LOG_ENCODING);
fileHandler.setFormatter(new Formatter() {
@Override
@@ -120,7 +88,7 @@ public final class Logger extends java.util.logging.Logger {
*/
synchronized public static void setLogDirectory(String directoryPath) {
/*
* Create file handlers for the new directory and swap them into all of
* Create a file handler for the new directory and swap it into all of
* the existing loggers using thread-safe Logger methods. The new
* handlers are added before the old handlers so that no messages will
* be lost, but this makes it possible for log messages to be written
@@ -128,25 +96,20 @@ public final class Logger extends java.util.logging.Logger {
* add/remove handler calls (currently, the base class handlers
* collection is a CopyOnWriteArrayList).
*/
FileHandler newUserFriendlyHandler = createFileHandlerWithoutTraces(directoryPath);
FileHandler newDeveloperFriendlyHandler = createFileHandlerWithTraces(directoryPath);
FileHandler newFileHandler = createFileHandlerWithTraces(directoryPath);
for (Logger logger : namesToLoggers.values()) {
logger.addHandler(newUserFriendlyHandler);
logger.addHandler(newDeveloperFriendlyHandler);
logger.removeHandler(userFriendlyHandler);
logger.removeHandler(userFriendlyHandler);
logger.addHandler(newFileHandler);
logger.removeHandler(logFileHandler);
}
/*
* Close the old file handlers and save references to the new handlers
* Close the old file handler and save reference to the new handler
* so they can be added to any new loggers. This swap is why this method
* and the two overloads of getLogger() are synchronized, serializing
* access to userFriendlyHandler and developerFriendlyHandler.
* access to logFileHandler.
*/
userFriendlyHandler.close();
userFriendlyHandler = newUserFriendlyHandler;
developerFriendlyHandler.close();
developerFriendlyHandler = newDeveloperFriendlyHandler;
logFileHandler.close();
logFileHandler = newFileHandler;
}
/**
@@ -178,8 +141,7 @@ public final class Logger extends java.util.logging.Logger {
synchronized public static Logger getLogger(String name, String resourceBundleName) {
if (!namesToLoggers.containsKey(name)) {
Logger logger = new Logger(name, resourceBundleName);
logger.addHandler(userFriendlyHandler);
logger.addHandler(developerFriendlyHandler);
logger.addHandler(logFileHandler);
namesToLoggers.put(name, logger);
}
return namesToLoggers.get(name);
@@ -41,7 +41,7 @@ public interface DisplayableItemNodeVisitor<T> {
T visit(LocalFileNode dfn);
T visit(VirtualDirectoryNode ldn);
T visit(LocalDirectoryNode ldn);
T visit(DirectoryNode dn);
@@ -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.
@@ -0,0 +1,284 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.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 <appName>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<Void, Void> {
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
}
}
@@ -0,0 +1,163 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JDialogFormInfo">
<Properties>
<Property name="defaultCloseOperation" type="int" value="2"/>
</Properties>
<SyntheticProperties>
<SyntheticProperty name="formSizePolicy" type="int" value="1"/>
<SyntheticProperty name="generateCenter" type="boolean" value="false"/>
</SyntheticProperties>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="bnRefresh" pref="112" max="32767" attributes="0"/>
<EmptySpace pref="48" max="32767" attributes="0"/>
<Component id="bnOk" min="-2" pref="101" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="bnCancel" min="-2" pref="101" max="-2" attributes="0"/>
</Group>
<Component id="jScrollPane1" alignment="0" pref="0" max="32767" attributes="0"/>
<Component id="jLabel1" alignment="0" max="32767" attributes="0"/>
<Component id="jSeparator1" alignment="0" max="32767" attributes="0"/>
<Component id="errorLabel" alignment="0" max="32767" attributes="0"/>
<Component id="jScrollPane2" max="32767" attributes="0"/>
</Group>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="jScrollPane2" min="-2" pref="107" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="jSeparator1" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="jLabel1" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="jScrollPane1" min="-2" pref="112" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="bnRefresh" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="bnCancel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="bnOk" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Component id="errorLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JScrollPane" name="jScrollPane1">
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JTable" name="diskTable">
<Properties>
<Property name="model" type="javax.swing.table.TableModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="model" type="code"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Container>
<Component class="javax.swing.JLabel" name="jLabel1">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/livetriage/Bundle.properties" key="SelectDriveDialog.jLabel1.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="bnRefresh">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/livetriage/Bundle.properties" key="SelectDriveDialog.bnRefresh.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="bnRefreshActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="bnOk">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/livetriage/Bundle.properties" key="SelectDriveDialog.bnOk.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="bnOkActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="errorLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/livetriage/Bundle.properties" key="SelectDriveDialog.errorLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JSeparator" name="jSeparator1">
</Component>
<Component class="javax.swing.JButton" name="bnCancel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/livetriage/Bundle.properties" key="SelectDriveDialog.bnCancel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="bnCancelActionPerformed"/>
</Events>
</Component>
<Container class="javax.swing.JScrollPane" name="jScrollPane2">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="null"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JTextArea" name="jTextArea1">
<Properties>
<Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
<Color blue="f0" green="f0" red="f0" type="rgb"/>
</Property>
<Property name="columns" type="int" value="20"/>
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
<Font name="Tahoma" size="11" style="0"/>
</Property>
<Property name="rows" type="int" value="5"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/livetriage/Bundle.properties" key="SelectDriveDialog.jTextArea1.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="null"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Form>
@@ -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<LocalDisk> 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")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//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();
}// </editor-fold>//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<Object, Void> {
private final Logger logger = Logger.getLogger(LocalDiskThread.class.getName());
private List<LocalDisk> 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();
}
}
}
}
@@ -135,7 +135,7 @@ class MSOfficeEmbeddedContentExtractor {
* supported. Else it returns false.
*/
boolean isContentExtractionSupported(AbstractFile abstractFile) {
String abstractFileMimeType = fileTypeDetector.detectMIMEType(abstractFile);
String abstractFileMimeType = fileTypeDetector.getMIMEType(abstractFile);
for (SupportedExtractionFormats s : SupportedExtractionFormats.values()) {
if (s.toString().equals(abstractFileMimeType)) {
abstractFileExtractionFormat = s;
@@ -139,7 +139,7 @@ class SevenZipExtractor {
* supported. Else it returns false.
*/
boolean isSevenZipExtractionSupported(AbstractFile abstractFile) {
String abstractFileMimeType = fileTypeDetector.detectMIMEType(abstractFile);
String abstractFileMimeType = fileTypeDetector.getMIMEType(abstractFile);
for (SupportedArchiveExtractionFormats s : SupportedArchiveExtractionFormats.values()) {
if (s.toString().equals(abstractFileMimeType)) {
return true;
@@ -187,7 +187,7 @@ final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter
/*
* Qualify the MIME type.
*/
String mimeType = fileTypeDetector.detectMIMEType(file);
String mimeType = fileTypeDetector.getMIMEType(file);
if (mimeType.equals("application/octet-stream")) {
possiblyEncrypted = true;
}
@@ -250,7 +250,7 @@ public final class ExifParserFileIngestModule implements FileIngestModule {
* @return true if to be processed
*/
private boolean parsableFormat(AbstractFile f) {
String mimeType = fileTypeDetector.detectMIMEType(f);
String mimeType = fileTypeDetector.getMIMEType(f);
return supportedMimeTypes.contains(mimeType);
}
@@ -169,7 +169,7 @@ public class FileExtMismatchIngestModule implements FileIngestModule {
if (settings.skipFilesWithNoExtension() && currActualExt.isEmpty()) {
return false;
}
String currActualSigType = detector.detectMIMEType(abstractFile);
String currActualSigType = detector.getMIMEType(abstractFile);
if (settings.getCheckType() != CHECK_TYPE.ALL) {
if (settings.getCheckType() == CHECK_TYPE.NO_TEXT_FILES) {
if (!currActualExt.isEmpty() && currActualSigType.equals("text/plain")) { //NON-NLS
@@ -171,14 +171,15 @@ public class FileTypeDetector {
}
/**
* Detects the MIME type of a file.
* Detects the MIME type of a file, then writes it the AbstractFile object
* representing the file and returns the detected type.
*
* @param file The file to test.
*
* @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) {
public String getMIMEType(AbstractFile file) {
/*
* Check to see if the file has already been typed.
*/
@@ -250,6 +251,11 @@ public class FileTypeDetector {
}
}
/*
* Documented side effect: write the result to the AbstractFile object.
*/
file.setMIMEType(mimeType);
return mimeType;
}
@@ -293,7 +299,7 @@ public class FileTypeDetector {
attributes.add(setNameAttribute);
BlackboardAttribute ruleNameAttribute = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CATEGORY, FileTypeIdModuleFactory.getModuleName(), fileType.getMimeType());
attributes.add(ruleNameAttribute);
artifact.addAttributes(attributes);
artifact.addAttributes(attributes);
try {
Case.getCurrentCase().getServices().getBlackboard().indexArtifact(artifact);
} catch (Blackboard.BlackboardException ex) {
@@ -393,7 +399,7 @@ public class FileTypeDetector {
*/
@Deprecated
public String detectAndPostToBlackboard(AbstractFile file) throws TskCoreException {
String fileType = detectMIMEType(file);
String fileType = getMIMEType(file);
file.setMIMEType(fileType);
file.save();
return fileType;
@@ -417,7 +423,7 @@ public class FileTypeDetector {
*/
@Deprecated
public String getFileType(AbstractFile file) throws TskCoreException {
String fileType = detectMIMEType(file);
String fileType = getMIMEType(file);
file.setMIMEType(fileType);
file.save();
return fileType;
@@ -437,7 +443,7 @@ public class FileTypeDetector {
*/
@Deprecated
public String detect(AbstractFile file) throws TskCoreException {
String fileType = detectMIMEType(file);
String fileType = getMIMEType(file);
return fileType;
}
@@ -91,7 +91,7 @@ public class FileTypeIdIngestModule implements FileIngestModule {
*/
try {
long startTime = System.currentTimeMillis();
file.setMIMEType(fileTypeDetector.detectMIMEType(file));
fileTypeDetector.getMIMEType(file);
addToTotals(jobId, (System.currentTimeMillis() - startTime));
return ProcessResult.OK;
} catch (Exception e) {
@@ -34,6 +34,7 @@ class ReportExcel implements TableReportModule {
private static final Logger logger = Logger.getLogger(ReportExcel.class.getName());
private static ReportExcel instance;
private static final int EXCEL_CELL_MAXIMUM_SIZE = 36767; //Specified at:https://poi.apache.org/apidocs/org/apache/poi/ss/SpreadsheetVersion.html
private Workbook wb;
private Sheet sheet;
@@ -236,10 +237,24 @@ class ReportExcel implements TableReportModule {
* @param row cells to add
*/
@Override
@NbBundle.Messages({
"ReportExcel.exceptionMessage.dataTooLarge=Value is too long to fit into an Excel cell. ",
"ReportExcel.exceptionMessage.errorText=Error showing data into an Excel cell."
})
public void addRow(List<String> rowData) {
Row row = sheet.createRow(rowIndex);
for (int i = 0; i < rowData.size(); ++i) {
row.createCell(i).setCellValue(rowData.get(i));
Cell excelCell = row.createCell(i);
try {
excelCell.setCellValue(rowData.get(i));
} catch (Exception e) {
if (e instanceof java.lang.IllegalArgumentException && rowData.get(i).length() > EXCEL_CELL_MAXIMUM_SIZE) {
excelCell.setCellValue(Bundle.ReportExcel_exceptionMessage_dataTooLarge() + e.getMessage());
} else {
excelCell.setCellValue(Bundle.ReportExcel_exceptionMessage_errorText());
}
}
}
++rowIndex;
}
@@ -51,6 +51,7 @@ import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.services.Services;
import org.sleuthkit.autopsy.casemodule.services.TagsManager;
import org.sleuthkit.autopsy.coreutils.EscapeUtil;
import org.sleuthkit.autopsy.coreutils.ImageUtils;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.ContentUtils.ExtractFscContentVisitor;
@@ -554,7 +555,8 @@ class ReportHTML implements TableReportModule {
StringBuilder builder = new StringBuilder();
builder.append("\t<tr>\n"); //NON-NLS
for (String cell : row) {
builder.append("\t\t<td>").append(cell).append("</td>\n"); //NON-NLS
String escapeHTMLCell = EscapeUtil.escapeHtml(cell);
builder.append("\t\t<td>").append(escapeHTMLCell).append("</td>\n"); //NON-NLS
}
builder.append("\t</tr>\n"); //NON-NLS
rowCount++;
@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013-16 Basis Technology Corp.
* Copyright 2013-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -40,7 +40,6 @@ import java.util.logging.Level;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.services.TagsManager;
import org.sleuthkit.autopsy.coreutils.EscapeUtil;
import org.sleuthkit.autopsy.coreutils.ImageUtils;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.ContentUtils;
@@ -666,8 +665,7 @@ class TableReportGenerator {
tableModule.startTable(columnHeaderNames);
}
String previewreplace = EscapeUtil.escapeHtml(preview);
tableModule.addRow(Arrays.asList(new String[]{previewreplace.replaceAll("<!", ""), uniquePath, tagsList}));
tableModule.addRow(Arrays.asList(new String[]{preview, uniquePath, tagsList}));
}
// Finish the current data type
@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2017 Basis Technology Corp.
* Copyright 2017-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -28,13 +28,14 @@ import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.coreutils.Logger;
@ActionID(category = "Tools", id = "org.sleuthkit.autopsy.experimental.autoingest.AutoIngestDashboardOpenAction")
@ActionReference(path = "Menu/Tools", position = 104)
@ActionReference(path = "Menu/Tools", position = 201)
@ActionRegistration(displayName = "#CTL_AutoIngestDashboardOpenAction", lazy = false)
@Messages({"CTL_AutoIngestDashboardOpenAction=Auto Ingest Dashboard"})
public final class AutoIngestDashboardOpenAction extends CallableSystemAction {
private static final Logger LOGGER = Logger.getLogger(AutoIngestDashboardOpenAction.class.getName());
private static final String DISPLAY_NAME = Bundle.CTL_AutoIngestDashboardOpenAction();
private static final long serialVersionUID = 1L;
@Override
public boolean isEnabled() {
@@ -220,7 +220,7 @@ public enum FileTypeUtils {
* mimetype could not be detected.
*/
static boolean hasDrawableMIMEType(AbstractFile file) throws FileTypeDetector.FileTypeDetectorInitException {
String mimeType = getFileTypeDetector().detectMIMEType(file).toLowerCase();
String mimeType = getFileTypeDetector().getMIMEType(file).toLowerCase();
return isDrawableMimeType(mimeType) || (mimeType.equals("audio/x-aiff") && "tiff".equalsIgnoreCase(file.getNameExtension()));
}
@@ -235,7 +235,7 @@ public enum FileTypeUtils {
*/
public static boolean hasVideoMIMEType(AbstractFile file) {
try {
String mimeType = getFileTypeDetector().detectMIMEType(file).toLowerCase();
String mimeType = getFileTypeDetector().getMIMEType(file).toLowerCase();
return mimeType.startsWith("video/") || videoMimeTypes.contains(mimeType);
} catch (FileTypeDetector.FileTypeDetectorInitException ex) {
LOGGER.log(Level.SEVERE, "Error determining MIME type of " + getContentPathSafe(file), ex);
@@ -365,81 +365,84 @@ class GlobalListsManagementPanel extends javax.swing.JPanel implements OptionsPa
chooser.addChoosableFileFilter(autopsyFilter);
chooser.addChoosableFileFilter(encaseFilter);
chooser.setAcceptAllFileFilterUsed(false);
chooser.setMultiSelectionEnabled(true);
chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
String listName = null;
int returnVal = chooser.showOpenDialog(this);
if (returnVal == JFileChooser.APPROVE_OPTION) {
File selFile = chooser.getSelectedFile();
if (selFile == null) {
return;
}
File[] selFiles = chooser.getSelectedFiles();
//force append extension if not given
String fileAbs = selFile.getAbsolutePath();
final KeywordSearchList reader;
if (KeywordSearchUtil.isXMLList(fileAbs)) {
reader = new XmlKeywordSearchList(fileAbs);
} else {
reader = new EnCaseKeywordSearchList(fileAbs);
}
if (!reader.load()) {
KeywordSearchUtil.displayDialog(
NbBundle.getMessage(this.getClass(), "KeywordSearch.listImportFeatureTitle"), NbBundle.getMessage(this.getClass(), "KeywordSearch.importListFileDialogMsg", fileAbs), KeywordSearchUtil.DIALOG_MESSAGE_TYPE.ERROR);
return;
}
List<KeywordList> toImport = reader.getListsL();
List<KeywordList> toImportConfirmed = new ArrayList<>();
final XmlKeywordSearchList writer = XmlKeywordSearchList.getCurrent();
for (KeywordList list : toImport) {
//check name collisions
listName = list.getName();
if (writer.listExists(listName)) {
String[] options;
if (toImport.size() == 1) { //only give them cancel and yes buttons for single list imports
options = new String[]{NbBundle.getMessage(this.getClass(), "KeywordSearch.yesOwMsg"),
NbBundle.getMessage(this.getClass(), "KeywordSearch.cancelImportMsg")};
} else {
options = new String[]{NbBundle.getMessage(this.getClass(), "KeywordSearch.yesOwMsg"),
NbBundle.getMessage(this.getClass(), "KeywordSearch.noSkipMsg"),
NbBundle.getMessage(this.getClass(), "KeywordSearch.cancelImportMsg")};
}
int choice = JOptionPane.showOptionDialog(this,
NbBundle.getMessage(this.getClass(), "KeywordSearch.overwriteListPrompt", listName),
NbBundle.getMessage(this.getClass(), "KeywordSearch.importOwConflict"),
JOptionPane.YES_NO_CANCEL_OPTION,
JOptionPane.QUESTION_MESSAGE,
null,
options,
options[0]);
if (choice == JOptionPane.OK_OPTION) {
toImportConfirmed.add(list);
} else if (choice == JOptionPane.CANCEL_OPTION) {
break;
}
for (File file : selFiles) {
if (file == null) {
continue;
}
//force append extension if not given
String fileAbs = file.getAbsolutePath();
final KeywordSearchList reader;
if (KeywordSearchUtil.isXMLList(fileAbs)) {
reader = new XmlKeywordSearchList(fileAbs);
} else {
//no conflict
toImportConfirmed.add(list);
reader = new EnCaseKeywordSearchList(fileAbs);
}
}
if (!reader.load()) {
KeywordSearchUtil.displayDialog(
NbBundle.getMessage(this.getClass(), "KeywordSearch.listImportFeatureTitle"), NbBundle.getMessage(this.getClass(), "KeywordSearch.importListFileDialogMsg", fileAbs), KeywordSearchUtil.DIALOG_MESSAGE_TYPE.ERROR);
return;
}
if (toImportConfirmed.isEmpty()) {
return;
}
List<KeywordList> toImport = reader.getListsL();
List<KeywordList> toImportConfirmed = new ArrayList<>();
if (!writer.writeLists(toImportConfirmed)) {
KeywordSearchUtil.displayDialog(
NbBundle.getMessage(this.getClass(), "KeywordSearch.listImportFeatureTitle"), NbBundle.getMessage(this.getClass(), "KeywordSearch.kwListFailImportMsg"), KeywordSearchUtil.DIALOG_MESSAGE_TYPE.INFO);
final XmlKeywordSearchList writer = XmlKeywordSearchList.getCurrent();
for (KeywordList list : toImport) {
//check name collisions
listName = list.getName();
if (writer.listExists(listName)) {
String[] options;
if (toImport.size() == 1) { //only give them cancel and yes buttons for single list imports
options = new String[]{NbBundle.getMessage(this.getClass(), "KeywordSearch.yesOwMsg"),
NbBundle.getMessage(this.getClass(), "KeywordSearch.cancelImportMsg")};
} else {
options = new String[]{NbBundle.getMessage(this.getClass(), "KeywordSearch.yesOwMsg"),
NbBundle.getMessage(this.getClass(), "KeywordSearch.noSkipMsg"),
NbBundle.getMessage(this.getClass(), "KeywordSearch.cancelImportMsg")};
}
int choice = JOptionPane.showOptionDialog(this,
NbBundle.getMessage(this.getClass(), "KeywordSearch.overwriteListPrompt", listName),
NbBundle.getMessage(this.getClass(), "KeywordSearch.importOwConflict"),
JOptionPane.YES_NO_CANCEL_OPTION,
JOptionPane.QUESTION_MESSAGE,
null,
options,
options[0]);
if (choice == JOptionPane.OK_OPTION) {
toImportConfirmed.add(list);
} else if (choice == JOptionPane.CANCEL_OPTION) {
break;
}
} else {
//no conflict
toImportConfirmed.add(list);
}
}
if (toImportConfirmed.isEmpty()) {
return;
}
if (!writer.writeLists(toImportConfirmed)) {
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, file.getParent());
}
ModuleSettings.setConfigSetting(ModuleSettings.MAIN_SETTINGS, LAST_KEYWORD_LIST_PATH_KEY, selFile.getParent());
}
tableModel.resync();
@@ -511,7 +511,7 @@ public final class KeywordSearchIngestModule implements FileIngestModule {
if (context.fileIngestIsCancelled()) {
return;
}
String fileType = fileTypeDetector.detectMIMEType(aFile);
String fileType = fileTypeDetector.getMIMEType(aFile);
// we skip archive formats that are opened by the archive module.
// @@@ We could have a check here to see if the archive module was enabled though...
@@ -1,5 +1,5 @@
#Updated by build script
#Fri, 05 Jan 2018 10:31:22 -0500
#Tue, 23 Jan 2018 11:13:26 -0500
LBL_splash_window_title=Starting Autopsy
SPLASH_HEIGHT=314
SPLASH_WIDTH=538
@@ -1,4 +1,4 @@
#Updated by build script
#Fri, 05 Jan 2018 10:31:22 -0500
#Tue, 23 Jan 2018 11:13:26 -0500
CTL_MainWindow_Title=Autopsy 4.5.0
CTL_MainWindow_Title_No_Project=Autopsy 4.5.0
Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 16 KiB

+33
View File
@@ -0,0 +1,33 @@
/*! \page live_triage_page Live Triage
\section live_triage_overview Overview
The Live Triage feature allows you to load Autopsy onto a removable drive to run on target systems while making minimal changes to that target system. This will currently only work on Windows systems.
\section live_triage_create_drive Creating a live triage drive
To create a live triage drive, go to Tools->Make Live Triage Drive to bring up the main dialog.
\image html live_triage_dialog.png
Select the drive you want to use - any type of USB storage device will work. For best results use the fastest drive available. Once the process is complete the root folder will contain an Autopsy folder and a RunFromUSB.bat file.
\section live_triage_usage Running Autopsy from the live triage drive
Insert the drive into the target machine and browse to it in Windows Explorer. Right click on RunFromUSB.bat and select "Run as administrator". This is necessary to analyze the local drives.
\image html live_triage_script.png
Running the script will generate a few more directories on the USB drive. The configData directory stores all the data used by Autopsy - primarily configuration files and temporary files. You can make changes to the Autopsy settings and they will persist between runs. The cases directory is created as a recommended place to save your case data. You will need to browse to it when creating a case in Autopsy.
Once Autopsy is running, proceed to create a case as normal, making sure to save it on the USB drive.
\image html live_triage_case.png
Then choose the Local Disk data source and select the desired drive.
\image html live_triage_ds.png
See the \ref ds_local page for more information on local disk data sources.
*/
+1
View File
@@ -60,6 +60,7 @@ The following topics are available here:
- \subpage windows_authentication
- \subpage multiuser_sec_page
- \subpage multiuser_page
- \subpage live_triage_page
- \subpage advanced_page
If the topic you need is not listed, refer to the <a href="http://wiki.sleuthkit.org/index.php?title=Autopsy_User%27s_Guide">Autopsy Wiki</a> or join the <a href="https://lists.sourceforge.net/lists/listinfo/sleuthkit-users">SleuthKit User List</a> at SourceForge.