added dialog for orphaned nodes

This commit is contained in:
Greg DiCristofaro 2020-04-06 09:13:39 -04:00
parent 7331056633
commit c6a317ece0
4 changed files with 317 additions and 4 deletions

View File

@ -257,3 +257,7 @@ CasesDashboardTopComponent.refreshButton.text=Refresh
AutoIngestCasesDeletionDialog.jLabel1.text=Progress AutoIngestCasesDeletionDialog.jLabel1.text=Progress
CasesDashboardTopComponent.deleteOrphanCaseNodesButton.text=Delete Orphan Case Znodes CasesDashboardTopComponent.deleteOrphanCaseNodesButton.text=Delete Orphan Case Znodes
CasesDashboardTopComponent.deleteOrphanManifestNodesButton.text=Delete Orphan Manifest Znodes CasesDashboardTopComponent.deleteOrphanManifestNodesButton.text=Delete Orphan Manifest Znodes
DeleteOrphanCaseNodesDialog.descriptionText.text=The following znodes are no longer have an associated case. Would you like to delete them?
DeleteOrphanCaseNodesDialog.okButton.text=OK
DeleteOrphanCaseNodesDialog.cancelButton.text=Cancel
DeleteOrphanCaseNodesDialog.titleText.text=Delete The Following Znodes?

View File

@ -0,0 +1,123 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JDialogFormInfo">
<Properties>
<Property name="defaultCloseOperation" type="int" value="2"/>
<Property name="title" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="DeleteOrphanCaseNodesDialog.titleText.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<SyntheticProperties>
<SyntheticProperty name="formSizePolicy" type="int" value="1"/>
<SyntheticProperty name="generateCenter" type="boolean" value="false"/>
</SyntheticProperties>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jScrollPane" alignment="1" max="32767" attributes="0"/>
<Component id="descriptionText" alignment="1" max="32767" attributes="0"/>
<Group type="102" alignment="1" attributes="0">
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
<Component id="okButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="cancelButton" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="descriptionText" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="jScrollPane" pref="238" max="32767" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="cancelButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="okButton" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JLabel" name="descriptionText">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="DeleteOrphanCaseNodesDialog.descriptionText.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="verticalAlignment" type="int" value="1"/>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
</Component>
<Container class="javax.swing.JScrollPane" name="jScrollPane">
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JTextArea" name="znodesTextArea">
<Properties>
<Property name="editable" type="boolean" value="false"/>
<Property name="columns" type="int" value="20"/>
<Property name="lineWrap" type="boolean" value="true"/>
<Property name="rows" type="int" value="5"/>
</Properties>
</Component>
</SubComponents>
</Container>
<Component class="javax.swing.JButton" name="cancelButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="DeleteOrphanCaseNodesDialog.cancelButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cancelButtonActionPerformed"/>
</Events>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
</Component>
<Component class="javax.swing.JButton" name="okButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="DeleteOrphanCaseNodesDialog.okButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="okButtonActionPerformed"/>
</Events>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
</Component>
</SubComponents>
</Form>

View File

@ -0,0 +1,156 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2020-2020 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.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* This dialog shows the system administrator the orphaned znodes to be deleted.
* If 'OK' is selected, isOkSelected() will return true.
*/
public class DeleteOrphanCaseNodesDialog extends javax.swing.JDialog {
private static final String NEW_LINE = System.getProperty("line.separator");
private static final String DEFAULT_INDENT = " ";
private static final String COLON = ":";
private boolean okSelected = false;
/**
* Creates new form DeleteOrphanCaseNodesDialog
*/
public DeleteOrphanCaseNodesDialog(java.awt.Frame parent, boolean modal, Map<String, List<String>> znodes) {
super(parent, modal);
initComponents();
additionalInit(znodes);
}
private void additionalInit(Map<String, List<String>> znodes) {
String textAreaText = "";
if (znodes != null) {
textAreaText = znodes.entrySet().stream().map((kv) -> {
return Stream.concat(
Stream.of(kv.getKey() + COLON),
kv.getValue().stream().map((node) -> DEFAULT_INDENT + node))
.collect(Collectors.joining(NEW_LINE));
})
.collect(Collectors.joining(NEW_LINE));
}
znodesTextArea.setText(textAreaText);
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
javax.swing.JLabel descriptionText = new javax.swing.JLabel();
javax.swing.JScrollPane jScrollPane = new javax.swing.JScrollPane();
znodesTextArea = new javax.swing.JTextArea();
javax.swing.JButton cancelButton = new javax.swing.JButton();
javax.swing.JButton okButton = new javax.swing.JButton();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
setTitle(org.openide.util.NbBundle.getMessage(DeleteOrphanCaseNodesDialog.class, "DeleteOrphanCaseNodesDialog.titleText.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(descriptionText, org.openide.util.NbBundle.getMessage(DeleteOrphanCaseNodesDialog.class, "DeleteOrphanCaseNodesDialog.descriptionText.text")); // NOI18N
descriptionText.setVerticalAlignment(javax.swing.SwingConstants.TOP);
znodesTextArea.setEditable(false);
znodesTextArea.setColumns(20);
znodesTextArea.setLineWrap(true);
znodesTextArea.setRows(5);
jScrollPane.setViewportView(znodesTextArea);
org.openide.awt.Mnemonics.setLocalizedText(cancelButton, org.openide.util.NbBundle.getMessage(DeleteOrphanCaseNodesDialog.class, "DeleteOrphanCaseNodesDialog.cancelButton.text")); // NOI18N
cancelButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
cancelButtonActionPerformed(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(okButton, org.openide.util.NbBundle.getMessage(DeleteOrphanCaseNodesDialog.class, "DeleteOrphanCaseNodesDialog.okButton.text")); // NOI18N
okButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
okButtonActionPerformed(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jScrollPane, javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(descriptionText, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addGap(0, 0, Short.MAX_VALUE)
.addComponent(okButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(cancelButton)))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(descriptionText)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(jScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 238, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(cancelButton)
.addComponent(okButton))
.addContainerGap())
);
pack();
}// </editor-fold>//GEN-END:initComponents
private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed
okSelected = true;
dispose();
}//GEN-LAST:event_okButtonActionPerformed
private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed
dispose();
}//GEN-LAST:event_cancelButtonActionPerformed
/**
* If the system administrator selected OK.
* @return Whether or not 'OK' was selected by the system administrator.
*/
public boolean isOkSelected() {
return okSelected;
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JTextArea znodesTextArea;
// End of variables declaration//GEN-END:variables
}

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2019-2019 Basis Technology Corp. * Copyright 2019-2020 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -23,11 +23,9 @@ import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Set;
import java.util.logging.Level; import java.util.logging.Level;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.multiusercases.CoordinationServiceUtils; import org.sleuthkit.autopsy.casemodule.multiusercases.CoordinationServiceUtils;
@ -61,6 +59,10 @@ final class DeleteOrphanCaseNodesTask implements Runnable {
} }
/**
* Retrieves an instance of the coordination service in order to fetch znodes and potentially delete.
* @return The coordination service or null on error.
*/
private CoordinationService getCoordinationService() { private CoordinationService getCoordinationService() {
progress.progress(Bundle.DeleteOrphanCaseNodesTask_progress_connectingToCoordSvc()); progress.progress(Bundle.DeleteOrphanCaseNodesTask_progress_connectingToCoordSvc());
logger.log(Level.INFO, Bundle.DeleteOrphanCaseNodesTask_progress_connectingToCoordSvc()); logger.log(Level.INFO, Bundle.DeleteOrphanCaseNodesTask_progress_connectingToCoordSvc());
@ -74,6 +76,11 @@ final class DeleteOrphanCaseNodesTask implements Runnable {
} }
/**
* Retrieves node paths for cases.
* @param coordinationService The coordination service to use in order to fetch the node paths.
* @return The list of node paths for cases.
*/
private List<String> getNodePaths(CoordinationService coordinationService) { private List<String> getNodePaths(CoordinationService coordinationService) {
progress.progress(Bundle.DeleteOrphanCaseNodesTask_progress_gettingCaseZnodes()); progress.progress(Bundle.DeleteOrphanCaseNodesTask_progress_gettingCaseZnodes());
logger.log(Level.INFO, Bundle.DeleteOrphanCaseNodesTask_progress_gettingCaseZnodes()); logger.log(Level.INFO, Bundle.DeleteOrphanCaseNodesTask_progress_gettingCaseZnodes());
@ -98,6 +105,11 @@ final class DeleteOrphanCaseNodesTask implements Runnable {
paths.add(path); paths.add(path);
} }
/**
* Determines orphaned znode paths.
* @param nodePaths The list of case node paths.
* @return The list of orphaned node paths.
*/
private Map<String, List<String>> getOrphanedNodes(List<String> nodePaths) { private Map<String, List<String>> getOrphanedNodes(List<String> nodePaths) {
progress.progress(Bundle.DeleteOrphanCaseNodesTask_progress_lookingForOrphanedCaseZnodes()); progress.progress(Bundle.DeleteOrphanCaseNodesTask_progress_lookingForOrphanedCaseZnodes());
logger.log(Level.INFO, Bundle.DeleteOrphanCaseNodesTask_progress_lookingForOrphanedCaseZnodes()); logger.log(Level.INFO, Bundle.DeleteOrphanCaseNodesTask_progress_lookingForOrphanedCaseZnodes());
@ -125,6 +137,16 @@ final class DeleteOrphanCaseNodesTask implements Runnable {
return nodePathsToDelete; return nodePathsToDelete;
} }
/**
* prompts the user with a list of orphaned znodes.
* @param orphanedNodes The orphaned znodes.
* @return True if the user would like to proceed deleting the znodes.
*/
private boolean promptUser(Map<String, List<String>> orphanedNodes) {
DeleteOrphanCaseNodesDialog dialog = new DeleteOrphanCaseNodesDialog(null, true, orphanedNodes);
return dialog.isOkSelected();
}
@Override @Override
@ -147,7 +169,7 @@ final class DeleteOrphanCaseNodesTask implements Runnable {
Map<String, List<String>> orphanedNodes = getOrphanedNodes(nodePaths); Map<String, List<String>> orphanedNodes = getOrphanedNodes(nodePaths);
boolean continueDelete = displayToUser(orphanedNodes); boolean continueDelete = promptUser(orphanedNodes);
if (continueDelete) if (continueDelete)
deleteNodes(coordinationService, orphanedNodes); deleteNodes(coordinationService, orphanedNodes);
@ -169,6 +191,14 @@ final class DeleteOrphanCaseNodesTask implements Runnable {
} }
/**
* Deletes the orphaned znodes provided in the 'orphanedNodes' variable.
* @param coordinationService The coordination service to use for deletion.
* @param orphanedNodes A mapping of case to the orphaned znodes.
*
* @throws InterruptedException If the thread executing this task is
* interrupted during the delete operation.
*/
private void deleteNodes(CoordinationService coordinationService, Map<String, List<String>> orphanedNodes) { private void deleteNodes(CoordinationService coordinationService, Map<String, List<String>> orphanedNodes) {
String caseName = null; String caseName = null;
String nodePath = null; String nodePath = null;