mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-19 11:07:43 +00:00
Merge remote-tracking branch 'upstream/develop' into 3784_BitlockerDetection
This commit is contained in:
commit
702f46d911
@ -72,10 +72,12 @@ public class ImageDSProcessor implements DataSourceProcessor, AutoIngestDataSour
|
|||||||
filtersList.add(allFilter);
|
filtersList.add(allFilter);
|
||||||
filtersList.add(rawFilter);
|
filtersList.add(rawFilter);
|
||||||
filtersList.add(encaseFilter);
|
filtersList.add(encaseFilter);
|
||||||
filtersList.add(virtualMachineFilter);
|
|
||||||
allExt.addAll(GeneralFilter.RAW_IMAGE_EXTS);
|
allExt.addAll(GeneralFilter.RAW_IMAGE_EXTS);
|
||||||
allExt.addAll(GeneralFilter.ENCASE_IMAGE_EXTS);
|
allExt.addAll(GeneralFilter.ENCASE_IMAGE_EXTS);
|
||||||
allExt.addAll(GeneralFilter.VIRTUAL_MACHINE_EXTS);
|
if(!System.getProperty("os.name").toLowerCase().contains("mac")){
|
||||||
|
filtersList.add(virtualMachineFilter);
|
||||||
|
allExt.addAll(GeneralFilter.VIRTUAL_MACHINE_EXTS);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy
|
||||||
|
*
|
||||||
|
* 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.ingest;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generic Ingest Job settings class.
|
||||||
|
* Primary use of this class is for Python modules because classes created in Python
|
||||||
|
* cannot be serialized / deserialized in Java.
|
||||||
|
*/
|
||||||
|
public class GenericIngestModuleJobSettings implements IngestModuleIngestJobSettings {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getVersionNumber(){
|
||||||
|
return serialVersionUID;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Map<String, String> settings;
|
||||||
|
|
||||||
|
public GenericIngestModuleJobSettings(){
|
||||||
|
this.settings = new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the string value for passed key parameter.
|
||||||
|
*
|
||||||
|
* @param key The key to lookup
|
||||||
|
* @return The value or null if the key was not found.
|
||||||
|
*/
|
||||||
|
public String getSetting(String key){
|
||||||
|
return settings.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the passed key value pair
|
||||||
|
*
|
||||||
|
* @param key The key to be added to the settings
|
||||||
|
* @param value The value to be added for the key
|
||||||
|
*/
|
||||||
|
public void setSetting(String key, String value){
|
||||||
|
settings.put(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the key from the settings.
|
||||||
|
* @param key The key to be removed
|
||||||
|
*/
|
||||||
|
public void removeSetting(String key){
|
||||||
|
settings.remove(key);
|
||||||
|
}
|
||||||
|
}
|
@ -36,7 +36,6 @@ import java.util.logging.Level;
|
|||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.openide.util.io.NbObjectInputStream;
|
import org.openide.util.io.NbObjectInputStream;
|
||||||
import org.openide.util.io.NbObjectOutputStream;
|
import org.openide.util.io.NbObjectOutputStream;
|
||||||
import org.python.util.PythonObjectInputStream;
|
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
|
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
|
||||||
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
|
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
|
||||||
@ -492,25 +491,12 @@ public final class IngestJobSettings {
|
|||||||
String moduleSettingsFilePath = getModuleSettingsFilePath(factory);
|
String moduleSettingsFilePath = getModuleSettingsFilePath(factory);
|
||||||
File settingsFile = new File(moduleSettingsFilePath);
|
File settingsFile = new File(moduleSettingsFilePath);
|
||||||
if (settingsFile.exists()) {
|
if (settingsFile.exists()) {
|
||||||
if (!isPythonModuleSettingsFile(moduleSettingsFilePath)) {
|
try (NbObjectInputStream in = new NbObjectInputStream(new FileInputStream(settingsFile.getAbsolutePath()))) {
|
||||||
try (NbObjectInputStream in = new NbObjectInputStream(new FileInputStream(settingsFile.getAbsolutePath()))) {
|
settings = (IngestModuleIngestJobSettings) in.readObject();
|
||||||
settings = (IngestModuleIngestJobSettings) in.readObject();
|
} catch (IOException | ClassNotFoundException ex) {
|
||||||
} catch (IOException | ClassNotFoundException ex) {
|
String warning = NbBundle.getMessage(IngestJobSettings.class, "IngestJobSettings.moduleSettingsLoad.warning", factory.getModuleDisplayName(), this.executionContext); //NON-NLS
|
||||||
String warning = NbBundle.getMessage(IngestJobSettings.class, "IngestJobSettings.moduleSettingsLoad.warning", factory.getModuleDisplayName(), this.executionContext); //NON-NLS
|
logger.log(Level.WARNING, warning, ex);
|
||||||
logger.log(Level.WARNING, warning, ex);
|
this.warnings.add(warning);
|
||||||
this.warnings.add(warning);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// @@@ BC Jython serialization is currently broken and this
|
|
||||||
// throws an exception. (-2323). Commenting out so that
|
|
||||||
// Python modules will at least load with default settings.
|
|
||||||
// try (PythonObjectInputStream in = new PythonObjectInputStream(new FileInputStream(settingsFile.getAbsolutePath()))) {
|
|
||||||
// settings = (IngestModuleIngestJobSettings) in.readObject();
|
|
||||||
// } catch (IOException | ClassNotFoundException exception) {
|
|
||||||
// String warning = NbBundle.getMessage(IngestJobSettings.class, "IngestJobSettings.moduleSettingsLoad.warning", factory.getModuleDisplayName(), this.executionContext); //NON-NLS
|
|
||||||
// logger.log(Level.WARNING, warning, exception);
|
|
||||||
// this.warnings.add(warning);
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (settings == null) {
|
if (settings == null) {
|
||||||
|
@ -37,6 +37,7 @@ import org.apache.tika.metadata.Metadata;
|
|||||||
import org.apache.tika.parser.AutoDetectParser;
|
import org.apache.tika.parser.AutoDetectParser;
|
||||||
import org.apache.tika.parser.ParseContext;
|
import org.apache.tika.parser.ParseContext;
|
||||||
import org.apache.tika.sax.BodyContentHandler;
|
import org.apache.tika.sax.BodyContentHandler;
|
||||||
|
import org.openide.util.NbBundle.Messages;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||||
import org.sleuthkit.autopsy.casemodule.services.Blackboard;
|
import org.sleuthkit.autopsy.casemodule.services.Blackboard;
|
||||||
@ -50,21 +51,20 @@ import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
|
|||||||
import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector;
|
import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector;
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||||
|
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||||
import org.sleuthkit.datamodel.ReadContentInputStream.ReadContentInputStreamException;
|
import org.sleuthkit.datamodel.ReadContentInputStream.ReadContentInputStreamException;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
import org.sleuthkit.datamodel.TskData;
|
import org.sleuthkit.datamodel.TskData;
|
||||||
import org.xml.sax.ContentHandler;
|
import org.xml.sax.ContentHandler;
|
||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* File ingest module to detect encryption and password protection.
|
* File ingest module to detect encryption and password protection.
|
||||||
*/
|
*/
|
||||||
final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter {
|
final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter {
|
||||||
|
|
||||||
private static final int FILE_SIZE_MODULUS = 512;
|
private static final int FILE_SIZE_MODULUS = 512;
|
||||||
|
|
||||||
private static final String MIME_TYPE_OOXML_PROTECTED = "application/x-ooxml-protected";
|
private static final String MIME_TYPE_OOXML_PROTECTED = "application/x-ooxml-protected";
|
||||||
private static final String MIME_TYPE_MSWORD = "application/msword";
|
private static final String MIME_TYPE_MSWORD = "application/msword";
|
||||||
private static final String MIME_TYPE_MSEXCEL = "application/vnd.ms-excel";
|
private static final String MIME_TYPE_MSEXCEL = "application/vnd.ms-excel";
|
||||||
@ -110,6 +110,10 @@ final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Messages({
|
||||||
|
"EncryptionDetectionFileIngestModule.artifactComment.password=Password protection detected.",
|
||||||
|
"EncryptionDetectionFileIngestModule.artifactComment.suspected=Suspected encryption due to high entropy (%f)."
|
||||||
|
})
|
||||||
@Override
|
@Override
|
||||||
public IngestModule.ProcessResult process(AbstractFile file) {
|
public IngestModule.ProcessResult process(AbstractFile file) {
|
||||||
|
|
||||||
@ -132,11 +136,13 @@ final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter
|
|||||||
String mimeType = fileTypeDetector.getMIMEType(file);
|
String mimeType = fileTypeDetector.getMIMEType(file);
|
||||||
if (mimeType.equals("application/octet-stream")) {
|
if (mimeType.equals("application/octet-stream")) {
|
||||||
if (isFileEncryptionSuspected(file)) {
|
if (isFileEncryptionSuspected(file)) {
|
||||||
return flagFile(file, BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_SUSPECTED);
|
return flagFile(file, BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_SUSPECTED,
|
||||||
|
String.format(Bundle.EncryptionDetectionFileIngestModule_artifactComment_suspected(), calculatedEntropy));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (isFilePasswordProtected(file)) {
|
if (isFilePasswordProtected(file)) {
|
||||||
return flagFile(file, BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED);
|
return flagFile(file, BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED,
|
||||||
|
Bundle.EncryptionDetectionFileIngestModule_artifactComment_password());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -168,14 +174,18 @@ final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter
|
|||||||
*
|
*
|
||||||
* @param file The file to be processed.
|
* @param file The file to be processed.
|
||||||
* @param artifactType The type of artifact to create.
|
* @param artifactType The type of artifact to create.
|
||||||
|
* @param comment A comment to be attached to the artifact.
|
||||||
*
|
*
|
||||||
* @return 'OK' if the file was processed successfully, or 'ERROR' if there
|
* @return 'OK' if the file was processed successfully, or 'ERROR' if there
|
||||||
* was a problem.
|
* was a problem.
|
||||||
*/
|
*/
|
||||||
private IngestModule.ProcessResult flagFile(AbstractFile file, BlackboardArtifact.ARTIFACT_TYPE artifactType) {
|
private IngestModule.ProcessResult flagFile(AbstractFile file, BlackboardArtifact.ARTIFACT_TYPE artifactType, String comment) {
|
||||||
try {
|
try {
|
||||||
BlackboardArtifact artifact = file.newArtifact(artifactType);
|
BlackboardArtifact artifact = file.newArtifact(artifactType);
|
||||||
|
|
||||||
|
artifact.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT,
|
||||||
|
EncryptionDetectionModuleFactory.getModuleName(), comment));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
/*
|
/*
|
||||||
* Index the artifact for keyword search.
|
* Index the artifact for keyword search.
|
||||||
|
@ -927,7 +927,7 @@ public class TimeLineController {
|
|||||||
* @param o The object to un-register.
|
* @param o The object to un-register.
|
||||||
*/
|
*/
|
||||||
synchronized public void unRegisterForEvents(Object o) {
|
synchronized public void unRegisterForEvents(Object o) {
|
||||||
eventbus.unregister(0);
|
eventbus.unregister(o);
|
||||||
}
|
}
|
||||||
|
|
||||||
static synchronized public void setTimeZone(TimeZone timeZone) {
|
static synchronized public void setTimeZone(TimeZone timeZone) {
|
||||||
|
@ -509,7 +509,7 @@ public final class FilteredEventsModel {
|
|||||||
* @param o The object to un-register.
|
* @param o The object to un-register.
|
||||||
*/
|
*/
|
||||||
synchronized public void unRegisterForEvents(Object o) {
|
synchronized public void unRegisterForEvents(Object o) {
|
||||||
eventbus.unregister(0);
|
eventbus.unregister(o);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -52,6 +52,14 @@ final class AinStatusDashboard extends javax.swing.JPanel implements Observer {
|
|||||||
autoIngestMonitor.addObserver(this);
|
autoIngestMonitor.addObserver(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AutoIngestMonitor getMonitor() {
|
||||||
|
return autoIngestMonitor;
|
||||||
|
}
|
||||||
|
|
||||||
|
AinStatusPanel getNodesStatusPanel() {
|
||||||
|
return nodesPanel;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method is called from within the constructor to initialize the form.
|
* 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
|
* WARNING: Do NOT modify this code. The content of this method is always
|
||||||
@ -143,9 +151,10 @@ final class AinStatusDashboard extends javax.swing.JPanel implements Observer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update(Observable o, Object arg) {
|
public void update(Observable o, Object arg) {
|
||||||
if (arg instanceof AutoIngestNodeState)
|
if (arg instanceof AutoIngestNodeState) {
|
||||||
EventQueue.invokeLater(() -> {
|
EventQueue.invokeLater(() -> {
|
||||||
refreshTables();
|
refreshTables();
|
||||||
});
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.experimental.autoingest;
|
package org.sleuthkit.autopsy.experimental.autoingest;
|
||||||
|
|
||||||
|
import java.awt.Component;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@ -74,8 +75,6 @@ final class AinStatusDashboardTopComponent extends TopComponent {
|
|||||||
tc.add(nodeTab);
|
tc.add(nodeTab);
|
||||||
tc.open();
|
tc.open();
|
||||||
}
|
}
|
||||||
tc.toFront();
|
|
||||||
tc.requestActive();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,6 +114,19 @@ final class AinStatusDashboardTopComponent extends TopComponent {
|
|||||||
WindowManager.getDefault().setTopComponentFloating(this, true);
|
WindowManager.getDefault().setTopComponentFloating(this, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current AutoIngestDashboard if there is one.
|
||||||
|
*
|
||||||
|
* @return the current AutoIngestDashboard or null if there is not one
|
||||||
|
*/
|
||||||
|
AinStatusDashboard getAinStatusDashboard() {
|
||||||
|
for (Component comp : getComponents()) {
|
||||||
|
if (comp instanceof AinStatusDashboard) {
|
||||||
|
return (AinStatusDashboard) comp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* This method is called from within the constructor to initialize the form.
|
* 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
|
* WARNING: Do NOT modify this code. The content of this method is always
|
||||||
|
@ -97,6 +97,7 @@ final class AinStatusNode extends AbstractNode {
|
|||||||
@Messages({"AinStatusNode.hostName.title=Host Name",
|
@Messages({"AinStatusNode.hostName.title=Host Name",
|
||||||
"AinStatusNode.status.title=Status",
|
"AinStatusNode.status.title=Status",
|
||||||
"AinStatusNode.status.running=Running",
|
"AinStatusNode.status.running=Running",
|
||||||
|
"AinStatusNode.status.pauseRequested=Pause Requested",
|
||||||
"AinStatusNode.status.pausedByUser=Paused By User",
|
"AinStatusNode.status.pausedByUser=Paused By User",
|
||||||
"AinStatusNode.status.pausedForError=Paused Due to System Error",
|
"AinStatusNode.status.pausedForError=Paused Due to System Error",
|
||||||
"AinStatusNode.status.startingup=Starting Up",
|
"AinStatusNode.status.startingup=Starting Up",
|
||||||
@ -129,6 +130,9 @@ final class AinStatusNode extends AbstractNode {
|
|||||||
case PAUSED_DUE_TO_SYSTEM_ERROR:
|
case PAUSED_DUE_TO_SYSTEM_ERROR:
|
||||||
status = Bundle.AinStatusNode_status_pausedForError();
|
status = Bundle.AinStatusNode_status_pausedForError();
|
||||||
break;
|
break;
|
||||||
|
case PAUSE_REQUESTED:
|
||||||
|
status = Bundle.AinStatusNode_status_pauseRequested();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -142,12 +146,11 @@ final class AinStatusNode extends AbstractNode {
|
|||||||
List<Action> actions = new ArrayList<>();
|
List<Action> actions = new ArrayList<>();
|
||||||
if (AutoIngestDashboard.isAdminAutoIngestDashboard()) {
|
if (AutoIngestDashboard.isAdminAutoIngestDashboard()) {
|
||||||
if (nodeState.getState() == AutoIngestNodeState.State.PAUSED_BY_REQUEST
|
if (nodeState.getState() == AutoIngestNodeState.State.PAUSED_BY_REQUEST
|
||||||
|| nodeState.getState() == AutoIngestNodeState.State.PAUSED_DUE_TO_SYSTEM_ERROR) {
|
|| nodeState.getState() == AutoIngestNodeState.State.PAUSED_DUE_TO_SYSTEM_ERROR
|
||||||
actions.add(new AutoIngestAdminActions.ResumeAction());
|
|| nodeState.getState() == AutoIngestNodeState.State.RUNNING) {
|
||||||
} else if (nodeState.getState() == AutoIngestNodeState.State.RUNNING){
|
actions.add(new AutoIngestAdminActions.AutoIngestNodeControlAction.PauseResumeAction(nodeState));
|
||||||
actions.add(new AutoIngestAdminActions.PauseAction());
|
|
||||||
}
|
}
|
||||||
actions.add(new AutoIngestAdminActions.ShutdownAction());
|
actions.add(new AutoIngestAdminActions.AutoIngestNodeControlAction.ShutdownAction(nodeState));
|
||||||
}
|
}
|
||||||
return actions.toArray(new Action[actions.size()]);
|
return actions.toArray(new Action[actions.size()]);
|
||||||
}
|
}
|
||||||
|
@ -99,12 +99,12 @@ final class AinStatusPanel extends javax.swing.JPanel implements ExplorerManager
|
|||||||
void refresh(AutoIngestMonitor monitor) {
|
void refresh(AutoIngestMonitor monitor) {
|
||||||
outline.setRowSelectionAllowed(false);
|
outline.setRowSelectionAllowed(false);
|
||||||
Node[] selectedNodes = explorerManager.getSelectedNodes();
|
Node[] selectedNodes = explorerManager.getSelectedNodes();
|
||||||
AinStatusNode autoIngestNode = new AinStatusNode(monitor);
|
AinStatusNode ainStatusNode = new AinStatusNode(monitor);
|
||||||
explorerManager.setRootContext(autoIngestNode);
|
explorerManager.setRootContext(ainStatusNode);
|
||||||
outline.setRowSelectionAllowed(true);
|
outline.setRowSelectionAllowed(true);
|
||||||
if (selectedNodes.length > 0 && autoIngestNode.getChildren().findChild(selectedNodes[0].getName()) != null && outline.isFocusable()) { //don't allow saved selections of empty nodes to be restored
|
if (selectedNodes.length > 0 && ainStatusNode.getChildren().findChild(selectedNodes[0].getName()) != null && outline.isFocusable()) { //don't allow saved selections of empty nodes to be restored
|
||||||
try {
|
try {
|
||||||
explorerManager.setSelectedNodes(new Node[]{autoIngestNode.getChildren().findChild(selectedNodes[0].getName())});
|
explorerManager.setSelectedNodes(new Node[]{ainStatusNode.getChildren().findChild(selectedNodes[0].getName())});
|
||||||
} catch (PropertyVetoException ignore) {
|
} catch (PropertyVetoException ignore) {
|
||||||
//Unable to select previously selected node
|
//Unable to select previously selected node
|
||||||
}
|
}
|
||||||
|
@ -18,14 +18,122 @@
|
|||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.experimental.autoingest;
|
package org.sleuthkit.autopsy.experimental.autoingest;
|
||||||
|
|
||||||
|
import java.awt.Cursor;
|
||||||
|
import java.awt.EventQueue;
|
||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.util.logging.Level;
|
||||||
import javax.swing.AbstractAction;
|
import javax.swing.AbstractAction;
|
||||||
|
import javax.swing.JOptionPane;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.openide.windows.WindowManager;
|
import org.openide.windows.WindowManager;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
|
import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestMonitor.AutoIngestNodeState;
|
||||||
import org.sleuthkit.autopsy.ingest.IngestProgressSnapshotDialog;
|
import org.sleuthkit.autopsy.ingest.IngestProgressSnapshotDialog;
|
||||||
|
|
||||||
final class AutoIngestAdminActions {
|
final class AutoIngestAdminActions {
|
||||||
|
|
||||||
|
static abstract class AutoIngestNodeControlAction extends AbstractAction {
|
||||||
|
|
||||||
|
private final AutoIngestNodeState nodeState;
|
||||||
|
private final Logger logger = Logger.getLogger(AutoIngestNodeControlAction.class.getName());
|
||||||
|
|
||||||
|
AutoIngestNodeControlAction(AutoIngestNodeState nodeState, String title) {
|
||||||
|
super(title);
|
||||||
|
this.nodeState = nodeState;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
if (nodeState != null) {
|
||||||
|
final AinStatusDashboardTopComponent tc = (AinStatusDashboardTopComponent) WindowManager.getDefault().findTopComponent(AinStatusDashboardTopComponent.PREFERRED_ID);
|
||||||
|
if (tc != null) {
|
||||||
|
AinStatusDashboard dashboard = tc.getAinStatusDashboard();
|
||||||
|
if (dashboard != null) {
|
||||||
|
dashboard.getNodesStatusPanel().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
|
||||||
|
EventQueue.invokeLater(() -> {
|
||||||
|
try {
|
||||||
|
controlAutoIngestNode(dashboard);
|
||||||
|
} catch (AutoIngestMonitor.AutoIngestMonitorException ex) {
|
||||||
|
logger.log(Level.WARNING, "Error sending control event to node", ex);
|
||||||
|
} finally {
|
||||||
|
dashboard.getNodesStatusPanel().setCursor(Cursor.getDefaultCursor());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void controlAutoIngestNode(AinStatusDashboard dashboard) throws AutoIngestMonitor.AutoIngestMonitorException;
|
||||||
|
|
||||||
|
AutoIngestNodeState getNodeState() {
|
||||||
|
return nodeState;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NbBundle.Messages({"AutoIngestAdminActions.pause.title=Pause Node",
|
||||||
|
"AutoIngestAdminActions.resume.title=Resume Node"})
|
||||||
|
static final class PauseResumeAction extends AutoIngestNodeControlAction {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
PauseResumeAction(AutoIngestNodeState nodeState) {
|
||||||
|
super(nodeState, nodeState.getState() == AutoIngestNodeState.State.RUNNING
|
||||||
|
? Bundle.AutoIngestAdminActions_pause_title() : Bundle.AutoIngestAdminActions_resume_title());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object clone() throws CloneNotSupportedException {
|
||||||
|
return super.clone(); //To change body of generated methods, choose Tools | Templates.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void controlAutoIngestNode(AinStatusDashboard dashboard) throws AutoIngestMonitor.AutoIngestMonitorException {
|
||||||
|
if (getNodeState().getState() == AutoIngestNodeState.State.RUNNING) {
|
||||||
|
dashboard.getMonitor().pauseAutoIngestNode(getNodeState().getName());
|
||||||
|
} else {
|
||||||
|
dashboard.getMonitor().resumeAutoIngestNode(getNodeState().getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NbBundle.Messages({"AutoIngestAdminActions.shutdown.title=Shutdown Node",
|
||||||
|
"AutoIngestAdminActions.shutdown.OK=OK", "AutoIngestAdminActions.shutdown.Cancel=Cancel",
|
||||||
|
"AutoIngestAdminActions.shutdown.consequences=This will cancel any currently running job on this host. Exiting while a job is running potentially leaves the case in an inconsistent or corrupted state."})
|
||||||
|
static final class ShutdownAction extends AutoIngestNodeControlAction {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
ShutdownAction(AutoIngestNodeState nodeState) {
|
||||||
|
super(nodeState, Bundle.AutoIngestAdminActions_shutdown_title());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object clone() throws CloneNotSupportedException {
|
||||||
|
return super.clone(); //To change body of generated methods, choose Tools | Templates.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void controlAutoIngestNode(AinStatusDashboard dashboard) throws AutoIngestMonitor.AutoIngestMonitorException {
|
||||||
|
Object[] options = {Bundle.AutoIngestAdminActions_shutdown_OK(),
|
||||||
|
Bundle.AutoIngestAdminActions_shutdown_Cancel()
|
||||||
|
};
|
||||||
|
|
||||||
|
int reply = JOptionPane.showOptionDialog(dashboard.getNodesStatusPanel(),
|
||||||
|
Bundle.AutoIngestAdminActions_shutdown_consequences(),
|
||||||
|
NbBundle.getMessage(AutoIngestControlPanel.class, "ConfirmationDialog.ConfirmExitHeader"),
|
||||||
|
JOptionPane.DEFAULT_OPTION,
|
||||||
|
JOptionPane.WARNING_MESSAGE,
|
||||||
|
null,
|
||||||
|
options,
|
||||||
|
options[JOptionPane.NO_OPTION]);
|
||||||
|
|
||||||
|
if (reply == JOptionPane.OK_OPTION) {
|
||||||
|
dashboard.getMonitor().shutdownAutoIngestNode(getNodeState().getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@NbBundle.Messages({"AutoIngestAdminActions.progressDialogAction.title=Ingest Progress"})
|
@NbBundle.Messages({"AutoIngestAdminActions.progressDialogAction.title=Ingest Progress"})
|
||||||
static final class ProgressDialogAction extends AbstractAction {
|
static final class ProgressDialogAction extends AbstractAction {
|
||||||
|
|
||||||
@ -152,65 +260,4 @@ final class AutoIngestAdminActions {
|
|||||||
return super.clone(); //To change body of generated methods, choose Tools | Templates.
|
return super.clone(); //To change body of generated methods, choose Tools | Templates.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@NbBundle.Messages({"AutoIngestAdminActions.pause.title=Pause Node"})
|
|
||||||
static final class PauseAction extends AbstractAction {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
PauseAction() {
|
|
||||||
super(Bundle.AutoIngestAdminActions_pause_title());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e) {
|
|
||||||
//TODO JIRA-
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object clone() throws CloneNotSupportedException {
|
|
||||||
return super.clone(); //To change body of generated methods, choose Tools | Templates.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@NbBundle.Messages({"AutoIngestAdminActions.resume.title=Resume Node"})
|
|
||||||
static final class ResumeAction extends AbstractAction {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
ResumeAction() {
|
|
||||||
super(Bundle.AutoIngestAdminActions_resume_title());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e) {
|
|
||||||
//TODO JIRA-
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object clone() throws CloneNotSupportedException {
|
|
||||||
return super.clone(); //To change body of generated methods, choose Tools | Templates.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@NbBundle.Messages({"AutoIngestAdminActions.shutdown.title=Shutdown Node"})
|
|
||||||
static final class ShutdownAction extends AbstractAction {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
ShutdownAction() {
|
|
||||||
super(Bundle.AutoIngestAdminActions_shutdown_title());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e) {
|
|
||||||
//TODO JIRA-
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object clone() throws CloneNotSupportedException {
|
|
||||||
return super.clone(); //To change body of generated methods, choose Tools | Templates.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -852,7 +852,7 @@ public final class AutoIngestControlPanel extends JPanel implements Observer {
|
|||||||
case CASE_DELETED:
|
case CASE_DELETED:
|
||||||
updateExecutor.submit(new UpdateAllJobsTablesTask());
|
updateExecutor.submit(new UpdateAllJobsTablesTask());
|
||||||
break;
|
break;
|
||||||
case PAUSED_BY_REQUEST:
|
case PAUSED_BY_USER_REQUEST:
|
||||||
EventQueue.invokeLater(() -> {
|
EventQueue.invokeLater(() -> {
|
||||||
tbStatusMessage.setText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnPause.paused"));
|
tbStatusMessage.setText(org.openide.util.NbBundle.getMessage(AutoIngestControlPanel.class, "AutoIngestControlPanel.bnPause.paused"));
|
||||||
bnOptions.setEnabled(true);
|
bnOptions.setEnabled(true);
|
||||||
@ -881,6 +881,9 @@ public final class AutoIngestControlPanel extends JPanel implements Observer {
|
|||||||
case JOB_STATUS_UPDATED:
|
case JOB_STATUS_UPDATED:
|
||||||
updateExecutor.submit(new UpdateRunningJobsTablesTask());
|
updateExecutor.submit(new UpdateRunningJobsTablesTask());
|
||||||
break;
|
break;
|
||||||
|
case SHUTTING_DOWN:
|
||||||
|
LifecycleManager.getDefault().exit();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -170,7 +170,7 @@ final class AutoIngestJobsPanel extends javax.swing.JPanel implements ExplorerMa
|
|||||||
AutoIngestJobsNode autoIngestNode = new AutoIngestJobsNode(jobsSnapshot, status);
|
AutoIngestJobsNode autoIngestNode = new AutoIngestJobsNode(jobsSnapshot, status);
|
||||||
explorerManager.setRootContext(autoIngestNode);
|
explorerManager.setRootContext(autoIngestNode);
|
||||||
outline.setRowSelectionAllowed(true);
|
outline.setRowSelectionAllowed(true);
|
||||||
if (selectedNodes.length > 0 && outline.isFocusable()) { //don't allow saved selections of empty nodes to be restored
|
if (selectedNodes.length > 0 && autoIngestNode.getChildren().findChild(selectedNodes[0].getName()) != null && outline.isFocusable()) { //don't allow saved selections of empty nodes to be restored
|
||||||
try {
|
try {
|
||||||
explorerManager.setSelectedNodes(new Node[]{autoIngestNode.getChildren().findChild(selectedNodes[0].getName())});
|
explorerManager.setSelectedNodes(new Node[]{autoIngestNode.getChildren().findChild(selectedNodes[0].getName())});
|
||||||
} catch (PropertyVetoException ignore) {
|
} catch (PropertyVetoException ignore) {
|
||||||
|
@ -94,6 +94,7 @@ import org.sleuthkit.autopsy.experimental.configuration.SharedConfiguration.Shar
|
|||||||
import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor;
|
import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor;
|
||||||
import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException;
|
import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException;
|
||||||
import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestJob.AutoIngestJobException;
|
import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestJob.AutoIngestJobException;
|
||||||
|
import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestNodeControlEvent.ControlEventType;
|
||||||
import org.sleuthkit.autopsy.ingest.IngestJob;
|
import org.sleuthkit.autopsy.ingest.IngestJob;
|
||||||
import org.sleuthkit.autopsy.ingest.IngestJob.CancellationReason;
|
import org.sleuthkit.autopsy.ingest.IngestJob.CancellationReason;
|
||||||
import org.sleuthkit.autopsy.ingest.IngestJobSettings;
|
import org.sleuthkit.autopsy.ingest.IngestJobSettings;
|
||||||
@ -134,7 +135,10 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen
|
|||||||
Event.JOB_COMPLETED.toString(),
|
Event.JOB_COMPLETED.toString(),
|
||||||
Event.CASE_PRIORITIZED.toString(),
|
Event.CASE_PRIORITIZED.toString(),
|
||||||
Event.JOB_STARTED.toString(),
|
Event.JOB_STARTED.toString(),
|
||||||
Event.REPORT_STATE.toString()}));
|
Event.REPORT_STATE.toString(),
|
||||||
|
ControlEventType.PAUSE.toString(),
|
||||||
|
ControlEventType.RESUME.toString(),
|
||||||
|
ControlEventType.SHUTDOWN.toString()}));
|
||||||
private static final long JOB_STATUS_EVENT_INTERVAL_SECONDS = 10;
|
private static final long JOB_STATUS_EVENT_INTERVAL_SECONDS = 10;
|
||||||
private static final String JOB_STATUS_PUBLISHING_THREAD_NAME = "AIM-job-status-event-publisher-%d";
|
private static final String JOB_STATUS_PUBLISHING_THREAD_NAME = "AIM-job-status-event-publisher-%d";
|
||||||
private static final long MAX_MISSED_JOB_STATUS_UPDATES = 10;
|
private static final long MAX_MISSED_JOB_STATUS_UPDATES = 10;
|
||||||
@ -282,6 +286,8 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen
|
|||||||
handleRemoteCaseDeletedEvent((AutoIngestCaseDeletedEvent) event);
|
handleRemoteCaseDeletedEvent((AutoIngestCaseDeletedEvent) event);
|
||||||
} else if (event instanceof AutoIngestRequestNodeStateEvent) {
|
} else if (event instanceof AutoIngestRequestNodeStateEvent) {
|
||||||
handleRemoteRequestNodeStateEvent();
|
handleRemoteRequestNodeStateEvent();
|
||||||
|
} else if (event instanceof AutoIngestNodeControlEvent) {
|
||||||
|
handleRemoteNodeControlEvent((AutoIngestNodeControlEvent) event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -405,6 +411,28 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen
|
|||||||
eventPublisher.publishRemotely(lastPublishedStateEvent);
|
eventPublisher.publishRemotely(lastPublishedStateEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void handleRemoteNodeControlEvent(AutoIngestNodeControlEvent event) {
|
||||||
|
if (event.getNodeName().compareToIgnoreCase(LOCAL_HOST_NAME) == 0) {
|
||||||
|
switch (event.getControlEventType()) {
|
||||||
|
case PAUSE:
|
||||||
|
pause();
|
||||||
|
break;
|
||||||
|
case RESUME:
|
||||||
|
resume();
|
||||||
|
break;
|
||||||
|
case SHUTDOWN:
|
||||||
|
shutDown();
|
||||||
|
// Notify the front end (if any) to shutdown.
|
||||||
|
setChanged();
|
||||||
|
notifyObservers(Event.SHUTTING_DOWN);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
SYS_LOGGER.log(Level.WARNING, "Received unsupported control event: {0}", event.getControlEventType());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shuts down auto ingest.
|
* Shuts down auto ingest.
|
||||||
*/
|
*/
|
||||||
@ -419,6 +447,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen
|
|||||||
eventPublisher.removeSubscriber(EVENT_LIST, instance);
|
eventPublisher.removeSubscriber(EVENT_LIST, instance);
|
||||||
stopInputFolderScans();
|
stopInputFolderScans();
|
||||||
stopJobProcessing();
|
stopJobProcessing();
|
||||||
|
eventPublisher.publishRemotely(lastPublishedStateEvent = new AutoIngestNodeStateEvent(Event.SHUTDOWN, AutoIngestManager.LOCAL_HOST_NAME));
|
||||||
eventPublisher.closeRemoteEventChannel();
|
eventPublisher.closeRemoteEventChannel();
|
||||||
cleanupJobs();
|
cleanupJobs();
|
||||||
|
|
||||||
@ -1696,14 +1725,13 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen
|
|||||||
* object.
|
* object.
|
||||||
*/
|
*/
|
||||||
setChanged();
|
setChanged();
|
||||||
notifyObservers(Event.PAUSED_BY_REQUEST);
|
notifyObservers(Event.PAUSED_BY_USER_REQUEST);
|
||||||
|
|
||||||
/**
|
|
||||||
* Publish an event to let remote listeners know that the
|
|
||||||
* node has been paused.
|
|
||||||
*/
|
|
||||||
eventPublisher.publishRemotely(lastPublishedStateEvent = new AutoIngestNodeStateEvent(Event.PAUSED_BY_REQUEST, AutoIngestManager.LOCAL_HOST_NAME));
|
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Publish an event to let remote listeners know that a pause
|
||||||
|
* has been requested.
|
||||||
|
*/
|
||||||
|
eventPublisher.publishRemotely(lastPublishedStateEvent = new AutoIngestNodeStateEvent(Event.PAUSE_REQUESTED, AutoIngestManager.LOCAL_HOST_NAME));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1746,18 +1774,22 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen
|
|||||||
* if auto ingest is shutting down.
|
* if auto ingest is shutting down.
|
||||||
*/
|
*/
|
||||||
private void pauseIfRequested() throws InterruptedException {
|
private void pauseIfRequested() throws InterruptedException {
|
||||||
|
if (State.SHUTTING_DOWN == state) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
synchronized (pauseLock) {
|
synchronized (pauseLock) {
|
||||||
if (pauseRequested) {
|
if (pauseRequested) {
|
||||||
sysLogger.log(Level.INFO, "Job processing paused by request");
|
sysLogger.log(Level.INFO, "Job processing paused by request");
|
||||||
pauseRequested = false;
|
pauseRequested = false;
|
||||||
setChanged();
|
setChanged();
|
||||||
notifyObservers(Event.PAUSED_BY_REQUEST);
|
notifyObservers(Event.PAUSED_BY_USER_REQUEST);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Publish an event to let remote listeners know that the
|
* Publish an event to let remote listeners know that the
|
||||||
* node has been paused.
|
* node has been paused.
|
||||||
*/
|
*/
|
||||||
eventPublisher.publishRemotely(lastPublishedStateEvent = new AutoIngestNodeStateEvent(Event.PAUSED_BY_REQUEST, AutoIngestManager.LOCAL_HOST_NAME));
|
eventPublisher.publishRemotely(lastPublishedStateEvent = new AutoIngestNodeStateEvent(Event.PAUSED_BY_USER_REQUEST, AutoIngestManager.LOCAL_HOST_NAME));
|
||||||
|
|
||||||
pauseLock.wait();
|
pauseLock.wait();
|
||||||
sysLogger.log(Level.INFO, "Job processing resumed after pause request");
|
sysLogger.log(Level.INFO, "Job processing resumed after pause request");
|
||||||
@ -1781,6 +1813,10 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen
|
|||||||
* if auto ingest is shutting down.
|
* if auto ingest is shutting down.
|
||||||
*/
|
*/
|
||||||
private void pauseForSystemError() throws InterruptedException {
|
private void pauseForSystemError() throws InterruptedException {
|
||||||
|
if (State.SHUTTING_DOWN == state) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
synchronized (pauseLock) {
|
synchronized (pauseLock) {
|
||||||
sysLogger.log(Level.SEVERE, "Job processing paused for system error");
|
sysLogger.log(Level.SEVERE, "Job processing paused for system error");
|
||||||
setChanged();
|
setChanged();
|
||||||
@ -3062,12 +3098,14 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen
|
|||||||
JOB_COMPLETED,
|
JOB_COMPLETED,
|
||||||
CASE_PRIORITIZED,
|
CASE_PRIORITIZED,
|
||||||
CASE_DELETED,
|
CASE_DELETED,
|
||||||
PAUSED_BY_REQUEST,
|
PAUSE_REQUESTED,
|
||||||
|
PAUSED_BY_USER_REQUEST,
|
||||||
PAUSED_FOR_SYSTEM_ERROR,
|
PAUSED_FOR_SYSTEM_ERROR,
|
||||||
RESUMED,
|
RESUMED,
|
||||||
STARTING_UP,
|
STARTING_UP,
|
||||||
RUNNING,
|
RUNNING,
|
||||||
SHUTTING_DOWN,
|
SHUTTING_DOWN,
|
||||||
|
SHUTDOWN,
|
||||||
REPORT_STATE
|
REPORT_STATE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,6 +42,7 @@ import org.sleuthkit.autopsy.events.AutopsyEventException;
|
|||||||
import org.sleuthkit.autopsy.events.AutopsyEventPublisher;
|
import org.sleuthkit.autopsy.events.AutopsyEventPublisher;
|
||||||
import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestJob.ProcessingStatus;
|
import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestJob.ProcessingStatus;
|
||||||
import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestManager.Event;
|
import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestManager.Event;
|
||||||
|
import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestNodeControlEvent.ControlEventType;
|
||||||
/**
|
/**
|
||||||
* An auto ingest monitor responsible for monitoring and reporting the
|
* An auto ingest monitor responsible for monitoring and reporting the
|
||||||
* processing of auto ingest jobs.
|
* processing of auto ingest jobs.
|
||||||
@ -61,10 +62,12 @@ final class AutoIngestMonitor extends Observable implements PropertyChangeListen
|
|||||||
AutoIngestManager.Event.CASE_PRIORITIZED.toString(),
|
AutoIngestManager.Event.CASE_PRIORITIZED.toString(),
|
||||||
AutoIngestManager.Event.JOB_STARTED.toString(),
|
AutoIngestManager.Event.JOB_STARTED.toString(),
|
||||||
AutoIngestManager.Event.RUNNING.toString(),
|
AutoIngestManager.Event.RUNNING.toString(),
|
||||||
AutoIngestManager.Event.PAUSED_BY_REQUEST.toString(),
|
AutoIngestManager.Event.PAUSE_REQUESTED.toString(),
|
||||||
|
AutoIngestManager.Event.PAUSED_BY_USER_REQUEST.toString(),
|
||||||
AutoIngestManager.Event.PAUSED_FOR_SYSTEM_ERROR.toString(),
|
AutoIngestManager.Event.PAUSED_FOR_SYSTEM_ERROR.toString(),
|
||||||
AutoIngestManager.Event.STARTING_UP.toString(),
|
AutoIngestManager.Event.STARTING_UP.toString(),
|
||||||
AutoIngestManager.Event.SHUTTING_DOWN.toString(),
|
AutoIngestManager.Event.SHUTTING_DOWN.toString(),
|
||||||
|
AutoIngestManager.Event.SHUTDOWN.toString(),
|
||||||
AutoIngestManager.Event.RESUMED.toString()}));
|
AutoIngestManager.Event.RESUMED.toString()}));
|
||||||
private final AutopsyEventPublisher eventPublisher;
|
private final AutopsyEventPublisher eventPublisher;
|
||||||
private CoordinationService coordinationService;
|
private CoordinationService coordinationService;
|
||||||
@ -221,9 +224,10 @@ final class AutoIngestMonitor extends Observable implements PropertyChangeListen
|
|||||||
* @param event A node state change event.
|
* @param event A node state change event.
|
||||||
*/
|
*/
|
||||||
private void handleAutoIngestNodeStateEvent(AutoIngestNodeStateEvent event) {
|
private void handleAutoIngestNodeStateEvent(AutoIngestNodeStateEvent event) {
|
||||||
if (event.getEventType() == AutoIngestManager.Event.SHUTTING_DOWN) {
|
AutoIngestNodeState oldNodeState = null;
|
||||||
|
if (event.getEventType() == AutoIngestManager.Event.SHUTDOWN) {
|
||||||
// Remove node from collection.
|
// Remove node from collection.
|
||||||
nodeStates.remove(event.getNodeName());
|
oldNodeState = nodeStates.remove(event.getNodeName());
|
||||||
} else {
|
} else {
|
||||||
// Otherwise either create an entry for the given node name or update
|
// Otherwise either create an entry for the given node name or update
|
||||||
// an existing entry in the map.
|
// an existing entry in the map.
|
||||||
@ -231,7 +235,7 @@ final class AutoIngestMonitor extends Observable implements PropertyChangeListen
|
|||||||
}
|
}
|
||||||
setChanged();
|
setChanged();
|
||||||
// Trigger a dashboard refresh.
|
// Trigger a dashboard refresh.
|
||||||
notifyObservers(nodeStates.get(event.getNodeName()));
|
notifyObservers(oldNodeState == null ? nodeStates.get(event.getNodeName()) : oldNodeState);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -522,6 +526,45 @@ final class AutoIngestMonitor extends Observable implements PropertyChangeListen
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send the given control event to the given node.
|
||||||
|
*
|
||||||
|
* @param eventType The type of control event to send.
|
||||||
|
* @param nodeName The name of the node to send it to.
|
||||||
|
*/
|
||||||
|
private void sendControlEventToNode(ControlEventType eventType, String nodeName) {
|
||||||
|
new Thread(() -> {
|
||||||
|
eventPublisher.publishRemotely(new AutoIngestNodeControlEvent(eventType, nodeName));
|
||||||
|
}).start();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tell the specified node to pause.
|
||||||
|
*
|
||||||
|
* @param nodeName
|
||||||
|
*/
|
||||||
|
void pauseAutoIngestNode(String nodeName) {
|
||||||
|
sendControlEventToNode(ControlEventType.PAUSE, nodeName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tell the specified node to resume.
|
||||||
|
*
|
||||||
|
* @param nodeName
|
||||||
|
*/
|
||||||
|
void resumeAutoIngestNode(String nodeName) {
|
||||||
|
sendControlEventToNode(ControlEventType.RESUME, nodeName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tell the specified node to shutdown.
|
||||||
|
*
|
||||||
|
* @param nodeName
|
||||||
|
*/
|
||||||
|
void shutdownAutoIngestNode(String nodeName) {
|
||||||
|
sendControlEventToNode(ControlEventType.SHUTDOWN, nodeName);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A task that queries the coordination service for auto ingest manifest
|
* A task that queries the coordination service for auto ingest manifest
|
||||||
* node data and converts it to auto ingest jobs for publication top its
|
* node data and converts it to auto ingest jobs for publication top its
|
||||||
@ -677,6 +720,7 @@ final class AutoIngestMonitor extends Observable implements PropertyChangeListen
|
|||||||
STARTING_UP,
|
STARTING_UP,
|
||||||
SHUTTING_DOWN,
|
SHUTTING_DOWN,
|
||||||
RUNNING,
|
RUNNING,
|
||||||
|
PAUSE_REQUESTED,
|
||||||
PAUSED_BY_REQUEST,
|
PAUSED_BY_REQUEST,
|
||||||
PAUSED_DUE_TO_SYSTEM_ERROR,
|
PAUSED_DUE_TO_SYSTEM_ERROR,
|
||||||
UNKNOWN
|
UNKNOWN
|
||||||
@ -697,7 +741,7 @@ final class AutoIngestMonitor extends Observable implements PropertyChangeListen
|
|||||||
case RUNNING:
|
case RUNNING:
|
||||||
nodeState = State.RUNNING;
|
nodeState = State.RUNNING;
|
||||||
break;
|
break;
|
||||||
case PAUSED_BY_REQUEST:
|
case PAUSED_BY_USER_REQUEST:
|
||||||
nodeState = State.PAUSED_BY_REQUEST;
|
nodeState = State.PAUSED_BY_REQUEST;
|
||||||
break;
|
break;
|
||||||
case PAUSED_FOR_SYSTEM_ERROR:
|
case PAUSED_FOR_SYSTEM_ERROR:
|
||||||
@ -706,6 +750,9 @@ final class AutoIngestMonitor extends Observable implements PropertyChangeListen
|
|||||||
case RESUMED:
|
case RESUMED:
|
||||||
nodeState = State.RUNNING;
|
nodeState = State.RUNNING;
|
||||||
break;
|
break;
|
||||||
|
case PAUSE_REQUESTED:
|
||||||
|
nodeState = State.PAUSE_REQUESTED;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
nodeState = State.UNKNOWN;
|
nodeState = State.UNKNOWN;
|
||||||
break;
|
break;
|
||||||
|
@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* 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.experimental.autoingest;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import org.sleuthkit.autopsy.events.AutopsyEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event published to pause, resume or shutdown an AIN.
|
||||||
|
*/
|
||||||
|
final class AutoIngestNodeControlEvent extends AutopsyEvent implements Serializable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The set of available controls.
|
||||||
|
*/
|
||||||
|
enum ControlEventType {
|
||||||
|
PAUSE,
|
||||||
|
RESUME,
|
||||||
|
SHUTDOWN
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
private final String nodeName;
|
||||||
|
private final ControlEventType eventType;
|
||||||
|
|
||||||
|
AutoIngestNodeControlEvent(ControlEventType eventType, String nodeName) {
|
||||||
|
super(eventType.toString(), null, null);
|
||||||
|
this.eventType = eventType;
|
||||||
|
this.nodeName = nodeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
String getNodeName() {
|
||||||
|
return nodeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
ControlEventType getControlEventType() {
|
||||||
|
return eventType;
|
||||||
|
}
|
||||||
|
}
|
@ -1,16 +0,0 @@
|
|||||||
Known Issues
|
|
||||||
|
|
||||||
Last Reviewed: June 12, 2012
|
|
||||||
|
|
||||||
|
|
||||||
This lists the bugs and issues thare are known and could effect
|
|
||||||
investigation results. There are other minor interface bugs that
|
|
||||||
are not listed here.
|
|
||||||
|
|
||||||
Keyword Search module:
|
|
||||||
- Slack space of files is not added to the index and therefore will
|
|
||||||
not be searched.
|
|
||||||
- Files larger than 100MB AND that are file types that are supported
|
|
||||||
by Tika (word docs, PDF, HTML, JPEG, etc.) are now added to the index as fully extracted text.
|
|
||||||
However, due to memory limitations of certain parsers, if full text extraction fails,
|
|
||||||
only strings extracted from the large file will be added to the index.
|
|
19
NEWS.txt
19
NEWS.txt
@ -1,23 +1,26 @@
|
|||||||
---------------- VERSION 4.7.0 --------------
|
---------------- VERSION 4.7.0 --------------
|
||||||
New Features:
|
New Features:
|
||||||
- A graph visualization was added to the Communications tool to make it easier to find messages and relationships.
|
- A graph visualization was added to the Communications tool to make it easier to find messages and relationships.
|
||||||
- A new Application content viewer provides custom views of media files, SQLite files, and Plists.
|
- A new "Application" content viewer (lower right) that will contain file-type specific viewers (to reduce number of tabs).
|
||||||
- A data source processor that runs Volatility was added to support ingesting memory images.
|
- New viewer for SQLite databases (in Application content viewer)
|
||||||
- Reports (e.g., RegRipper output) generated by ingest modules are now indexed for keyword search.
|
- New viewer for binary PLists (in Appilcation content viewer)
|
||||||
- Passwords to open password protected archive files can be entered.
|
|
||||||
- PhotoRec carving module can be configured to keep corrupted files.
|
|
||||||
- Filters to reduce files processed by ingest modules can have data range conditions.
|
|
||||||
- L01 files can be imported as data sources.
|
- L01 files can be imported as data sources.
|
||||||
- Block size can be supplied for local drives and for images for which SleuthKit auto detect fails.
|
- Ingest filters can now use date range conditions for triage.
|
||||||
|
- Passwords to open password protected archive files can be entered (by right clicking on the file).
|
||||||
|
- Reports (e.g., RegRipper output) generated by ingest modules are now indexed for keyword search.
|
||||||
|
- PhotoRec carving module can be configured to keep corrupted files.
|
||||||
|
- Sector size can be specified for local drives and images when E01 is wrong or it is a raw image.
|
||||||
|
- New data source processor in Experimental module that runs Volatility, adds the outputs as files, and parses the reports to provide INTERESTING_FILE artifacts.
|
||||||
- Assorted small enhancements are included.
|
- Assorted small enhancements are included.
|
||||||
|
|
||||||
Bug Fixes:
|
Bug Fixes:
|
||||||
- Memory leaks and other issues revealed by fuzzing the SleuthKit have
|
- Memory leaks and other issues revealed by fuzzing the The Sleuth Kit have
|
||||||
been fixed.
|
been fixed.
|
||||||
- Result views (upper right) and content views (lower right) stay in synch when switching result views.
|
- Result views (upper right) and content views (lower right) stay in synch when switching result views.
|
||||||
- Concurrency bugs in the ingest tasks scheduler have been fixed.
|
- Concurrency bugs in the ingest tasks scheduler have been fixed.
|
||||||
- Assorted small bug fixes are included.
|
- Assorted small bug fixes are included.
|
||||||
|
|
||||||
|
|
||||||
---------------- VERSION 4.6.0 --------------
|
---------------- VERSION 4.6.0 --------------
|
||||||
New Features:
|
New Features:
|
||||||
- A new Message content viewer was added to make it easier to view email message contents.
|
- A new Message content viewer was added to make it easier to view email message contents.
|
||||||
|
@ -43,3 +43,4 @@ Autopsy depends on a specific version of The Sleuth Kit. You need the Java libr
|
|||||||
* Limitations (Updated May 2018) *
|
* Limitations (Updated May 2018) *
|
||||||
- Timeline does not work on OS X
|
- Timeline does not work on OS X
|
||||||
- Video thumbnails are not generated (need to get a consistent version of OpenCV)
|
- Video thumbnails are not generated (need to get a consistent version of OpenCV)
|
||||||
|
- VHD and VMDK files not supported on OS X
|
||||||
|
11
build.xml
11
build.xml
@ -67,6 +67,16 @@
|
|||||||
<echo> TSK_HOME: ${env.TSK_HOME}</echo>
|
<echo> TSK_HOME: ${env.TSK_HOME}</echo>
|
||||||
</target>
|
</target>
|
||||||
|
|
||||||
|
<target name="clean" depends="suite.clean">
|
||||||
|
<delete includeEmptyDirs="true" failonerror="false">
|
||||||
|
<fileset dir="docs\doxygen-user\user-docs" includes="**/*"/>
|
||||||
|
</delete>
|
||||||
|
|
||||||
|
<delete includeEmptyDirs="true" failonerror="false">
|
||||||
|
<fileset dir="docs\doxygen\doxygen_docs\api-docs" includes="**/*"/>
|
||||||
|
</delete>
|
||||||
|
</target>
|
||||||
|
|
||||||
<!-- This target will create a custom ZIP file for us. It first uses the general
|
<!-- This target will create a custom ZIP file for us. It first uses the general
|
||||||
ZIP target and then opens it up and adds in any files that we want. This is where we customize the
|
ZIP target and then opens it up and adds in any files that we want. This is where we customize the
|
||||||
version number. -->
|
version number. -->
|
||||||
@ -90,7 +100,6 @@
|
|||||||
<copy file="${basedir}/README.txt" tofile="${zip-tmp}/${app.name}/README.txt"/>
|
<copy file="${basedir}/README.txt" tofile="${zip-tmp}/${app.name}/README.txt"/>
|
||||||
<copy file="${basedir}/LICENSE-2.0.txt" tofile="${zip-tmp}/${app.name}/LICENSE-2.0.txt"/>
|
<copy file="${basedir}/LICENSE-2.0.txt" tofile="${zip-tmp}/${app.name}/LICENSE-2.0.txt"/>
|
||||||
<copy file="${basedir}/NEWS.txt" tofile="${zip-tmp}/${app.name}/NEWS.txt"/>
|
<copy file="${basedir}/NEWS.txt" tofile="${zip-tmp}/${app.name}/NEWS.txt"/>
|
||||||
<copy file="${basedir}/KNOWN_ISSUES.txt" tofile="${zip-tmp}/${app.name}/KNOWN_ISSUES.txt"/>
|
|
||||||
<copy file="${basedir}/Running_Linux_OSX.txt" tofile="${zip-tmp}/${app.name}/Running_Linux_OSX.txt"/>
|
<copy file="${basedir}/Running_Linux_OSX.txt" tofile="${zip-tmp}/${app.name}/Running_Linux_OSX.txt"/>
|
||||||
<copy file="${basedir}/unix_setup.sh" tofile="${zip-tmp}/${app.name}/unix_setup.sh"/>
|
<copy file="${basedir}/unix_setup.sh" tofile="${zip-tmp}/${app.name}/unix_setup.sh"/>
|
||||||
<replaceregexp file="${zip-tmp}/${app.name}/unix_setup.sh" match="TSK_VERSION=(.*)" replace="TSK_VERSION=${TSK_VERSION}" byline="true"/>
|
<replaceregexp file="${zip-tmp}/${app.name}/unix_setup.sh" match="TSK_VERSION=(.*)" replace="TSK_VERSION=${TSK_VERSION}" byline="true"/>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user