package change

This commit is contained in:
Greg DiCristofaro
2021-03-10 11:35:08 -05:00
parent 8389476f5f
commit 19a677100b
9 changed files with 0 additions and 1645 deletions
@@ -1,146 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.3" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JDialogFormInfo">
<Properties>
<Property name="defaultCloseOperation" type="int" value="2"/>
</Properties>
<SyntheticProperties>
<SyntheticProperty name="formSizePolicy" type="int" value="1"/>
<SyntheticProperty name="generateCenter" type="boolean" value="false"/>
</SyntheticProperties>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
<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="false"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
<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="validationLabel" alignment="0" max="32767" attributes="0"/>
<Group type="102" alignment="1" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="domainSuffixLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="categoryLabel" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="32767" attributes="0"/>
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Component id="categoryTextField" pref="272" max="32767" attributes="0"/>
<Component id="domainSuffixTextField" max="32767" attributes="0"/>
</Group>
</Group>
<Group type="102" alignment="1" attributes="0">
<EmptySpace min="0" pref="216" max="32767" attributes="0"/>
<Component id="saveButton" 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"/>
<Group type="103" groupAlignment="1" attributes="0">
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="categoryLabel" min="-2" max="-2" attributes="0"/>
<Component id="categoryTextField" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Component id="domainSuffixTextField" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="domainSuffixLabel" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Component id="validationLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" 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>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JTextField" name="categoryTextField">
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="categoryTextFieldActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JTextField" name="domainSuffixTextField">
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="domainSuffixTextFieldActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="categoryLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/url/analytics/Bundle.properties" key="AddEditCategoryDialog.categoryLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<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.JLabel" name="domainSuffixLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/url/analytics/Bundle.properties" key="AddEditCategoryDialog.domainSuffixLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<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.JLabel" name="validationLabel">
<Properties>
<Property name="foreground" type="java.awt.Color" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="java.awt.Color.RED" type="code"/>
</Property>
<Property name="text" type="java.lang.String" value=" "/>
<Property name="toolTipText" type="java.lang.String" value=""/>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="cancelButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/url/analytics/Bundle.properties" key="AddEditCategoryDialog.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="saveButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/url/analytics/Bundle.properties" key="AddEditCategoryDialog.saveButton.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="saveButtonActionPerformed"/>
</Events>
</Component>
</SubComponents>
</Form>
@@ -1,267 +0,0 @@
/*
* 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.url.analytics;
import java.util.Set;
import org.openide.util.NbBundle.Messages;
/**
* Dialog for adding or editing a custom domain suffix category.
*/
@Messages({
"AddEditCategoryDialog_Edit=Edit Entry",
"AddEditCategoryDialog_Add=Add Entry"
})
class AddEditCategoryDialog extends javax.swing.JDialog {
private boolean changed = false;
private final Set<String> currentSuffixesToUpper;
private final DomainCategory currentDomainCategory;
/**
* Main constructor if adding a new domain suffix.
*
* @param parent The parent frame for this dialog.
* @param currentSuffixesToUpper The current domain suffixes to upper case
* and trimmed. Used for determining repeats.
*/
AddEditCategoryDialog(java.awt.Frame parent, Set<String> currentSuffixesToUpper) {
this(parent, currentSuffixesToUpper, null);
}
/**
* Main constructor if editing a domain suffix.
*
* @param parentThe parent frame for this dialog.
* @param currentSuffixesToUpper The current domain suffixes to upper case
* and trimmed. Used for determining repeats.
* @param currentDomainCategory The domain category being edited. If null,
* it will be assumed that a new domain suffix is being added.
*/
AddEditCategoryDialog(java.awt.Frame parent, Set<String> currentSuffixesToUpper, DomainCategory currentDomainCategory) {
super(parent, true);
initComponents();
this.currentSuffixesToUpper = currentSuffixesToUpper;
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
if (currentDomainCategory == null) {
setTitle(Bundle.AddEditCategoryDialog_Add());
domainSuffixTextField.setEditable(true);
domainSuffixTextField.setEnabled(true);
} else {
setTitle(Bundle.AddEditCategoryDialog_Edit());
domainSuffixTextField.setEditable(false);
domainSuffixTextField.setEnabled(false);
}
}
/**
* 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.
*/
DomainCategory getValue() {
return new DomainCategory(domainSuffixTextField.getText().trim(), categoryTextField.getText().trim());
}
/**
* 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() {
return changed;
}
/**
* When the text field is updated, this method is called.
*
* @param suffixStr The current domain suffix string in the input.
* @param categoryStr The current category string in the input.
*/
@Messages({
"# {0} - maxSuffixLen",
"AddEditCategoryDialog_onValueUpdate_badSuffix=Please provide a domain suffix that is no more than {0} characters.",
"# {0} - maxCategoryLen",
"AddEditCategoryDialog_onValueUpdate_badCategory=Please provide a domain suffix that is no more than {0} characters.",
"AddEditCategoryDialog_onValueUpdate_suffixRepeat=Please provide a unique domain suffix.",
"AddEditCategoryDialog_onValueUpdate_sameCategory=Please provide a new category for this domain suffix.",})
void onValueUpdate(String suffixStr, String categoryStr) {
String safeSuffixStr = suffixStr == null ? "" : suffixStr;
String safeCategoryStr = categoryStr == null ? "" : categoryStr;
// update input text field if it is not the same.
if (!safeCategoryStr.equals(categoryTextField.getText())) {
categoryTextField.setText(safeCategoryStr);
}
if (!safeSuffixStr.equals(domainSuffixTextField.getText())) {
domainSuffixTextField.setText(safeSuffixStr);
}
String validationMessage = null;
if (safeSuffixStr.trim().length() == 0 || safeSuffixStr.trim().length() > WebCategoriesDataModel.getMaxDomainSuffixLength()) {
validationMessage = Bundle.AddEditCategoryDialog_onValueUpdate_badSuffix(WebCategoriesDataModel.getMaxCategoryLength());
} else if (safeCategoryStr.trim().length() == 0 || safeCategoryStr.trim().length() > WebCategoriesDataModel.getMaxCategoryLength()) {
validationMessage = Bundle.AddEditCategoryDialog_onValueUpdate_badCategory(WebCategoriesDataModel.getMaxDomainSuffixLength());
} else if (currentSuffixesToUpper.contains(safeSuffixStr.trim().toUpperCase())) {
validationMessage = Bundle.AddEditCategoryDialog_onValueUpdate_suffixRepeat();
} else if (currentDomainCategory != null
&& currentDomainCategory.getCategory() != null
&& safeCategoryStr.trim().equals(currentDomainCategory.getCategory().trim())) {
validationMessage = Bundle.AddEditCategoryDialog_onValueUpdate_sameCategory();
}
saveButton.setEnabled(validationMessage == null);
validationLabel.setText(validationMessage == null ? "" : validationMessage);
}
/**
* 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() {
categoryTextField = new javax.swing.JTextField();
domainSuffixTextField = new javax.swing.JTextField();
javax.swing.JLabel categoryLabel = new javax.swing.JLabel();
javax.swing.JLabel domainSuffixLabel = new javax.swing.JLabel();
validationLabel = new javax.swing.JLabel();
javax.swing.JButton cancelButton = new javax.swing.JButton();
saveButton = new javax.swing.JButton();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
categoryTextField.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
categoryTextFieldActionPerformed(evt);
}
});
domainSuffixTextField.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
domainSuffixTextFieldActionPerformed(evt);
}
});
categoryLabel.setText(org.openide.util.NbBundle.getMessage(AddEditCategoryDialog.class, "AddEditCategoryDialog.categoryLabel.text")); // NOI18N
domainSuffixLabel.setText(org.openide.util.NbBundle.getMessage(AddEditCategoryDialog.class, "AddEditCategoryDialog.domainSuffixLabel.text")); // NOI18N
validationLabel.setForeground(java.awt.Color.RED);
validationLabel.setText(" ");
validationLabel.setToolTipText("");
cancelButton.setText(org.openide.util.NbBundle.getMessage(AddEditCategoryDialog.class, "AddEditCategoryDialog.cancelButton.text")); // NOI18N
cancelButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
cancelButtonActionPerformed(evt);
}
});
saveButton.setText(org.openide.util.NbBundle.getMessage(AddEditCategoryDialog.class, "AddEditCategoryDialog.saveButton.text")); // NOI18N
saveButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
saveButtonActionPerformed(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(validationLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(domainSuffixLabel)
.addComponent(categoryLabel))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addComponent(categoryTextField, javax.swing.GroupLayout.DEFAULT_SIZE, 272, Short.MAX_VALUE)
.addComponent(domainSuffixTextField)))
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addGap(0, 216, Short.MAX_VALUE)
.addComponent(saveButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(cancelButton)))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(categoryLabel)
.addComponent(categoryTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGap(18, 18, 18)
.addComponent(domainSuffixTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(domainSuffixLabel))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(validationLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(saveButton)
.addComponent(cancelButton))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
pack();
}// </editor-fold>//GEN-END:initComponents
private void saveButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveButtonActionPerformed
this.changed = true;
dispose();
}//GEN-LAST:event_saveButtonActionPerformed
private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed
this.changed = false;
dispose();
}//GEN-LAST:event_cancelButtonActionPerformed
private void domainSuffixTextFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_domainSuffixTextFieldActionPerformed
onValueUpdate(domainSuffixTextField.getText(), categoryTextField.getText());
}//GEN-LAST:event_domainSuffixTextFieldActionPerformed
private void categoryTextFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_categoryTextFieldActionPerformed
onValueUpdate(domainSuffixTextField.getText(), categoryTextField.getText());
}//GEN-LAST:event_categoryTextFieldActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JTextField categoryTextField;
private javax.swing.JTextField domainSuffixTextField;
private javax.swing.JButton saveButton;
private javax.swing.JLabel validationLabel;
// End of variables declaration//GEN-END:variables
}
@@ -1,13 +0,0 @@
WebCategoryOptionsController_title=Custom Web Categories
WebCategoryOptionsController_keywords=Custom Web Categories
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.categoriesTitle.text=Categories:
WebCategoriesOptionsPanel.newEntryButton.text=New Entry
WebCategoriesOptionsPanel.editEntryButton.text=Edit Entry
WebCategoriesOptionsPanel.deleteEntryButton.text=Delete Entry
WebCategoriesOptionsPanel.importSetButton.text=Import Set
WebCategoriesOptionsPanel.exportSetButton.text=Export Set
@@ -1,19 +0,0 @@
# {0} - maxCategoryLen
AddEditCategoryDialog_onValueUpdate_badCategory=Please provide a domain suffix 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_sameCategory=Please provide a new category for this domain suffix.
AddEditCategoryDialog_onValueUpdate_suffixRepeat=Please provide a unique domain suffix.
WebCategoryOptionsController_title=Custom Web Categories
WebCategoryOptionsController_keywords=Custom Web Categories
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.categoriesTitle.text=Categories:
WebCategoriesOptionsPanel.newEntryButton.text=New Entry
WebCategoriesOptionsPanel.editEntryButton.text=Edit Entry
WebCategoriesOptionsPanel.deleteEntryButton.text=Delete Entry
WebCategoriesOptionsPanel.importSetButton.text=Import Set
WebCategoriesOptionsPanel.exportSetButton.text=Export Set
@@ -1,88 +0,0 @@
/*
* 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.url.analytics;
import java.sql.SQLException;
import java.util.logging.Level;
import org.apache.commons.lang3.StringUtils;
import org.openide.util.lookup.ServiceProvider;
import org.sleuthkit.autopsy.coreutils.Logger;
/**
* A DomainCategoryProvider for custom web categories.
*/
@ServiceProvider(service = DomainCategorizer.class)
public class CustomWebCategorizer implements DomainCategorizer {
private static final Logger logger = Logger.getLogger(CustomWebCategorizer.class.getName());
private final WebCategoriesDataModel dataModel;
/**
* Constructor accepting a custom WebCategoriesDataModel.
*
* @param dataModel The WebCategoriesDataModel to use as a data model.
*/
CustomWebCategorizer(WebCategoriesDataModel dataModel) {
this.dataModel = dataModel;
}
/**
* No parameter constructor that uses the singleton instance of the
* WebCategoriesDataModel.
*
*/
public CustomWebCategorizer() {
this(WebCategoriesDataModel.getInstance());
}
@Override
public DomainCategory getCategory(String domain, String host) throws DomainCategorizerException {
if (!dataModel.isInitialized()) {
return null;
}
String hostToUse = (StringUtils.isBlank(host)) ? domain : host;
if (StringUtils.isBlank(hostToUse)) {
return null;
}
hostToUse = hostToUse.toLowerCase();
try {
return dataModel.getMatchingRecord(hostToUse);
} catch (SQLException ex) {
logger.log(Level.WARNING, "There was an error while retrieving data for: " + hostToUse, ex);
return null;
}
}
@Override
public void initialize() throws DomainCategorizerException {
try {
dataModel.initialize();
} catch (SQLException ex) {
throw new DomainCategorizerException("Unable to initialize.", ex);
}
}
@Override
public void close() throws Exception {
dataModel.close();
}
}
@@ -1,509 +0,0 @@
/*
* 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.url.analytics;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.File;
import java.io.IOException;
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.sql.Statement;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.openide.modules.InstalledFileLocator;
/**
* Provides the data model for exporting, importing and CRUD operations on
* custom web categories.
*/
class WebCategoriesDataModel implements AutoCloseable {
/**
* DTO to be used with jackson when converting to and from exported content.
*/
@JsonIgnoreProperties(ignoreUnknown = true)
static class CustomCategorizationJsonDto {
private final String category;
private final List<String> domains;
/**
* Main constructor.
*
* @param category The category.
* @param domains The list of host suffixes in this category.
*/
@JsonCreator
CustomCategorizationJsonDto(
@JsonProperty("category") String category,
@JsonProperty("domains") List<String> domains) {
this.category = category;
this.domains = domains == null
? Collections.emptyList()
: new ArrayList<>(domains);
}
/**
* Returns the category.
*
* @return The category.
*/
String getCategory() {
return category;
}
/**
* Returns the list of domain suffixes in this category.
*
* @return The list of domain suffixes in this category.
*/
List<String> getDomains() {
return domains;
}
}
private static final int MAX_CAT_SIZE = 300;
private static final int MAX_DOMAIN_SIZE = 255;
private static final String ROOT_FOLDER = "DomainCategorization";
private static final String FILE_REL_PATH = "custom_list.db";
private static final String JDBC_SQLITE_PREFIX = "jdbc:sqlite:";
private static final String TABLE_NAME = "domain_suffix";
private static final String SUFFIX_COLUMN = "suffix";
private static final String CATEGORY_COLUMN = "category";
private static final Logger logger = Logger.getLogger(WebCategoriesDataModel.class.getName());
private static WebCategoriesDataModel instance;
/**
* Returns the maximum string length of a domain suffix.
*
* @return The maximum string length of a domain suffix.
*/
static int getMaxDomainSuffixLength() {
return MAX_DOMAIN_SIZE;
}
/**
* Returns the maximum string length of a category.
*
* @return The maximum string length of a category.
*/
static int getMaxCategoryLength() {
return MAX_DOMAIN_SIZE;
}
/**
* Retrieves the default path for where custom domain categorization exists.
*
* @return The path or null if the path cannot be reconciled.
*/
private static File getDefaultPath() {
File dir = InstalledFileLocator.getDefault().locate(ROOT_FOLDER, WebCategoriesDataModel.class.getPackage().getName(), false);
if (dir == null || !dir.exists()) {
logger.log(Level.WARNING, String.format("Unable to find file %s with InstalledFileLocator", ROOT_FOLDER));
return null;
}
return Paths.get(dir.getAbsolutePath(), FILE_REL_PATH).toFile();
}
/**
* Generates the normalized category string to be inserted into the
* database.
*
* @param category The category.
* @return The normalized string.
*/
private static String getNormalizedCategory(String category) {
if (category == null) {
return "";
}
return category.trim().substring(0, Math.min(category.length(), MAX_CAT_SIZE));
}
/**
* Generates the normalized domain suffix string to be inserted into the
* database.
*
* @param domainSuffix The domain suffix.
* @return The normalized string.
*/
private static String getNormalizedSuffix(String domainSuffix) {
if (domainSuffix == null) {
return "";
}
return domainSuffix.trim().substring(0, Math.min(domainSuffix.length(), MAX_DOMAIN_SIZE)).toLowerCase();
}
/**
* Retrieves a singleton instance of this class.
*
* @return The singleton instance of this class.
*/
static WebCategoriesDataModel getInstance() {
if (instance == null) {
instance = new WebCategoriesDataModel();
}
return instance;
}
private final File sqlitePath;
private Connection dbConn = null;
/**
* Constructor used to create singleton instance.
*/
private WebCategoriesDataModel() {
this(getDefaultPath());
}
/**
* Constructor that accepts a variable path for the custom sqlite database
* for custom domain categories.
*
* @param sqlitePath The path.
*/
WebCategoriesDataModel(File sqlitePath) {
this.sqlitePath = sqlitePath;
}
/**
* Creates a sqlite jdbc connection.
*
* @throws SQLException
*/
synchronized void initialize() throws SQLException {
String url = JDBC_SQLITE_PREFIX + sqlitePath.getAbsolutePath();
if (this.dbConn != null) {
this.dbConn.close();
this.dbConn = null;
}
this.dbConn = DriverManager.getConnection(url);
// speed up operations by turning off WAL
try (Statement turnOffWal = dbConn.createStatement()) {
turnOffWal.execute("PRAGMA journal_mode=OFF");
}
// create table if it doesn't exist
try (Statement createDomainsTable = dbConn.createStatement()) {
createDomainsTable.execute(
" CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " (\n"
+ " " + SUFFIX_COLUMN + " VARCHAR(" + MAX_DOMAIN_SIZE + ") PRIMARY KEY,\n"
+ " " + CATEGORY_COLUMN + " VARCHAR(" + MAX_CAT_SIZE + ")\n"
+ " ) WITHOUT ROWID");
}
}
/**
* Returns true if initialized.
*
* @return True if initialized.
*/
synchronized boolean isInitialized() {
return this.dbConn != null;
}
/**
* Imports json file replacing any data in this database.
*
* @param jsonInput The json file to import.
* @throws IOException
* @throws SQLException
*/
synchronized void importJson(File jsonInput) throws IOException, SQLException {
if (jsonInput == null) {
logger.log(Level.WARNING, "No valid file provided.");
return;
}
if (!isInitialized()) {
initialize();
}
ObjectMapper mapper = new ObjectMapper();
List<CustomCategorizationJsonDto> customCategorizations = mapper.readValue(jsonInput, new TypeReference<List<CustomCategorizationJsonDto>>() {
});
customCategorizations = customCategorizations == null ? Collections.emptyList() : customCategorizations;
// insert all records as a batch for speed purposes
try (PreparedStatement domainInsert = dbConn.prepareStatement(
"INSERT OR REPLACE INTO " + TABLE_NAME + "(" + SUFFIX_COLUMN + ", " + CATEGORY_COLUMN + ") VALUES (?, ?)", Statement.NO_GENERATED_KEYS)) {
for (int i = 0; i < customCategorizations.size(); i++) {
CustomCategorizationJsonDto category = customCategorizations.get(i);
if (category == null || category.getDomains() == null || category.getCategory() == null) {
logger.log(Level.WARNING, String.format("Could not process item in file: %s at index: %d", jsonInput.getAbsolutePath(), i));
continue;
}
String categoryStr = getNormalizedCategory(category.getCategory());
for (int listIdx = 0; listIdx < category.getDomains().size(); i++) {
String domain = category.getDomains().get(listIdx);
if (domain == null) {
logger.log(Level.WARNING, String.format("Could not process domain at idx: %d in category %s for file %s",
listIdx, categoryStr, jsonInput.getAbsolutePath()));
}
domainInsert.setString(1, getNormalizedSuffix(domain));
domainInsert.setString(2, categoryStr);
domainInsert.addBatch();
}
}
domainInsert.executeBatch();
}
}
/**
* Exports current database to a json file.
*
* @param jsonOutput The output file.
* @throws SQLException
* @throws IOException
*/
synchronized void exportToJson(File jsonOutput) throws SQLException, IOException {
if (jsonOutput == null) {
logger.log(Level.WARNING, "Null file provided.");
return;
}
if (!isInitialized()) {
initialize();
}
// retrieve items from the database
List<Pair<String, String>> categoryDomains = new ArrayList<>();
try (Statement domainSelect = dbConn.createStatement();
ResultSet resultSet = domainSelect.executeQuery(
"SELECT " + SUFFIX_COLUMN + ", " + CATEGORY_COLUMN + " FROM " + TABLE_NAME)) {
while (resultSet.next()) {
categoryDomains.add(Pair.of(resultSet.getString(CATEGORY_COLUMN), resultSet.getString(SUFFIX_COLUMN)));
}
}
// aggregate data appropriately into CustomCategorizationJsonDto
List<CustomCategorizationJsonDto> categories
= categoryDomains.stream()
.collect(Collectors.toMap(
p -> p.getKey(),
p -> new ArrayList<>(Arrays.asList(p.getValue())),
(p1, p2) -> {
p1.addAll(p2);
return p1;
}
))
.entrySet().stream()
.map(entry -> new CustomCategorizationJsonDto(entry.getKey(), entry.getValue()))
.collect(Collectors.toList());
// write to disk
ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(jsonOutput, categories);
}
/**
* Delete a record from the database.
*
* @param domainSuffix The domain suffix of the item to delete.
* @return Whether or not the operation actually deleted something.
* @throws SQLException
* @throws IllegalArgumentException
*/
synchronized boolean deleteRecord(String domainSuffix) throws SQLException, IllegalArgumentException {
if (StringUtils.isBlank(domainSuffix)) {
throw new IllegalArgumentException("Expected non-empty domain suffix");
}
if (!isInitialized()) {
initialize();
}
try (PreparedStatement suffixDelete = dbConn.prepareStatement(
"DELETE FROM " + TABLE_NAME + " WHERE LOWER(" + SUFFIX_COLUMN + ") = LOWER(?)", Statement.RETURN_GENERATED_KEYS);) {
suffixDelete.setString(1, getNormalizedSuffix(domainSuffix));
return suffixDelete.executeUpdate() > 0;
}
}
/**
* Inserts or updates the entry for the given domain suffix.
*
* @param entry The domain suffix and category.
* @return True if successfully inserted/updated.
* @throws SQLException
* @throws IllegalStateException
* @throws IllegalArgumentException
*/
synchronized boolean insertUpdateSuffix(DomainCategory entry) throws SQLException, IllegalStateException, IllegalArgumentException {
if (entry == null || StringUtils.isBlank(entry.getCategory()) || StringUtils.isBlank(entry.getHostSuffix())) {
throw new IllegalArgumentException("Expected non-empty category and domain suffix.");
}
if (!isInitialized()) {
initialize();
}
try (PreparedStatement insertUpdate = dbConn.prepareStatement(
"INSERT OR REPLACE INTO " + TABLE_NAME + "(" + SUFFIX_COLUMN + ", " + CATEGORY_COLUMN + ") VALUES (?, ?)",
Statement.RETURN_GENERATED_KEYS)) {
insertUpdate.setString(1, getNormalizedSuffix(entry.getHostSuffix()));
insertUpdate.setString(1, getNormalizedCategory(entry.getCategory()));
return insertUpdate.executeUpdate() > 0;
}
}
/**
* Return all records in the database.
*
* @return The list of domain suffixes and their categories.
* @throws SQLException
*/
List<DomainCategory> getRecords() throws SQLException {
if (!isInitialized()) {
initialize();
}
List<DomainCategory> entries = new ArrayList<>();
try (Statement domainSelect = dbConn.createStatement();
ResultSet resultSet = domainSelect.executeQuery(
"SELECT " + SUFFIX_COLUMN + ", " + CATEGORY_COLUMN + " FROM " + TABLE_NAME + "")) {
while (resultSet.next()) {
entries.add(new DomainCategory(
resultSet.getString(SUFFIX_COLUMN),
resultSet.getString(CATEGORY_COLUMN)));
}
}
return entries;
}
// get the suffix and category from the main table and gets the longest matching suffix.
private static final String BASE_QUERY_FMT_STR
= "SELECT " + SUFFIX_COLUMN + ", " + CATEGORY_COLUMN + " FROM " + TABLE_NAME
+ " WHERE suffix IN (%s) ORDER BY LENGTH(" + SUFFIX_COLUMN + ") DESC LIMIT 1";
/**
* Retrieves the longest matching domain suffix and category matching the
* list of suffixes or null if no item can be found.
*
* @param suffixes The list of suffixes.
* @return The longest matching entry or null if no entry found.
* @throws SQLException
*/
synchronized DomainCategory getLongestSuffixRecord(List<String> suffixes) throws SQLException {
if (suffixes == null) {
return null;
}
if (!isInitialized()) {
initialize();
}
String questionMarks = IntStream.range(0, suffixes.size())
.mapToObj((num) -> "?")
.collect(Collectors.joining(","));
try (PreparedStatement stmt = dbConn.prepareStatement(String.format(BASE_QUERY_FMT_STR, questionMarks))) {
for (int i = 0; i < suffixes.size(); i++) {
stmt.setString(i + 1, suffixes.get(i));
}
try (ResultSet resultSet = stmt.executeQuery()) {
if (resultSet.next()) {
String suffix = resultSet.getString(SUFFIX_COLUMN);
String category = resultSet.getString(CATEGORY_COLUMN);
return new DomainCategory(suffix, category);
}
}
}
return null;
}
/**
* Retrieves the longest matching domain suffix and category matching the
* list of suffixes or null if no item can be found.
*
* @param host The host name.
* @return The longest matching entry or null if no entry found.
* @throws SQLException
*/
DomainCategory getMatchingRecord(String host) throws SQLException {
return getLongestSuffixRecord(getSuffixes(host));
}
/**
* 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 synchronized void close() throws Exception {
dbConn.close();
dbConn = null;
}
}
@@ -1,86 +0,0 @@
/*
* 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.url.analytics;
import java.beans.PropertyChangeListener;
import javax.swing.JComponent;
import org.netbeans.spi.options.OptionsPanelController;
import org.openide.util.HelpCtx;
import org.openide.util.Lookup;
/**
* The options panel controller that registers and displays the option panel for
* custom web categories.
*/
@OptionsPanelController.TopLevelRegistration(categoryName = "#WebCategoryOptionsController_title",
iconBase = "org/sleuthkit/autopsy/corecomponents/checkbox32.png",
position = 21,
keywords = "#WebCategoryOptionsController_keywords",
keywordsCategory = "Custom Web Categories")
public class WebCategoriesOptionsController extends OptionsPanelController {
private final WebCategoriesDataModel dataModel = WebCategoriesDataModel.getInstance();
private final WebCategoriesOptionsPanel panel = new WebCategoriesOptionsPanel(dataModel);
@Override
public void update() {
panel.refresh();
}
@Override
public void applyChanges() {
// NO OP since saves happen whenever there is a change.
}
@Override
public void cancel() {
// NO OP since saves happen whenever there is a change.
}
@Override
public boolean isValid() {
return true;
}
@Override
public boolean isChanged() {
return false;
}
@Override
public JComponent getComponent(Lookup masterLookup) {
return panel;
}
@Override
public HelpCtx getHelpCtx() {
return null;
}
@Override
public void addPropertyChangeListener(PropertyChangeListener l) {
// NO OP since saves happen whenever there is a change.
}
@Override
public void removePropertyChangeListener(PropertyChangeListener l) {
// NO OP since saves happen whenever there is a change.
}
}
@@ -1,195 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.8" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
<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="false"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,2,106,0,0,3,37"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
<SubComponents>
<Component class="javax.swing.JLabel" name="panelDescription">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/url/analytics/Bundle.properties" key="WebCategoriesOptionsPanel.panelDescription.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="org.netbeans.modules.form.compat2.border.CompoundBorderInfo">
<CompoundBorder>
<Border PropertyName="outside" info="org.netbeans.modules.form.compat2.border.EtchedBorderInfo">
<EtchetBorder/>
</Border>
<Border PropertyName="inside" info="org.netbeans.modules.form.compat2.border.EmptyBorderInfo">
<EmptyBorder bottom="5" left="5" right="5" top="5"/>
</Border>
</CompoundBorder>
</Border>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="-1" gridY="-1" gridWidth="3" gridHeight="1" fill="3" ipadX="0" ipadY="0" insetsTop="10" insetsLeft="10" insetsBottom="10" insetsRight="0" anchor="21" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JLabel" name="categoriesTitle">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/url/analytics/Bundle.properties" key="WebCategoriesOptionsPanel.categoriesTitle.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="1" gridWidth="3" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="10" insetsBottom="0" insetsRight="0" anchor="21" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JButton" name="newEntryButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/url/analytics/Bundle.properties" key="WebCategoriesOptionsPanel.newEntryButton.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="newEntryButtonActionPerformed"/>
</Events>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="3" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="10" insetsBottom="5" insetsRight="5" anchor="21" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JButton" name="editEntryButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/url/analytics/Bundle.properties" key="WebCategoriesOptionsPanel.editEntryButton.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="editEntryButtonActionPerformed"/>
</Events>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="1" gridY="3" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="5" insetsRight="5" anchor="21" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JButton" name="deleteEntryButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/url/analytics/Bundle.properties" key="WebCategoriesOptionsPanel.deleteEntryButton.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="deleteEntryButtonActionPerformed"/>
</Events>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="2" gridY="3" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="5" insetsRight="5" anchor="21" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JButton" name="importSetButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/url/analytics/Bundle.properties" key="WebCategoriesOptionsPanel.importSetButton.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="importSetButtonActionPerformed"/>
</Events>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="4" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="10" insetsBottom="5" insetsRight="5" anchor="21" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JButton" name="exportSetButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/url/analytics/Bundle.properties" key="WebCategoriesOptionsPanel.exportSetButton.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="exportSetButtonActionPerformed"/>
</Events>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="1" gridY="4" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="5" insetsRight="5" anchor="21" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Container class="javax.swing.JPanel" name="bottomStrut">
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="3" gridY="5" gridWidth="1" gridHeight="1" fill="3" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="1.0" weightY="1.0"/>
</Constraint>
</Constraints>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignFlowLayout"/>
</Container>
<Container class="javax.swing.JScrollPane" name="tableScrollPane">
<Properties>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[325, 32767]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[325, 300]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[325, 400]"/>
</Property>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="2" gridWidth="3" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="2" insetsLeft="10" insetsBottom="5" insetsRight="0" anchor="17" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Container class="javax.swing.JPanel" name="categoryTablePanel">
<AuxValues>
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="categoryTable"/>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignFlowLayout"/>
</Container>
</SubComponents>
</Container>
</SubComponents>
</Form>
@@ -1,322 +0,0 @@
/*
* 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.url.analytics;
import java.io.File;
import java.io.IOException;
import java.sql.SQLException;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.filechooser.FileNameExtensionFilter;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.corecomponents.OptionsPanel;
import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSettingsPanel;
// TODO Turn off when ingest running
/**
* The options panel displayed for import, export, and CRUD operations on domain
* categories.
*/
public class WebCategoriesOptionsPanel extends IngestModuleGlobalSettingsPanel implements OptionsPanel {
private static final Logger logger = Logger.getLogger(WebCategoriesOptionsPanel.class.getName());
private static final String DEFAULT_EXTENSION = "json";
private static final FileNameExtensionFilter DB_FILTER = new FileNameExtensionFilter("JSON", DEFAULT_EXTENSION);
private final JFileChooser fileChooser = new JFileChooser();
private final WebCategoriesDataModel dataModel;
private Set<String> domainCategoriesToUpper = new HashSet<>();
/**
* Creates new form CustomWebCategoriesOptionsPanel
*/
public WebCategoriesOptionsPanel(WebCategoriesDataModel dataModel) {
initComponents();
this.dataModel = dataModel;
fileChooser.addChoosableFileFilter(DB_FILTER);
fileChooser.setFileFilter(DB_FILTER);
refresh();
}
private DomainCategory getSelected() {
return null;
}
void refresh() {
/
}
private DomainCategory getAddEditValue(DomainCategory original) {
JFrame parent = (this.getRootPane() != null && this.getRootPane().getParent() instanceof JFrame)
? (JFrame) this.getRootPane().getParent()
: null;
AddEditCategoryDialog addEditDialog = new AddEditCategoryDialog(parent, domainCategoriesToUpper, original);
addEditDialog.setResizable(false);
addEditDialog.setLocationRelativeTo(parent);
addEditDialog.setVisible(true);
addEditDialog.toFront();
if (addEditDialog.isChanged()) {
return addEditDialog.getValue();
} else {
return null;
}
}
/**
* 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() {
java.awt.GridBagConstraints gridBagConstraints;
javax.swing.JLabel panelDescription = new javax.swing.JLabel();
javax.swing.JLabel categoriesTitle = new javax.swing.JLabel();
javax.swing.JButton newEntryButton = new javax.swing.JButton();
editEntryButton = new javax.swing.JButton();
deleteEntryButton = new javax.swing.JButton();
javax.swing.JButton importSetButton = new javax.swing.JButton();
javax.swing.JButton exportSetButton = new javax.swing.JButton();
javax.swing.JPanel bottomStrut = new javax.swing.JPanel();
tableScrollPane = new javax.swing.JScrollPane();
javax.swing.JPanel categoryTablePanel = categoryTable;
setLayout(new java.awt.GridBagLayout());
panelDescription.setText(org.openide.util.NbBundle.getMessage(WebCategoriesOptionsPanel.class, "WebCategoriesOptionsPanel.panelDescription.text")); // NOI18N
panelDescription.setBorder(javax.swing.BorderFactory.createCompoundBorder(javax.swing.BorderFactory.createEtchedBorder(), javax.swing.BorderFactory.createEmptyBorder(5, 5, 5, 5)));
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridwidth = 3;
gridBagConstraints.fill = java.awt.GridBagConstraints.VERTICAL;
gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START;
gridBagConstraints.insets = new java.awt.Insets(10, 10, 10, 0);
add(panelDescription, gridBagConstraints);
categoriesTitle.setText(org.openide.util.NbBundle.getMessage(WebCategoriesOptionsPanel.class, "WebCategoriesOptionsPanel.categoriesTitle.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
gridBagConstraints.gridwidth = 3;
gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START;
gridBagConstraints.insets = new java.awt.Insets(0, 10, 0, 0);
add(categoriesTitle, gridBagConstraints);
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) {
newEntryButtonActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 3;
gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START;
gridBagConstraints.insets = new java.awt.Insets(0, 10, 5, 5);
add(newEntryButton, gridBagConstraints);
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) {
editEntryButtonActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 3;
gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START;
gridBagConstraints.insets = new java.awt.Insets(0, 0, 5, 5);
add(editEntryButton, gridBagConstraints);
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) {
deleteEntryButtonActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 2;
gridBagConstraints.gridy = 3;
gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START;
gridBagConstraints.insets = new java.awt.Insets(0, 0, 5, 5);
add(deleteEntryButton, gridBagConstraints);
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) {
importSetButtonActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 4;
gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START;
gridBagConstraints.insets = new java.awt.Insets(0, 10, 5, 5);
add(importSetButton, gridBagConstraints);
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) {
exportSetButtonActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 4;
gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START;
gridBagConstraints.insets = new java.awt.Insets(0, 0, 5, 5);
add(exportSetButton, gridBagConstraints);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 3;
gridBagConstraints.gridy = 5;
gridBagConstraints.fill = java.awt.GridBagConstraints.VERTICAL;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 1.0;
add(bottomStrut, gridBagConstraints);
tableScrollPane.setMaximumSize(new java.awt.Dimension(325, 32767));
tableScrollPane.setMinimumSize(new java.awt.Dimension(325, 300));
tableScrollPane.setPreferredSize(new java.awt.Dimension(325, 400));
tableScrollPane.setViewportView(categoryTablePanel);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 2;
gridBagConstraints.gridwidth = 3;
gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
gridBagConstraints.insets = new java.awt.Insets(2, 10, 5, 0);
add(tableScrollPane, gridBagConstraints);
}// </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 {
dataModel.deleteRecord(selected.getHostSuffix());
refresh();
} catch (SQLException ex) {
logger.log(Level.WARNING, "There was an error while deleting: " + selected.getHostSuffix(), ex);
}
}
}//GEN-LAST:event_deleteEntryButtonActionPerformed
private void newEntryButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newEntryButtonActionPerformed
DomainCategory newCategory = getAddEditValue(null);
if (newCategory != null) {
try {
dataModel.insertUpdateSuffix(newCategory);
refresh();
} catch (SQLException ex) {
logger.log(Level.WARNING, "There was an error while adding new record: " + newCategory.getHostSuffix(), ex);
}
}
}//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) {
dataModel.insertUpdateSuffix(newCategory);
refresh();
}
} catch (SQLException ex) {
logger.log(Level.WARNING, "There was an error while editing: " + selected.getHostSuffix(), ex);
}
}
}//GEN-LAST:event_editEntryButtonActionPerformed
@Messages({
"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
int result = fileChooser.showOpenDialog(this);
if (result == JFileChooser.APPROVE_OPTION) {
File selectedFile = fileChooser.getSelectedFile();
if (selectedFile != null && selectedFile.exists()) {
try {
dataModel.importJson(selectedFile);
refresh();
} catch (SQLException | IOException ex) {
JOptionPane.showMessageDialog(
this,
Bundle.WebCategoriesOptionsPanel_importSetButtonActionPerformed_errorMessage(),
Bundle.WebCategoriesOptionsPanel_importSetButtonActionPerformed_errorTitle(),
JOptionPane.ERROR);
logger.log(Level.WARNING, "There was an error on import.", ex);
}
}
}
}//GEN-LAST:event_importSetButtonActionPerformed
@Messages({
"WebCategoriesOptionsPanel_exportSetButtonActionPerformed_errorMessage=There was an error exporting.",
"WebCategoriesOptionsPanel_exportSetButtonActionPerformed_errorTitle=Export Error",})
private void exportSetButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_exportSetButtonActionPerformed
int result = fileChooser.showSaveDialog(this);
if (result == JFileChooser.APPROVE_OPTION) {
File selectedFile = fileChooser.getSelectedFile();
if (selectedFile != null && selectedFile.exists()) {
try {
dataModel.exportToJson(selectedFile);
} catch (SQLException | IOException ex) {
JOptionPane.showMessageDialog(
this,
Bundle.WebCategoriesOptionsPanel_importSetButtonActionPerformed_errorMessage(),
Bundle.WebCategoriesOptionsPanel_importSetButtonActionPerformed_errorTitle(),
JOptionPane.ERROR);
logger.log(Level.WARNING, "There was an error on export.", ex);
}
}
}
}//GEN-LAST:event_exportSetButtonActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton deleteEntryButton;
private javax.swing.JButton editEntryButton;
private javax.swing.JScrollPane tableScrollPane;
// End of variables declaration//GEN-END:variables
@Override
public void saveSettings() {
// NO OP since saves happen whenever there is a change.
}
@Override
public void store() {
// NO OP since saves happen whenever there is a change.
}
@Override
public void load() {
refresh();
}
}