mirror of
https://github.com/elisspace/autopsy.git
synced 2026-09-17 00:06:18 +00:00
Merge branch 'develop' of github.com:sleuthkit/autopsy into 7505-tempPathChanges
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
CTL_ResetWindowsAction=Reset Windows
|
||||
ResetWindowAction.confirm.text=The program will close and restart to perform the resetting of window locations.\n\nAre you sure you want to reset all window locations?
|
||||
ResetWindowAction.confirm.title=Reset Windows
|
||||
ResetWindowAction.caseCloseFailure.text=Unable to close the current case, the software will restart and the windows locations will reset the next time the software is closed.
|
||||
ResetWindowAction.caseSaveMetadata.text=Unable to save current case path, the software will restart and the windows locations will reset but the current case will not be opened upon restart.
|
||||
ResetWindowAction.confirm.text=In order to perform the resetting of window locations the software will close and restart. If a case is currently open, it will be closed. If ingest or a search is currently running, it will be terminated. Are you sure you want to restart the software to reset all window locations?
|
||||
|
||||
@@ -20,8 +20,8 @@ package org.sleuthkit.autopsy.apputils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.SwingUtilities;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.openide.LifecycleManager;
|
||||
@@ -32,9 +32,10 @@ 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.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.CaseActionException;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
|
||||
|
||||
/**
|
||||
@@ -51,39 +52,66 @@ public final class ResetWindowsAction extends CallableSystemAction {
|
||||
private static final String DISPLAY_NAME = Bundle.CTL_ResetWindowsAction();
|
||||
private static final long serialVersionUID = 1L;
|
||||
private final static Logger logger = Logger.getLogger(ResetWindowsAction.class.getName());
|
||||
private final static String WINDOWS2LOCAL = "Windows2Local";
|
||||
private final static String CASE_TO_REOPEN_FILE = "caseToOpen.txt";
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return !Case.isCaseOpen();
|
||||
return true;
|
||||
}
|
||||
|
||||
@NbBundle.Messages({"ResetWindowAction.confirm.title=Reset Windows",
|
||||
"ResetWindowAction.confirm.text=The program will close and restart to perform the resetting of window locations.\n\nAre you sure you want to reset all window locations?"})
|
||||
@NbBundle.Messages({"ResetWindowAction.confirm.text=In order to perform the resetting of window locations the software will close and restart. "
|
||||
+ "If a case is currently open, it will be closed. If ingest or a search is currently running, it will be terminated. "
|
||||
+ "Are you sure you want to restart the software to reset all window locations?",
|
||||
"ResetWindowAction.caseCloseFailure.text=Unable to close the current case, "
|
||||
+ "the software will restart and the windows locations will reset the next time the software is closed.",
|
||||
"ResetWindowAction.caseSaveMetadata.text=Unable to save current case path, "
|
||||
+ "the software will restart and the windows locations will reset but the current case will not be opened upon restart."})
|
||||
|
||||
@Override
|
||||
public void performAction() {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
int response = JOptionPane.showConfirmDialog(
|
||||
WindowManager.getDefault().getMainWindow(),
|
||||
Bundle.ResetWindowAction_confirm_text(),
|
||||
Bundle.ResetWindowAction_confirm_title(),
|
||||
JOptionPane.YES_NO_OPTION, JOptionPane.PLAIN_MESSAGE);
|
||||
if (response == JOptionPane.YES_OPTION) {
|
||||
boolean response = MessageNotifyUtil.Message.confirm(Bundle.ResetWindowAction_confirm_text());
|
||||
if (response) {
|
||||
//adding the shutdown hook, closing the current case, and marking for restart can be re-ordered if slightly different behavior is desired
|
||||
Runtime.getRuntime().addShutdownHook(new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
FileUtils.deleteDirectory(new File(PlatformUtil.getUserConfigDirectory() + File.separator + "Windows2Local"));
|
||||
FileUtils.deleteDirectory(new File(PlatformUtil.getUserConfigDirectory() + File.separator + WINDOWS2LOCAL));
|
||||
} catch (IOException ex) {
|
||||
logger.log(Level.WARNING, "Unable to delete config directory, window locations will not be reset.", ex);
|
||||
//While we would like the user to be aware of this in the unlikely event that the directory can not be deleted
|
||||
//Because our deletion is being attempted in a shutdown hook I don't know that we can pop up UI elements during the shutdown proces
|
||||
logger.log(Level.SEVERE, "Unable to delete config directory, window locations will not be reset. To manually reset the windows please delete the following directory while the software is closed. " + PlatformUtil.getUserConfigDirectory() + File.separator + "Windows2Local", ex);
|
||||
}
|
||||
}
|
||||
});
|
||||
LifecycleManager.getDefault().markForRestart();
|
||||
LifecycleManager.getDefault().exit();
|
||||
try {
|
||||
if (Case.isCaseOpen()) {
|
||||
String caseMetadataFilePath = Case.getCurrentCase().getMetadata().getFilePath().toString();
|
||||
File caseToOpenFile = new File(ResetWindowsAction.getCaseToReopenFilePath());
|
||||
Charset encoding = null; //prevents writeStringToFile from having ambiguous arguments
|
||||
FileUtils.writeStringToFile(caseToOpenFile, caseMetadataFilePath, encoding);
|
||||
Case.closeCurrentCase();
|
||||
}
|
||||
// The method markForRestart can not be undone once it is called.
|
||||
LifecycleManager.getDefault().markForRestart();
|
||||
//we need to call exit last
|
||||
LifecycleManager.getDefault().exit();
|
||||
} catch (CaseActionException ex) {
|
||||
logger.log(Level.WARNING, Bundle.ResetWindowAction_caseCloseFailure_text(), ex);
|
||||
MessageNotifyUtil.Message.show(Bundle.ResetWindowAction_caseCloseFailure_text(), MessageNotifyUtil.MessageType.ERROR);
|
||||
} catch (IOException ex) {
|
||||
logger.log(Level.WARNING, Bundle.ResetWindowAction_caseSaveMetadata_text(), ex);
|
||||
MessageNotifyUtil.Message.show(Bundle.ResetWindowAction_caseSaveMetadata_text(), MessageNotifyUtil.MessageType.ERROR);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static String getCaseToReopenFilePath(){
|
||||
return PlatformUtil.getUserConfigDirectory() + File.separator + CASE_TO_REOPEN_FILE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this action to be enabled/disabled
|
||||
@@ -91,6 +119,7 @@ public final class ResetWindowsAction extends CallableSystemAction {
|
||||
* @param value whether to enable this action or not
|
||||
*/
|
||||
@Override
|
||||
|
||||
public void setEnabled(boolean value) {
|
||||
super.setEnabled(value);
|
||||
}
|
||||
|
||||
@@ -346,6 +346,12 @@ RecentCases.getName.text=Clear Recent Cases
|
||||
RecentItems.openRecentCase.msgDlg.text=Case {0} no longer exists.
|
||||
SelectDataSourceProcessorPanel.name.text=Select Data Source Type
|
||||
StartupWindow.title.text=Welcome
|
||||
# {0} - autFilePath
|
||||
StartupWindowProvider.openCase.cantOpen=Unable to open previously open case with metadata file: {0}
|
||||
# {0} - reOpenFilePath
|
||||
StartupWindowProvider.openCase.deleteOpenFailure=Unable to open or delete file containing path {0} to previously open case. The previous case will not be opened.
|
||||
# {0} - autFilePath
|
||||
StartupWindowProvider.openCase.noFile=Unable to open previously open case because metadata file not found at: {0}
|
||||
UnpackagePortableCaseDialog.title.text=Unpackage Portable Case
|
||||
UnpackagePortableCaseDialog.UnpackagePortableCaseDialog.extensions=Portable case package (.zip, .zip.001)
|
||||
UnpackagePortableCaseDialog.validatePaths.badExtension=File extension must be .zip or .zip.001
|
||||
|
||||
@@ -1934,7 +1934,7 @@ public class Case {
|
||||
*
|
||||
* @return A CaseMetaData object.
|
||||
*/
|
||||
CaseMetadata getMetadata() {
|
||||
public CaseMetadata getMetadata() {
|
||||
return metadata;
|
||||
}
|
||||
|
||||
|
||||
@@ -218,7 +218,7 @@ public final class CaseMetadata {
|
||||
*
|
||||
* @return The path to the metadata file
|
||||
*/
|
||||
Path getFilePath() {
|
||||
public Path getFilePath() {
|
||||
return metadataFilePath;
|
||||
}
|
||||
|
||||
|
||||
@@ -284,10 +284,10 @@ public class ImageDSProcessor implements DataSourceProcessor, AutoIngestDataSour
|
||||
ingestStream = IngestManager.getInstance().openIngestStream(image, settings);
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Error starting ingest modules", ex);
|
||||
final List<String> errors = new ArrayList<>();
|
||||
errors.add(ex.getMessage());
|
||||
callBack.done(DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS, errors, new ArrayList<>());
|
||||
return;
|
||||
// There was an error with ingest, but the data source has already been added
|
||||
// so proceed with the defaultIngestStream. Code in openIngestStream
|
||||
// should have caused a dialog to popup with the errors.
|
||||
ingestStream = new DefaultIngestStream();
|
||||
}
|
||||
|
||||
doAddImageProcess(deviceId, imagePath, sectorSize, timeZone, ignoreFatOrphanFiles, md5, sha1, sha256, progress, callBack);
|
||||
|
||||
@@ -18,12 +18,18 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.casemodule;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.logging.Level;
|
||||
import org.netbeans.spi.sendopts.OptionProcessor;
|
||||
import javax.swing.SwingUtilities;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.openide.util.Lookup;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.apputils.ResetWindowsAction;
|
||||
import org.sleuthkit.autopsy.commandlineingest.CommandLineIngestManager;
|
||||
import org.sleuthkit.autopsy.commandlineingest.CommandLineOpenCaseManager;
|
||||
import org.sleuthkit.autopsy.commandlineingest.CommandLineOptionProcessor;
|
||||
@@ -61,15 +67,22 @@ public class StartupWindowProvider implements StartupWindowInterface {
|
||||
return instance;
|
||||
}
|
||||
|
||||
@NbBundle.Messages({
|
||||
"# {0} - autFilePath",
|
||||
"StartupWindowProvider.openCase.noFile=Unable to open previously open case because metadata file not found at: {0}",
|
||||
"# {0} - reOpenFilePath",
|
||||
"StartupWindowProvider.openCase.deleteOpenFailure=Unable to open or delete file containing path {0} to previously open case. The previous case will not be opened.",
|
||||
"# {0} - autFilePath",
|
||||
"StartupWindowProvider.openCase.cantOpen=Unable to open previously open case with metadata file: {0}"})
|
||||
private void init() {
|
||||
if (startupWindowToUse == null) {
|
||||
// first check whether we are running from command line
|
||||
if (isRunningFromCommandLine()) {
|
||||
|
||||
|
||||
String defaultArg = getDefaultArgument();
|
||||
if(defaultArg != null) {
|
||||
new CommandLineOpenCaseManager(defaultArg).start();
|
||||
return;
|
||||
if (defaultArg != null) {
|
||||
new CommandLineOpenCaseManager(defaultArg).start();
|
||||
return;
|
||||
} else {
|
||||
// Autopsy is running from command line
|
||||
logger.log(Level.INFO, "Running from command line"); //NON-NLS
|
||||
@@ -83,36 +96,41 @@ public class StartupWindowProvider implements StartupWindowInterface {
|
||||
if (RuntimeProperties.runningWithGUI()) {
|
||||
checkSolr();
|
||||
}
|
||||
|
||||
//discover the registered windows
|
||||
Collection<? extends StartupWindowInterface> startupWindows
|
||||
= Lookup.getDefault().lookupAll(StartupWindowInterface.class);
|
||||
|
||||
int windowsCount = startupWindows.size();
|
||||
if (windowsCount == 1) {
|
||||
startupWindowToUse = startupWindows.iterator().next();
|
||||
logger.log(Level.INFO, "Will use the default startup window: " + startupWindowToUse.toString()); //NON-NLS
|
||||
} else if (windowsCount == 2) {
|
||||
//pick the non default one
|
||||
Iterator<? extends StartupWindowInterface> it = startupWindows.iterator();
|
||||
while (it.hasNext()) {
|
||||
StartupWindowInterface window = it.next();
|
||||
if (!org.sleuthkit.autopsy.casemodule.StartupWindow.class.isInstance(window)) {
|
||||
startupWindowToUse = window;
|
||||
logger.log(Level.INFO, "Will use the custom startup window: " + startupWindowToUse.toString()); //NON-NLS
|
||||
break;
|
||||
switch (windowsCount) {
|
||||
case 1:
|
||||
startupWindowToUse = startupWindows.iterator().next();
|
||||
logger.log(Level.INFO, "Will use the default startup window: {0}", startupWindowToUse.toString()); //NON-NLS
|
||||
break;
|
||||
case 2: {
|
||||
//pick the non default one
|
||||
Iterator<? extends StartupWindowInterface> it = startupWindows.iterator();
|
||||
while (it.hasNext()) {
|
||||
StartupWindowInterface window = it.next();
|
||||
if (!org.sleuthkit.autopsy.casemodule.StartupWindow.class.isInstance(window)) {
|
||||
startupWindowToUse = window;
|
||||
logger.log(Level.INFO, "Will use the custom startup window: {0}", startupWindowToUse.toString()); //NON-NLS
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// select first non-Autopsy start up window
|
||||
Iterator<? extends StartupWindowInterface> it = startupWindows.iterator();
|
||||
while (it.hasNext()) {
|
||||
StartupWindowInterface window = it.next();
|
||||
if (!window.getClass().getCanonicalName().startsWith("org.sleuthkit.autopsy")) {
|
||||
startupWindowToUse = window;
|
||||
logger.log(Level.INFO, "Will use the custom startup window: " + startupWindowToUse.toString()); //NON-NLS
|
||||
break;
|
||||
default: {
|
||||
// select first non-Autopsy start up window
|
||||
Iterator<? extends StartupWindowInterface> it = startupWindows.iterator();
|
||||
while (it.hasNext()) {
|
||||
StartupWindowInterface window = it.next();
|
||||
if (!window.getClass().getCanonicalName().startsWith("org.sleuthkit.autopsy")) {
|
||||
startupWindowToUse = window;
|
||||
logger.log(Level.INFO, "Will use the custom startup window: {0}", startupWindowToUse.toString()); //NON-NLS
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,6 +139,45 @@ public class StartupWindowProvider implements StartupWindowInterface {
|
||||
startupWindowToUse = new org.sleuthkit.autopsy.casemodule.StartupWindow();
|
||||
}
|
||||
}
|
||||
File openPreviousCaseFile = new File(ResetWindowsAction.getCaseToReopenFilePath());
|
||||
|
||||
if (openPreviousCaseFile.exists()) {
|
||||
//do actual opening on another thread
|
||||
new Thread(() -> {
|
||||
String caseFilePath = "";
|
||||
String unableToOpenMessage = null;
|
||||
try {
|
||||
//avoid readFileToString having ambiguous arguments
|
||||
Charset encoding = null;
|
||||
caseFilePath = FileUtils.readFileToString(openPreviousCaseFile, encoding);
|
||||
if (new File(caseFilePath).exists()) {
|
||||
FileUtils.forceDelete(openPreviousCaseFile);
|
||||
//close the startup window as we attempt to open the case
|
||||
close();
|
||||
Case.openAsCurrentCase(caseFilePath);
|
||||
|
||||
} else {
|
||||
unableToOpenMessage = Bundle.StartupWindowProvider_openCase_noFile(caseFilePath);
|
||||
logger.log(Level.WARNING, unableToOpenMessage);
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
unableToOpenMessage = Bundle.StartupWindowProvider_openCase_deleteOpenFailure(ResetWindowsAction.getCaseToReopenFilePath());
|
||||
logger.log(Level.WARNING, unableToOpenMessage, ex);
|
||||
} catch (CaseActionException ex) {
|
||||
unableToOpenMessage = Bundle.StartupWindowProvider_openCase_cantOpen(caseFilePath);
|
||||
logger.log(Level.WARNING, unableToOpenMessage, ex);
|
||||
}
|
||||
|
||||
if (RuntimeProperties.runningWithGUI() && !StringUtils.isBlank(unableToOpenMessage)) {
|
||||
final String message = unableToOpenMessage;
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
MessageNotifyUtil.Message.warn(message);
|
||||
//the case was not opened restore the startup window
|
||||
open();
|
||||
});
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
}
|
||||
|
||||
private void checkSolr() {
|
||||
@@ -147,9 +204,9 @@ public class StartupWindowProvider implements StartupWindowInterface {
|
||||
* @return True if running from command line, false otherwise
|
||||
*/
|
||||
private boolean isRunningFromCommandLine() {
|
||||
|
||||
|
||||
CommandLineOptionProcessor processor = Lookup.getDefault().lookup(CommandLineOptionProcessor.class);
|
||||
if(processor != null) {
|
||||
if (processor != null) {
|
||||
return processor.isRunFromCommandLine();
|
||||
}
|
||||
return false;
|
||||
@@ -157,12 +214,12 @@ public class StartupWindowProvider implements StartupWindowInterface {
|
||||
|
||||
/**
|
||||
* Get the default argument from the CommandLineOptionProcessor.
|
||||
*
|
||||
* @return If set, the default argument otherwise null.
|
||||
*
|
||||
* @return If set, the default argument otherwise null.
|
||||
*/
|
||||
private String getDefaultArgument() {
|
||||
private String getDefaultArgument() {
|
||||
CommandLineOptionProcessor processor = Lookup.getDefault().lookup(CommandLineOptionProcessor.class);
|
||||
if(processor != null) {
|
||||
if (processor != null) {
|
||||
return processor.getDefaultArgument();
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -301,7 +301,7 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
|
||||
|
||||
|
||||
/**
|
||||
* Values for configuration located in the /etc/*.conf file.
|
||||
* Values for configuration located in the /etc/\*.conf file.
|
||||
*/
|
||||
private static class ConfValues {
|
||||
private final String XmxVal;
|
||||
@@ -335,7 +335,7 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the /etc/*.conf file values pertinent to settings.
|
||||
* Retrieve the /etc/\*.conf file values pertinent to settings.
|
||||
* @return The conf file values.
|
||||
* @throws IOException
|
||||
*/
|
||||
|
||||
@@ -376,6 +376,10 @@ TagNode.propertySheet.origNameDisplayName=Original Name
|
||||
TagsNode.displayName.text=Tags
|
||||
TagsNode.createSheet.name.name=Name
|
||||
TagsNode.createSheet.name.displayName=Name
|
||||
UnsupportedContentNode.createSheet.name.desc=no description
|
||||
UnsupportedContentNode.createSheet.name.displayName=Name
|
||||
UnsupportedContentNode.createSheet.name.name=Name
|
||||
UnsupportedContentNode.displayName=Unsupported Content
|
||||
ViewsNode.name.text=Views
|
||||
ViewsNode.createSheet.name.name=Name
|
||||
ViewsNode.createSheet.name.displayName=Name
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.datamodel;
|
||||
|
||||
import org.sleuthkit.autopsy.datamodel.OsAccounts.OsAccountNode;
|
||||
|
||||
/**
|
||||
* Visitor Pattern interface that goes over Content nodes in the data source
|
||||
* area of the tree.
|
||||
@@ -50,6 +52,9 @@ interface ContentNodeVisitor<T> {
|
||||
|
||||
T visit(BlackboardArtifactNode bban);
|
||||
|
||||
T visit(UnsupportedContentNode ucn);
|
||||
|
||||
T visit(OsAccountNode bban);
|
||||
|
||||
/**
|
||||
* Visitor with an implementable default behavior for all types. Override
|
||||
@@ -122,5 +127,15 @@ interface ContentNodeVisitor<T> {
|
||||
public T visit(BlackboardArtifactNode bban) {
|
||||
return defaultVisit(bban);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T visit(UnsupportedContentNode ucn) {
|
||||
return defaultVisit(ucn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T visit(OsAccountNode bban) {
|
||||
return defaultVisit(bban);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ import org.sleuthkit.datamodel.Pool;
|
||||
import org.sleuthkit.datamodel.SlackFile;
|
||||
import org.sleuthkit.datamodel.SleuthkitItemVisitor;
|
||||
import org.sleuthkit.datamodel.SleuthkitVisitableItem;
|
||||
import org.sleuthkit.datamodel.UnsupportedContent;
|
||||
import org.sleuthkit.datamodel.VirtualDirectory;
|
||||
import org.sleuthkit.datamodel.Volume;
|
||||
|
||||
@@ -99,6 +100,11 @@ public class CreateSleuthkitNodeVisitor extends SleuthkitItemVisitor.Default<Abs
|
||||
public AbstractContentNode<? extends Content> visit(BlackboardArtifact art) {
|
||||
return new BlackboardArtifactNode(art);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractContentNode<? extends Content> visit(UnsupportedContent uc) {
|
||||
return new UnsupportedContentNode(uc);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AbstractContentNode<? extends Content> defaultVisit(SleuthkitVisitableItem di) {
|
||||
|
||||
@@ -202,6 +202,11 @@ public interface DisplayableItemNodeVisitor<T> {
|
||||
T visit(HostNode node);
|
||||
|
||||
T visit(DataSourcesByTypeNode node);
|
||||
|
||||
/*
|
||||
* Unsupported node
|
||||
*/
|
||||
T visit(UnsupportedContentNode ucn);
|
||||
|
||||
/**
|
||||
* Visitor with an implementable default behavior for all types. Override
|
||||
@@ -574,5 +579,10 @@ public interface DisplayableItemNodeVisitor<T> {
|
||||
public T visit(PersonGroupingNode node) {
|
||||
return defaultVisit(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T visit(UnsupportedContentNode node) {
|
||||
return defaultVisit(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.datamodel;
|
||||
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -29,18 +30,26 @@ import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.Action;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.openide.nodes.ChildFactory;
|
||||
import org.openide.nodes.Children;
|
||||
import org.openide.nodes.Node;
|
||||
import org.openide.nodes.Sheet;
|
||||
import org.openide.util.Exceptions;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.openide.util.lookup.Lookups;
|
||||
import org.openide.util.WeakListeners;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.events.OsAccountChangedEvent;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance;
|
||||
import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import static org.sleuthkit.autopsy.datamodel.AbstractContentNode.backgroundTasksPool;
|
||||
import org.sleuthkit.autopsy.events.AutopsyEvent;
|
||||
import org.sleuthkit.datamodel.Host;
|
||||
import org.sleuthkit.datamodel.OsAccount;
|
||||
import org.sleuthkit.datamodel.OsAccountRealm;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
import org.sleuthkit.datamodel.Tag;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.TskDataException;
|
||||
|
||||
@@ -52,6 +61,7 @@ public final class OsAccounts implements AutopsyVisitableItem {
|
||||
private static final Logger logger = Logger.getLogger(OsAccounts.class.getName());
|
||||
private static final String ICON_PATH = "org/sleuthkit/autopsy/images/os-account.png";
|
||||
private static final SimpleDateFormat DATE_FORMATTER = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
|
||||
private static final String REALM_DATA_AVAILABLE_EVENT = "REALM_DATA_AVAILABLE_EVENT";
|
||||
|
||||
private SleuthkitCase skCase;
|
||||
private final long filteringDSObjId;
|
||||
@@ -114,9 +124,9 @@ public final class OsAccounts implements AutopsyVisitableItem {
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
String eventType = evt.getPropertyName();
|
||||
if(eventType.equals(Case.Events.OS_ACCOUNT_ADDED.toString())
|
||||
if (eventType.equals(Case.Events.OS_ACCOUNT_ADDED.toString())
|
||||
|| eventType.equals(Case.Events.OS_ACCOUNT_REMOVED.toString())) {
|
||||
refresh(true);
|
||||
refresh(true);
|
||||
} else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
|
||||
// case was closed. Remove listeners so that we don't get called with a stale case handle
|
||||
if (evt.getNewValue() == null) {
|
||||
@@ -126,22 +136,22 @@ public final class OsAccounts implements AutopsyVisitableItem {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@Override
|
||||
protected void addNotify() {
|
||||
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.OS_ACCOUNT_ADDED, Case.Events.OS_ACCOUNT_REMOVED), listener);
|
||||
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), listener);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void removeNotify() {
|
||||
Case.removeEventTypeSubscriber(Collections.singleton(Case.Events.OS_ACCOUNT_ADDED), listener);
|
||||
Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), listener);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected boolean createKeys(List<OsAccount> list) {
|
||||
if(skCase != null) {
|
||||
if (skCase != null) {
|
||||
try {
|
||||
if (filteringDSObjId == 0) {
|
||||
list.addAll(skCase.getOsAccountManager().getOsAccounts());
|
||||
@@ -166,35 +176,52 @@ public final class OsAccounts implements AutopsyVisitableItem {
|
||||
/**
|
||||
* An OsAccount leaf Node.
|
||||
*/
|
||||
public static final class OsAccountNode extends DisplayableItemNode {
|
||||
public static final class OsAccountNode extends AbstractContentNode<OsAccount> {
|
||||
|
||||
private OsAccount account;
|
||||
|
||||
|
||||
private final PropertyChangeListener listener = new PropertyChangeListener() {
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
if(((OsAccountChangedEvent)evt).getOsAccount().getId() == account.getId()) {
|
||||
// Update the account node to the new one
|
||||
account = ((OsAccountChangedEvent)evt).getOsAccount();
|
||||
updateSheet();
|
||||
if (evt.getPropertyName().equals(Case.Events.OS_ACCOUNT_CHANGED.name())) {
|
||||
if (((OsAccountChangedEvent) evt).getOsAccount().getId() == account.getId()) {
|
||||
// Update the account node to the new one
|
||||
account = ((OsAccountChangedEvent) evt).getOsAccount();
|
||||
updateSheet();
|
||||
}
|
||||
} else if (evt.getPropertyName().equals(REALM_DATA_AVAILABLE_EVENT)) {
|
||||
OsAccountRealm realm = (OsAccountRealm) evt.getNewValue();
|
||||
|
||||
// Currently only 0 or 1 names are supported, this will need
|
||||
// to be modified if that changes.
|
||||
List<String> realmNames = realm.getRealmNames();
|
||||
if (!realmNames.isEmpty()) {
|
||||
updateSheet(new NodeProperty<>(
|
||||
Bundle.OsAccounts_accountRealmNameProperty_name(),
|
||||
Bundle.OsAccounts_accountRealmNameProperty_displayName(),
|
||||
Bundle.OsAccounts_accountRealmNameProperty_desc(),
|
||||
""));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private final PropertyChangeListener weakListener = WeakListeners.propertyChange(listener, null);
|
||||
|
||||
/**
|
||||
* Constructs a new OsAccountNode.
|
||||
*
|
||||
* @param account Node object.
|
||||
*/
|
||||
OsAccountNode(OsAccount account) {
|
||||
super(Children.LEAF, Lookups.fixed(account));
|
||||
super(account);
|
||||
this.account = account;
|
||||
|
||||
setName(account.getName());
|
||||
setDisplayName(account.getName());
|
||||
setIconBaseWithExtension(ICON_PATH);
|
||||
|
||||
Case.addEventTypeSubscriber(Collections.singleton(Case.Events.OS_ACCOUNT_CHANGED), listener);
|
||||
|
||||
Case.addEventTypeSubscriber(Collections.singleton(Case.Events.OS_ACCOUNT_CHANGED), weakListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -211,7 +238,16 @@ public final class OsAccounts implements AutopsyVisitableItem {
|
||||
public String getItemType() {
|
||||
return getClass().getName();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the OsAccount associated with this node.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
OsAccount getOsAccount() {
|
||||
return account;
|
||||
}
|
||||
|
||||
@Messages({
|
||||
"OsAccounts_accountNameProperty_name=Name",
|
||||
"OsAccounts_accountNameProperty_displayName=Name",
|
||||
@@ -226,13 +262,13 @@ public final class OsAccounts implements AutopsyVisitableItem {
|
||||
"OsAccounts_loginNameProperty_displayName=Login Name",
|
||||
"OsAccounts_loginNameProperty_desc=Os Account login name"
|
||||
})
|
||||
|
||||
|
||||
/**
|
||||
* Refreshes this node's property sheet.
|
||||
*/
|
||||
void updateSheet() {
|
||||
this.setSheet(createSheet());
|
||||
}
|
||||
* Refreshes this node's property sheet.
|
||||
*/
|
||||
void updateSheet() {
|
||||
this.setSheet(createSheet());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Sheet createSheet() {
|
||||
@@ -255,9 +291,8 @@ public final class OsAccounts implements AutopsyVisitableItem {
|
||||
Bundle.OsAccounts_loginNameProperty_displayName(),
|
||||
Bundle.OsAccounts_loginNameProperty_desc(),
|
||||
optional.isPresent() ? optional.get() : ""));
|
||||
// TODO - load realm on background thread
|
||||
// Fill with empty string, fetch on background task.
|
||||
String realmName = "";
|
||||
//String realmName = account.getRealm().getRealmNames().isEmpty() ? "" : account.getRealm().getRealmNames().get(0);
|
||||
propertiesSet.put(new NodeProperty<>(
|
||||
Bundle.OsAccounts_accountRealmNameProperty_name(),
|
||||
Bundle.OsAccounts_accountRealmNameProperty_displayName(),
|
||||
@@ -274,16 +309,91 @@ public final class OsAccounts implements AutopsyVisitableItem {
|
||||
Bundle.OsAccounts_createdTimeProperty_desc(),
|
||||
timeDisplayStr));
|
||||
|
||||
backgroundTasksPool.submit(new GetOsAccountRealmTask(new WeakReference<>(this), weakListener));
|
||||
|
||||
return sheet;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Action[] getActions(boolean popup) {
|
||||
List<Action> actionsList = new ArrayList<>();
|
||||
actionsList.addAll(Arrays.asList(super.getActions(popup)));
|
||||
actionsList.addAll(DataModelActionsFactory.getActions(account));
|
||||
|
||||
|
||||
return actionsList.toArray(new Action[actionsList.size()]);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Tag> getAllTagsFromDatabase() {
|
||||
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CorrelationAttributeInstance getCorrelationAttributeInstance() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Pair<DataResultViewerTable.Score, String> getScorePropertyAndDescription(List<Tag> tags) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DataResultViewerTable.HasCommentStatus getCommentProperty(List<Tag> tags, CorrelationAttributeInstance attribute) {
|
||||
return DataResultViewerTable.HasCommentStatus.NO_COMMENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Pair<Long, String> getCountPropertyAndDescription(CorrelationAttributeInstance.Type attributeType, String attributeValue, String defaultDescription) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(ContentNodeVisitor<T> visitor) {
|
||||
return visitor.visit(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Task for grabbing the osAccount realm.
|
||||
*/
|
||||
static class GetOsAccountRealmTask implements Runnable {
|
||||
|
||||
private final WeakReference<OsAccountNode> weakNodeRef;
|
||||
private final PropertyChangeListener listener;
|
||||
|
||||
/**
|
||||
* Construct a new task.
|
||||
*
|
||||
* @param weakContentRef
|
||||
* @param listener
|
||||
*/
|
||||
GetOsAccountRealmTask(WeakReference<OsAccountNode> weakContentRef, PropertyChangeListener listener) {
|
||||
this.weakNodeRef = weakContentRef;
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
OsAccountNode node = weakNodeRef.get();
|
||||
if (node == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
long realmId = node.getOsAccount().getRealmId();
|
||||
OsAccountRealm realm = Case.getCurrentCase().getSleuthkitCase().getOsAccountRealmManager().getRealmByRealmId(realmId);
|
||||
|
||||
if (listener != null && realm != null) {
|
||||
listener.propertyChange(new PropertyChangeEvent(
|
||||
AutopsyEvent.SourceType.LOCAL.toString(),
|
||||
REALM_DATA_AVAILABLE_EVENT,
|
||||
null, realm));
|
||||
}
|
||||
|
||||
} catch (TskCoreException ex) {
|
||||
Exceptions.printStackTrace(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2021 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.datamodel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.swing.Action;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.openide.nodes.Sheet;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance;
|
||||
import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable;
|
||||
import static org.sleuthkit.autopsy.datamodel.AbstractContentNode.NO_DESCR;
|
||||
import org.sleuthkit.datamodel.UnsupportedContent;
|
||||
import org.sleuthkit.datamodel.Tag;
|
||||
|
||||
/**
|
||||
* This class is used to represent the "Node" for an unsupported content object.
|
||||
*/
|
||||
public class UnsupportedContentNode extends AbstractContentNode<UnsupportedContent> {
|
||||
|
||||
/**
|
||||
*
|
||||
* @param unsupportedContent underlying Content instance
|
||||
*/
|
||||
@NbBundle.Messages({
|
||||
"UnsupportedContentNode.displayName=Unsupported Content",
|
||||
})
|
||||
public UnsupportedContentNode(UnsupportedContent unsupportedContent) {
|
||||
super(unsupportedContent);
|
||||
|
||||
// set name, display name, and icon
|
||||
this.setDisplayName(Bundle.UnsupportedContentNode_displayName());
|
||||
|
||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-icon.png"); //NON-NLS
|
||||
}
|
||||
|
||||
/**
|
||||
* Right click action for UnsupportedContentNode node
|
||||
*
|
||||
* @param popup
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Action[] getActions(boolean popup) {
|
||||
List<Action> actionsList = new ArrayList<>();
|
||||
|
||||
for (Action a : super.getActions(true)) {
|
||||
actionsList.add(a);
|
||||
}
|
||||
|
||||
return actionsList.toArray(new Action[actionsList.size()]);
|
||||
|
||||
}
|
||||
|
||||
@NbBundle.Messages({
|
||||
"UnsupportedContentNode.createSheet.name.name=Name",
|
||||
"UnsupportedContentNode.createSheet.name.displayName=Name",
|
||||
"UnsupportedContentNode.createSheet.name.desc=no description",
|
||||
})
|
||||
@Override
|
||||
protected Sheet createSheet() {
|
||||
Sheet sheet = super.createSheet();
|
||||
Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
|
||||
if (sheetSet == null) {
|
||||
sheetSet = Sheet.createPropertiesSet();
|
||||
sheet.put(sheetSet);
|
||||
}
|
||||
|
||||
sheetSet.put(new NodeProperty<>(Bundle.UnsupportedContentNode_createSheet_name_name(),
|
||||
Bundle.UnsupportedContentNode_createSheet_name_displayName(),
|
||||
Bundle.UnsupportedContentNode_createSheet_name_desc(),
|
||||
this.getDisplayName()));
|
||||
|
||||
return sheet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(ContentNodeVisitor<T> visitor) {
|
||||
return visitor.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
|
||||
return visitor.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getItemType() {
|
||||
return getClass().getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads and returns a list of all tags associated with this content node.
|
||||
*
|
||||
* Null implementation of an abstract method.
|
||||
*
|
||||
* @return list of tags associated with the node.
|
||||
*/
|
||||
@Override
|
||||
protected List<Tag> getAllTagsFromDatabase() {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns correlation attribute instance for the underlying content of the
|
||||
* node.
|
||||
*
|
||||
* Null implementation of an abstract method.
|
||||
*
|
||||
* @return correlation attribute instance for the underlying content of the
|
||||
* node.
|
||||
*/
|
||||
@Override
|
||||
protected CorrelationAttributeInstance getCorrelationAttributeInstance() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Score property for the node.
|
||||
*
|
||||
* Null implementation of an abstract method.
|
||||
*
|
||||
* @param tags list of tags.
|
||||
*
|
||||
* @return Score property for the underlying content of the node.
|
||||
*/
|
||||
@Override
|
||||
protected Pair<DataResultViewerTable.Score, String> getScorePropertyAndDescription(List<Tag> tags) {
|
||||
return Pair.of(DataResultViewerTable.Score.NO_SCORE, NO_DESCR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns comment property for the node.
|
||||
*
|
||||
* Null implementation of an abstract method.
|
||||
*
|
||||
* @param tags list of tags
|
||||
* @param attribute correlation attribute instance
|
||||
*
|
||||
* @return Comment property for the underlying content of the node.
|
||||
*/
|
||||
@Override
|
||||
protected DataResultViewerTable.HasCommentStatus getCommentProperty(List<Tag> tags, CorrelationAttributeInstance attribute) {
|
||||
return DataResultViewerTable.HasCommentStatus.NO_COMMENT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns occurrences/count property for the node.
|
||||
*
|
||||
* Null implementation of an abstract method.
|
||||
*
|
||||
* @param attributeType the type of the attribute to count
|
||||
* @param attributeValue the value of the attribute to coun
|
||||
* @param defaultDescription a description to use when none is determined by
|
||||
* the getCountPropertyAndDescription method
|
||||
*
|
||||
* @return count property for the underlying content of the node.
|
||||
*/
|
||||
@Override
|
||||
protected Pair<Long, String> getCountPropertyAndDescription(CorrelationAttributeInstance.Type attributeType, String attributeValue, String defaultDescription) {
|
||||
return Pair.of(-1L, NO_DESCR);
|
||||
}
|
||||
}
|
||||
@@ -59,6 +59,7 @@ SelectionContext.views=Views
|
||||
ViewContextAction.errorMessage.cannotFindDirectory=Failed to locate directory.
|
||||
ViewContextAction.errorMessage.cannotFindNode=Failed to locate data source node in tree.
|
||||
ViewContextAction.errorMessage.cannotSelectDirectory=Failed to select directory in tree.
|
||||
ViewContextAction.errorMessage.unsupportedParent=Unable to navigate to content not supported in this release.
|
||||
VolumeDetailsPanel.volumeIDLabel.text=Volume ID:
|
||||
VolumeDetailsPanel.volumeIDValue.text=...
|
||||
VolumeDetailsPanel.startValue.text=...
|
||||
|
||||
@@ -304,7 +304,6 @@ public class DataResultFilterNode extends FilterNode {
|
||||
NbBundle.getMessage(this.getClass(), "DataResultFilterNode.action.viewFileInDir.text"), c));
|
||||
}
|
||||
// action to go to the source file of the artifact
|
||||
// action to go to the source file of the artifact
|
||||
Content fileContent = ban.getLookup().lookup(AbstractFile.class);
|
||||
if (fileContent == null) {
|
||||
Content content = ban.getLookup().lookup(Content.class);
|
||||
|
||||
@@ -63,6 +63,7 @@ import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.TskData;
|
||||
import org.sleuthkit.datamodel.TskDataException;
|
||||
import org.sleuthkit.datamodel.UnsupportedContent;
|
||||
import org.sleuthkit.datamodel.VolumeSystem;
|
||||
|
||||
/**
|
||||
@@ -161,7 +162,8 @@ public class ViewContextAction extends AbstractAction {
|
||||
@Messages({
|
||||
"ViewContextAction.errorMessage.cannotFindDirectory=Failed to locate directory.",
|
||||
"ViewContextAction.errorMessage.cannotSelectDirectory=Failed to select directory in tree.",
|
||||
"ViewContextAction.errorMessage.cannotFindNode=Failed to locate data source node in tree."
|
||||
"ViewContextAction.errorMessage.cannotFindNode=Failed to locate data source node in tree.",
|
||||
"ViewContextAction.errorMessage.unsupportedParent=Unable to navigate to content not supported in this release."
|
||||
})
|
||||
public void actionPerformed(ActionEvent event) {
|
||||
EventQueue.invokeLater(() -> {
|
||||
@@ -181,6 +183,13 @@ public class ViewContextAction extends AbstractAction {
|
||||
logger.log(Level.SEVERE, String.format("Could not get parent of Content object: %s", content), ex); //NON-NLS
|
||||
return;
|
||||
}
|
||||
|
||||
if ((parentContent != null)
|
||||
&& (parentContent instanceof UnsupportedContent)) {
|
||||
MessageNotifyUtil.Message.error(Bundle.ViewContextAction_errorMessage_unsupportedParent());
|
||||
logger.log(Level.WARNING, String.format("Could not navigate to unsupported content with id: %d", parentContent.getId())); //NON-NLS
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the "Data Sources" node from the tree view.
|
||||
|
||||
@@ -60,7 +60,7 @@ final class ObjectDetectedFilterPanel extends AbstractDiscoveryFilterPanel {
|
||||
objectsList.clearList();
|
||||
List<String> setNames = DiscoveryUiUtils.getSetNames(BlackboardArtifact.ARTIFACT_TYPE.TSK_OBJECT_DETECTED, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DESCRIPTION);
|
||||
for (String name : setNames) {
|
||||
objectsList.addElement(name, null, null);
|
||||
objectsList.addElement(name, null, name);
|
||||
}
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Error loading object detected set names", ex);
|
||||
|
||||
@@ -31,6 +31,7 @@ import org.sleuthkit.datamodel.LocalFile;
|
||||
import org.sleuthkit.datamodel.LocalDirectory;
|
||||
import org.sleuthkit.datamodel.OsAccount;
|
||||
import org.sleuthkit.datamodel.SlackFile;
|
||||
import org.sleuthkit.datamodel.UnsupportedContent;
|
||||
import org.sleuthkit.datamodel.VirtualDirectory;
|
||||
|
||||
/**
|
||||
@@ -113,4 +114,9 @@ final class GetRootDirectoryVisitor extends GetFilesContentVisitor {
|
||||
public Collection<AbstractFile> visit(OsAccount art) {
|
||||
return getAllFromChildren(art);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<AbstractFile> visit(UnsupportedContent uc) {
|
||||
return getAllFromChildren(uc);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user