mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-17 02:07:42 +00:00
fixes and changes
This commit is contained in:
parent
2062ab5113
commit
0415a4eef1
@ -353,15 +353,16 @@ public class JTablePanel<T> extends AbstractLoadableComponent<List<T>> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the selected item or null if no item is selected.
|
||||
* @return The selected item or null if no item is selected.
|
||||
* Returns the selected items or null if no item is selected.
|
||||
* @return The selected items or null if no item is selected.
|
||||
*/
|
||||
public T getSelectedItem() {
|
||||
public List<T> getSelectedItems() {
|
||||
int selectedRow = this.table.getSelectedRow();
|
||||
if (selectedRow < 0 || this.tableModel == null || selectedRow >= this.tableModel.getDataRows().size()) {
|
||||
int count = this.table.getSelectedRowCount();
|
||||
if (selectedRow < 0 || this.tableModel == null || selectedRow + count > this.tableModel.getDataRows().size()) {
|
||||
return null;
|
||||
} else {
|
||||
return this.tableModel.getDataRows().get(selectedRow);
|
||||
return this.tableModel.getDataRows().subList(selectedRow, selectedRow + count);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -63,13 +63,13 @@
|
||||
<Component id="categoryLabel" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="validationLabel" min="-2" pref="34" max="-2" attributes="0"/>
|
||||
<Component id="validationLabel" min="-2" pref="46" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="saveButton" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="cancelButton" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="cancelButton" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="saveButton" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace pref="12" max="32767" attributes="0"/>
|
||||
<EmptySpace pref="8" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
|
@ -54,6 +54,7 @@ class AddEditCategoryDialog extends javax.swing.JDialog {
|
||||
onValueUpdate(domainSuffixTextField.getText(), categoryTextField.getText());
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Main constructor if adding a new domain suffix.
|
||||
*
|
||||
@ -77,8 +78,6 @@ class AddEditCategoryDialog extends javax.swing.JDialog {
|
||||
initComponents();
|
||||
this.currentSuffixes = currentSuffixes;
|
||||
this.currentDomainCategory = currentDomainCategory;
|
||||
|
||||
|
||||
|
||||
// set title based on whether or not we are editing or adding
|
||||
// also don't allow editing of domain suffix if editing
|
||||
@ -93,9 +92,9 @@ class AddEditCategoryDialog extends javax.swing.JDialog {
|
||||
domainSuffixTextField.setEnabled(false);
|
||||
onValueUpdate(currentDomainCategory.getHostSuffix(), currentDomainCategory.getCategory());
|
||||
}
|
||||
|
||||
|
||||
validationLabel.setText("");
|
||||
|
||||
|
||||
categoryTextField.getDocument().addDocumentListener(updateListener);
|
||||
domainSuffixTextField.getDocument().addDocumentListener(updateListener);
|
||||
}
|
||||
@ -103,6 +102,7 @@ class AddEditCategoryDialog extends javax.swing.JDialog {
|
||||
/**
|
||||
* Returns the string value for the name in the input field if Ok pressed or
|
||||
* null if not.
|
||||
*
|
||||
* @return The string value for the name in the input field if Ok pressed or
|
||||
* null if not.
|
||||
*/
|
||||
@ -112,6 +112,7 @@ class AddEditCategoryDialog extends javax.swing.JDialog {
|
||||
|
||||
/**
|
||||
* Returns whether or not the value has been changed and saved by the user.
|
||||
*
|
||||
* @return Whether or not the value has been changed and saved by the user.
|
||||
*/
|
||||
boolean isChanged() {
|
||||
@ -126,7 +127,7 @@ class AddEditCategoryDialog extends javax.swing.JDialog {
|
||||
*/
|
||||
@Messages({
|
||||
"# {0} - maxSuffixLen",
|
||||
"AddEditCategoryDialog_onValueUpdate_badSuffix=Please provide a domain suffix that is no more than {0} characters.",
|
||||
"AddEditCategoryDialog_onValueUpdate_badSuffix=Please provide a domain suffix that is no more than {0} characters that includes at least one period.",
|
||||
"# {0} - maxCategoryLen",
|
||||
"AddEditCategoryDialog_onValueUpdate_badCategory=Please provide a category that is no more than {0} characters.",
|
||||
"AddEditCategoryDialog_onValueUpdate_suffixRepeat=Please provide a unique domain suffix.",
|
||||
@ -147,16 +148,18 @@ class AddEditCategoryDialog extends javax.swing.JDialog {
|
||||
}
|
||||
|
||||
String validationMessage = null;
|
||||
if (safeSuffixStr.trim().length() == 0 || safeSuffixStr.trim().length() > WebCategoriesDataModel.getMaxDomainSuffixLength()) {
|
||||
if (safeSuffixStr.trim().length() == 0
|
||||
|| safeSuffixStr.trim().length() > WebCategoriesDataModel.getMaxDomainSuffixLength()
|
||||
|| safeSuffixStr.indexOf('.') < 0) {
|
||||
validationMessage = Bundle.AddEditCategoryDialog_onValueUpdate_badSuffix(WebCategoriesDataModel.getMaxCategoryLength());
|
||||
|
||||
} else if (safeCategoryStr.trim().length() == 0 || safeCategoryStr.trim().length() > WebCategoriesDataModel.getMaxCategoryLength()) {
|
||||
validationMessage = Bundle.AddEditCategoryDialog_onValueUpdate_badCategory(WebCategoriesDataModel.getMaxCategoryLength());
|
||||
|
||||
} else if (currentSuffixes.contains(normalizedSuffix) &&
|
||||
(currentDomainCategory == null ||
|
||||
!normalizedSuffix.equals(currentDomainCategory.getHostSuffix()))) {
|
||||
|
||||
} else if (currentSuffixes.contains(normalizedSuffix)
|
||||
&& (currentDomainCategory == null
|
||||
|| !normalizedSuffix.equals(currentDomainCategory.getHostSuffix()))) {
|
||||
|
||||
validationMessage = Bundle.AddEditCategoryDialog_onValueUpdate_suffixRepeat();
|
||||
|
||||
} else if (currentDomainCategory != null
|
||||
@ -167,7 +170,7 @@ class AddEditCategoryDialog extends javax.swing.JDialog {
|
||||
}
|
||||
|
||||
saveButton.setEnabled(validationMessage == null);
|
||||
validationLabel.setText(validationMessage == null ? "" : validationMessage);
|
||||
validationLabel.setText(validationMessage == null ? "" : String.format("<html>%s</html>", validationMessage));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -246,12 +249,12 @@ class AddEditCategoryDialog extends javax.swing.JDialog {
|
||||
.addComponent(categoryTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(categoryLabel))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(validationLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 34, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(validationLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 46, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(saveButton)
|
||||
.addComponent(cancelButton))
|
||||
.addContainerGap(12, Short.MAX_VALUE))
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(cancelButton)
|
||||
.addComponent(saveButton))
|
||||
.addContainerGap(8, Short.MAX_VALUE))
|
||||
);
|
||||
|
||||
pack();
|
||||
|
@ -4,7 +4,7 @@ AddEditCategoryDialog.categoryLabel.text=Category:
|
||||
AddEditCategoryDialog.domainSuffixLabel.text=Domain Suffix:
|
||||
AddEditCategoryDialog.saveButton.text=Save
|
||||
AddEditCategoryDialog.cancelButton.text=Cancel
|
||||
WebCategoriesOptionsPanel.panelDescription.text=This module allows you to find web categories based on host name.
|
||||
WebCategoriesOptionsPanel.panelDescription.text=This module allows you to classify web sites based on domain names.
|
||||
WebCategoriesOptionsPanel.categoriesTitle.text=Categories:
|
||||
WebCategoriesOptionsPanel.newEntryButton.text=New Entry
|
||||
WebCategoriesOptionsPanel.editEntryButton.text=Edit Entry
|
||||
|
@ -3,7 +3,7 @@ AddEditCategoryDialog_Edit=Edit Entry
|
||||
# {0} - maxCategoryLen
|
||||
AddEditCategoryDialog_onValueUpdate_badCategory=Please provide a category that is no more than {0} characters.
|
||||
# {0} - maxSuffixLen
|
||||
AddEditCategoryDialog_onValueUpdate_badSuffix=Please provide a domain suffix that is no more than {0} characters.
|
||||
AddEditCategoryDialog_onValueUpdate_badSuffix=Please provide a domain suffix that is no more than {0} characters that includes at least one period.
|
||||
AddEditCategoryDialog_onValueUpdate_sameCategory=Please provide a new category for this domain suffix.
|
||||
AddEditCategoryDialog_onValueUpdate_suffixRepeat=Please provide a unique domain suffix.
|
||||
WebCategoriesOptionsPanel_categoryTable_categoryColumnName=Category
|
||||
@ -19,7 +19,7 @@ AddEditCategoryDialog.categoryLabel.text=Category:
|
||||
AddEditCategoryDialog.domainSuffixLabel.text=Domain Suffix:
|
||||
AddEditCategoryDialog.saveButton.text=Save
|
||||
AddEditCategoryDialog.cancelButton.text=Cancel
|
||||
WebCategoriesOptionsPanel.panelDescription.text=This module allows you to find web categories based on host name.
|
||||
WebCategoriesOptionsPanel.panelDescription.text=This module allows you to classify web sites based on domain names.
|
||||
WebCategoriesOptionsPanel.categoriesTitle.text=Categories:
|
||||
WebCategoriesOptionsPanel.newEntryButton.text=New Entry
|
||||
WebCategoriesOptionsPanel.editEntryButton.text=Edit Entry
|
||||
|
@ -28,7 +28,9 @@ import org.sleuthkit.autopsy.url.analytics.DomainCategorizerException;
|
||||
import org.sleuthkit.autopsy.url.analytics.DomainCategory;
|
||||
|
||||
/**
|
||||
* A DomainCategoryProvider for custom web categories.
|
||||
* A DomainCategoryProvider for custom web categories. NOTE: If this class
|
||||
* package or name change, code in DomainCategoryRunner will also need to change
|
||||
* to reflect the changing class name for ordering purposes.
|
||||
*/
|
||||
@ServiceProvider(service = DomainCategorizer.class)
|
||||
public class CustomWebCategorizer implements DomainCategorizer {
|
||||
|
@ -89,6 +89,9 @@
|
||||
</Container>
|
||||
<Component class="javax.swing.JButton" name="newEntryButton">
|
||||
<Properties>
|
||||
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
|
||||
<Image iconType="3" name="/org/sleuthkit/autopsy/images/add16.png"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/url/analytics/domaincategorization/Bundle.properties" key="WebCategoriesOptionsPanel.newEntryButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
@ -104,6 +107,9 @@
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="editEntryButton">
|
||||
<Properties>
|
||||
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
|
||||
<Image iconType="3" name="/org/sleuthkit/autopsy/images/edit16.png"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/url/analytics/domaincategorization/Bundle.properties" key="WebCategoriesOptionsPanel.editEntryButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
@ -119,6 +125,9 @@
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="deleteEntryButton">
|
||||
<Properties>
|
||||
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
|
||||
<Image iconType="3" name="/org/sleuthkit/autopsy/images/delete16.png"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/url/analytics/domaincategorization/Bundle.properties" key="WebCategoriesOptionsPanel.deleteEntryButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
@ -134,6 +143,9 @@
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="importSetButton">
|
||||
<Properties>
|
||||
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
|
||||
<Image iconType="3" name="/org/sleuthkit/autopsy/images/import16.png"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/url/analytics/domaincategorization/Bundle.properties" key="WebCategoriesOptionsPanel.importSetButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
@ -149,6 +161,9 @@
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="exportSetButton">
|
||||
<Properties>
|
||||
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
|
||||
<Image iconType="3" name="/org/sleuthkit/autopsy/images/export16.png"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/url/analytics/domaincategorization/Bundle.properties" key="WebCategoriesOptionsPanel.exportSetButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
|
@ -35,6 +35,7 @@ import javax.swing.JFrame;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.filechooser.FileNameExtensionFilter;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.openide.util.WeakListeners;
|
||||
import org.sleuthkit.autopsy.corecomponents.OptionsPanel;
|
||||
@ -101,12 +102,12 @@ public class WebCategoriesOptionsPanel extends IngestModuleGlobalSettingsPanel i
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the item selected in the table or null if no selection.
|
||||
* Returns the items selected in the table or null if no selection.
|
||||
*
|
||||
* @return The item selected in the table or null if no selection.
|
||||
* @return The items selected in the table or null if no selection.
|
||||
*/
|
||||
private DomainCategory getSelected() {
|
||||
return categoryTable.getSelectedItem();
|
||||
private List<DomainCategory> getSelected() {
|
||||
return categoryTable.getSelectedItems();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -147,12 +148,13 @@ public class WebCategoriesOptionsPanel extends IngestModuleGlobalSettingsPanel i
|
||||
* happening.
|
||||
*/
|
||||
private void refreshComponentStates() {
|
||||
boolean selectedItem = getSelected() != null;
|
||||
List<DomainCategory> selectedItems = getSelected();
|
||||
int selectedCount = CollectionUtils.isEmpty(selectedItems) ? 0 : selectedItems.size();
|
||||
boolean isIngestRunning = IngestManager.getInstance().isIngestRunning();
|
||||
boolean operationsPermitted = !isIngestRunning && !isRefreshing;
|
||||
|
||||
deleteEntryButton.setEnabled(selectedItem && operationsPermitted);
|
||||
editEntryButton.setEnabled(selectedItem && operationsPermitted);
|
||||
deleteEntryButton.setEnabled(selectedCount > 0 && operationsPermitted);
|
||||
editEntryButton.setEnabled(selectedCount == 1 && operationsPermitted);
|
||||
|
||||
newEntryButton.setEnabled(operationsPermitted);
|
||||
exportSetButton.setEnabled(operationsPermitted);
|
||||
@ -287,6 +289,7 @@ public class WebCategoriesOptionsPanel extends IngestModuleGlobalSettingsPanel i
|
||||
gridBagConstraints.insets = new java.awt.Insets(2, 10, 10, 0);
|
||||
add(categoryTablePanel, gridBagConstraints);
|
||||
|
||||
newEntryButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/add16.png"))); // NOI18N
|
||||
newEntryButton.setText(org.openide.util.NbBundle.getMessage(WebCategoriesOptionsPanel.class, "WebCategoriesOptionsPanel.newEntryButton.text")); // NOI18N
|
||||
newEntryButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
@ -301,6 +304,7 @@ public class WebCategoriesOptionsPanel extends IngestModuleGlobalSettingsPanel i
|
||||
gridBagConstraints.insets = new java.awt.Insets(0, 10, 5, 5);
|
||||
add(newEntryButton, gridBagConstraints);
|
||||
|
||||
editEntryButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/edit16.png"))); // NOI18N
|
||||
editEntryButton.setText(org.openide.util.NbBundle.getMessage(WebCategoriesOptionsPanel.class, "WebCategoriesOptionsPanel.editEntryButton.text")); // NOI18N
|
||||
editEntryButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
@ -315,6 +319,7 @@ public class WebCategoriesOptionsPanel extends IngestModuleGlobalSettingsPanel i
|
||||
gridBagConstraints.insets = new java.awt.Insets(0, 0, 5, 5);
|
||||
add(editEntryButton, gridBagConstraints);
|
||||
|
||||
deleteEntryButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/delete16.png"))); // NOI18N
|
||||
deleteEntryButton.setText(org.openide.util.NbBundle.getMessage(WebCategoriesOptionsPanel.class, "WebCategoriesOptionsPanel.deleteEntryButton.text")); // NOI18N
|
||||
deleteEntryButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
@ -328,6 +333,7 @@ public class WebCategoriesOptionsPanel extends IngestModuleGlobalSettingsPanel i
|
||||
gridBagConstraints.insets = new java.awt.Insets(0, 0, 5, 5);
|
||||
add(deleteEntryButton, gridBagConstraints);
|
||||
|
||||
importSetButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/import16.png"))); // NOI18N
|
||||
importSetButton.setText(org.openide.util.NbBundle.getMessage(WebCategoriesOptionsPanel.class, "WebCategoriesOptionsPanel.importSetButton.text")); // NOI18N
|
||||
importSetButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
@ -342,6 +348,7 @@ public class WebCategoriesOptionsPanel extends IngestModuleGlobalSettingsPanel i
|
||||
gridBagConstraints.insets = new java.awt.Insets(0, 10, 5, 5);
|
||||
add(importSetButton, gridBagConstraints);
|
||||
|
||||
exportSetButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/export16.png"))); // NOI18N
|
||||
exportSetButton.setText(org.openide.util.NbBundle.getMessage(WebCategoriesOptionsPanel.class, "WebCategoriesOptionsPanel.exportSetButton.text")); // NOI18N
|
||||
exportSetButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
@ -375,14 +382,20 @@ public class WebCategoriesOptionsPanel extends IngestModuleGlobalSettingsPanel i
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
private void deleteEntryButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteEntryButtonActionPerformed
|
||||
DomainCategory selected = getSelected();
|
||||
if (selected != null && selected.getHostSuffix() != null) {
|
||||
try {
|
||||
runUpdateAction(() -> dataModel.deleteRecord(selected.getHostSuffix()));
|
||||
} catch (IllegalArgumentException | SQLException | IOException ex) {
|
||||
setDefaultCursor();
|
||||
logger.log(Level.WARNING, "There was an error while deleting: " + selected.getHostSuffix(), ex);
|
||||
List<DomainCategory> selectedItems = getSelected();
|
||||
if (!CollectionUtils.isEmpty(selectedItems)) {
|
||||
setWaitingCursor();
|
||||
for (DomainCategory selected : selectedItems) {
|
||||
if (selected != null && selected.getHostSuffix() != null) {
|
||||
try {
|
||||
dataModel.deleteRecord(selected.getHostSuffix());
|
||||
} catch (IllegalArgumentException | SQLException ex) {
|
||||
logger.log(Level.WARNING, "There was an error while deleting: " + selected.getHostSuffix(), ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
setDefaultCursor();
|
||||
refresh();
|
||||
}
|
||||
}//GEN-LAST:event_deleteEntryButtonActionPerformed
|
||||
|
||||
@ -399,16 +412,19 @@ public class WebCategoriesOptionsPanel extends IngestModuleGlobalSettingsPanel i
|
||||
}//GEN-LAST:event_newEntryButtonActionPerformed
|
||||
|
||||
private void editEntryButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_editEntryButtonActionPerformed
|
||||
DomainCategory selected = getSelected();
|
||||
if (selected != null && selected.getHostSuffix() != null) {
|
||||
try {
|
||||
DomainCategory newCategory = getAddEditValue(selected);
|
||||
if (newCategory != null) {
|
||||
runUpdateAction(() -> dataModel.insertUpdateSuffix(newCategory));
|
||||
List<DomainCategory> selectedItems = getSelected();
|
||||
if (CollectionUtils.isNotEmpty(selectedItems)) {
|
||||
DomainCategory selected = selectedItems.get(0);
|
||||
if (selected != null && selected.getHostSuffix() != null) {
|
||||
try {
|
||||
DomainCategory newCategory = getAddEditValue(selected);
|
||||
if (newCategory != null) {
|
||||
runUpdateAction(() -> dataModel.insertUpdateSuffix(newCategory));
|
||||
}
|
||||
} catch (IllegalArgumentException | SQLException | IOException ex) {
|
||||
setDefaultCursor();
|
||||
logger.log(Level.WARNING, "There was an error while editing: " + selected.getHostSuffix(), ex);
|
||||
}
|
||||
} catch (IllegalArgumentException | SQLException | IOException ex) {
|
||||
setDefaultCursor();
|
||||
logger.log(Level.WARNING, "There was an error while editing: " + selected.getHostSuffix(), ex);
|
||||
}
|
||||
}
|
||||
}//GEN-LAST:event_editEntryButtonActionPerformed
|
||||
@ -417,7 +433,7 @@ public class WebCategoriesOptionsPanel extends IngestModuleGlobalSettingsPanel i
|
||||
"WebCategoriesOptionsPanel_importSetButtonActionPerformed_errorMessage=There was an error importing this json file.",
|
||||
"WebCategoriesOptionsPanel_importSetButtonActionPerformed_errorTitle=Import Error",})
|
||||
private void importSetButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_importSetButtonActionPerformed
|
||||
fileChooser.setSelectedFile(null);
|
||||
fileChooser.setSelectedFile(new File(""));
|
||||
int result = fileChooser.showOpenDialog(this);
|
||||
if (result == JFileChooser.APPROVE_OPTION) {
|
||||
File selectedFile = fileChooser.getSelectedFile();
|
||||
|
@ -1,188 +0,0 @@
|
||||
/* UNCLASSIFIED
|
||||
*
|
||||
* Viking
|
||||
*
|
||||
* Copyright (c) 2021 Basis Technology Corporation.
|
||||
* Contact: brianc@basistech.com
|
||||
*/
|
||||
package org.sleuthkit.autopsy.recentactivity;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Paths;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.openide.modules.InstalledFileLocator;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.url.analytics.DomainCategorizer;
|
||||
import org.sleuthkit.autopsy.url.analytics.DomainCategorizerException;
|
||||
import org.sleuthkit.autopsy.url.analytics.DomainCategory;
|
||||
|
||||
/**
|
||||
* A DomainCategoryProvider that utilizes a sqlite db for data.
|
||||
*/
|
||||
public class CustomDomainCategorizer implements DomainCategorizer {
|
||||
|
||||
private static final String ROOT_FOLDER = "DomainCategorization";
|
||||
private static final String FILE_REL_PATH = "custom_categorization.db";
|
||||
|
||||
private static final String JDBC_SQLITE_PREFIX = "jdbc:sqlite:";
|
||||
private static final String SUFFIX_COLUMN = "suffix";
|
||||
private static final String CATEGORY_COLUMN = "category_id";
|
||||
|
||||
// get the suffix and category from the main table and gets the longest matching suffix.
|
||||
private static final String BASE_QUERY_FMT_STR = String.format(
|
||||
"SELECT %s, %s FROM domain_suffix WHERE suffix IN (%%s) ORDER BY LENGTH(%s) DESC LIMIT 1",
|
||||
SUFFIX_COLUMN, CATEGORY_COLUMN, SUFFIX_COLUMN);
|
||||
|
||||
private static final String CATEGORY_ID_COLUMN = "id";
|
||||
private static final String CATEGORY_NAME_COLUMN = "name";
|
||||
private static final String CATEGORY_IDS_QUERY = String.format("SELECT %s,%s FROM category", CATEGORY_ID_COLUMN, CATEGORY_NAME_COLUMN);
|
||||
|
||||
private static final Logger logger = Logger.getLogger(CustomDomainCategorizer.class.getName());
|
||||
|
||||
private Connection dbConn = null;
|
||||
private Map<Integer, String> categoryIds = null;
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves all the possible suffixes that could be tracked. For instance,
|
||||
* if the host was "chatenabled.mail.google.com", the list should be
|
||||
* ["chatenabled.mail.google.com", "mail.google.com", "google.com", "com"].
|
||||
*
|
||||
* @param host The host.
|
||||
* @return The possible suffixes.
|
||||
*/
|
||||
private List<String> getSuffixes(String host) {
|
||||
if (host == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<String> hostTokens = Arrays.asList(host.split("\\."));
|
||||
List<String> hostSegmentations = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < hostTokens.size(); i++) {
|
||||
String searchString = String.join(".", hostTokens.subList(i, hostTokens.size()));
|
||||
hostSegmentations.add(searchString);
|
||||
}
|
||||
|
||||
return hostSegmentations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DomainCategory getCategory(String domain, String host) throws DomainCategorizerException {
|
||||
String hostToUse = (StringUtils.isBlank(host)) ? domain : host;
|
||||
if (StringUtils.isBlank(hostToUse)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
hostToUse = hostToUse.toLowerCase();
|
||||
|
||||
List<String> segmentations = getSuffixes(host);
|
||||
String questionMarks = IntStream.range(0, segmentations.size())
|
||||
.mapToObj((num) -> "?")
|
||||
.collect(Collectors.joining(","));
|
||||
|
||||
String sql = String.format(BASE_QUERY_FMT_STR, questionMarks);
|
||||
|
||||
try (PreparedStatement stmt = dbConn.prepareStatement(sql)) {
|
||||
for (int i = 0; i < segmentations.size(); i++) {
|
||||
stmt.setString(i + 1, segmentations.get(i));
|
||||
}
|
||||
|
||||
try (ResultSet resultSet = stmt.executeQuery()) {
|
||||
if (resultSet.next()) {
|
||||
String suffix = resultSet.getString(SUFFIX_COLUMN);
|
||||
int categoryId = resultSet.getInt(CATEGORY_COLUMN);
|
||||
String category = (resultSet.wasNull()) ? null : categoryIds.get(categoryId);
|
||||
if (StringUtils.isNotBlank(suffix) && StringUtils.isNotBlank(category)) {
|
||||
return new DomainCategory(suffix, category);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
logger.log(Level.WARNING, "There was an error retrieving results for " + hostToUse, ex);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a mapping of category ids to the name of the category.
|
||||
*
|
||||
* @param dbConn The database connection to the sqlite database with the
|
||||
* category table.
|
||||
* @return The mapping of category id to category name.
|
||||
* @throws SQLException
|
||||
*/
|
||||
private Map<Integer, String> getCategoryIds(Connection dbConn) throws SQLException {
|
||||
if (dbConn == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Map<Integer, String> toRet = new HashMap<>();
|
||||
try (PreparedStatement stmt = dbConn.prepareStatement(CATEGORY_IDS_QUERY)) {
|
||||
try (ResultSet resultSet = stmt.executeQuery()) {
|
||||
while (resultSet.next()) {
|
||||
toRet.put(resultSet.getInt(CATEGORY_ID_COLUMN), resultSet.getString(CATEGORY_NAME_COLUMN));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return toRet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() throws DomainCategorizerException {
|
||||
File dir = InstalledFileLocator.getDefault().locate(ROOT_FOLDER, CustomDomainCategorizer.class.getPackage().getName(), false);
|
||||
|
||||
boolean needNew = true;
|
||||
try {
|
||||
if (dbConn != null && !dbConn.isClosed()) {
|
||||
needNew = false;
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
logger.log(Level.WARNING, "There was an error while checking to see if previously existing connection.", ex);
|
||||
}
|
||||
|
||||
if (needNew) {
|
||||
try {
|
||||
if (dir == null || !dir.exists()) {
|
||||
throw new DomainCategorizerException("Could not find parent directory of database");
|
||||
}
|
||||
|
||||
File dbFile = Paths.get(dir.toString(), FILE_REL_PATH).toFile();
|
||||
if (dbFile == null || !dbFile.exists()) {
|
||||
throw new DomainCategorizerException("Could not find database file in directory: " + dir.toString());
|
||||
}
|
||||
|
||||
Class.forName("org.sqlite.JDBC");
|
||||
dbConn = DriverManager.getConnection(JDBC_SQLITE_PREFIX + dbFile.toString());
|
||||
categoryIds = getCategoryIds(dbConn);
|
||||
} catch (ClassNotFoundException | SQLException ex) {
|
||||
throw new DomainCategorizerException("Unable to connect to class resource db.", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
if (dbConn != null && !dbConn.isClosed()) {
|
||||
dbConn.close();
|
||||
}
|
||||
dbConn = null;
|
||||
|
||||
categoryIds = null;
|
||||
}
|
||||
}
|
@ -83,6 +83,9 @@ class DomainCategoryRunner extends Extract {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(DomainCategoryRunner.class.getName());
|
||||
|
||||
// NOTE: if CustomWebCategorizer ever changes name, this will need to be changed as well.
|
||||
private static final String CUSTOM_CATEGORIZER_PATH = "org.sleuthkit.autopsy.url.analytics.domaincategorization.CustomWebCategorizer";
|
||||
|
||||
/**
|
||||
* Get seconds from epoch from the mapping for the attribute type id.
|
||||
*
|
||||
@ -444,7 +447,16 @@ class DomainCategoryRunner extends Extract {
|
||||
|
||||
List<DomainCategorizer> foundProviders = lookupList.stream()
|
||||
.filter(provider -> provider != null)
|
||||
.sorted((a, b) -> a.getClass().getName().compareToIgnoreCase(b.getClass().getName()))
|
||||
.sorted((a, b) -> {
|
||||
boolean aIsCustom = a.getClass().getName().contains(CUSTOM_CATEGORIZER_PATH);
|
||||
boolean bIsCustom = b.getClass().getName().contains(CUSTOM_CATEGORIZER_PATH);
|
||||
if (aIsCustom != bIsCustom) {
|
||||
// push custom categorizer to top
|
||||
return -Boolean.compare(aIsCustom, bIsCustom);
|
||||
}
|
||||
|
||||
return a.getClass().getName().compareToIgnoreCase(b.getClass().getName());
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// add the default categorizer last as a last resort
|
||||
|
Loading…
x
Reference in New Issue
Block a user