merge from develop

This commit is contained in:
Greg DiCristofaro 2023-08-30 14:15:56 -04:00
commit 0cd50f767d
79 changed files with 3888 additions and 1291 deletions

View File

@ -134,8 +134,8 @@
<property environment="env"/>
<copy file="${env.TSK_HOME}/bindings/java/dist/sleuthkit-${TSK_VERSION}.jar"
tofile="${ext.dir}/sleuthkit-${TSK_VERSION}.jar"/>
<copy file="${env.TSK_HOME}/bindings/java/lib/sqlite-jdbc-3.42.0.0.jar"
tofile="${ext.dir}/sqlite-jdbc-3.42.0.0.jar"/>
<copy file="${env.TSK_HOME}/bindings/java/lib/sqlite-jdbc-3.42.0.1.jar"
tofile="${ext.dir}/sqlite-jdbc-3.42.0.1.jar"/>
<copy file="${env.TSK_HOME}/bindings/java/lib/postgresql-42.3.5.jar"
tofile="${ext.dir}/postgresql-42.3.5.jar"/>
<copy file="${env.TSK_HOME}/bindings/java/lib/c3p0-0.9.5.5.jar"

View File

@ -2,7 +2,7 @@ Manifest-Version: 1.0
OpenIDE-Module: org.sleuthkit.autopsy.core/10
OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/core/Bundle.properties
OpenIDE-Module-Layer: org/sleuthkit/autopsy/core/layer.xml
OpenIDE-Module-Implementation-Version: 37
OpenIDE-Module-Implementation-Version: 38
OpenIDE-Module-Requires: org.openide.windows.WindowManager
AutoUpdate-Show-In-Client: true
AutoUpdate-Essential-Module: true

View File

@ -85,13 +85,13 @@ file.reference.Rejistry-1.1-SNAPSHOT.jar=release/modules/ext/Rejistry-1.1-SNAPSH
file.reference.serializer-2.7.2.jar=release/modules/ext/serializer-2.7.2.jar
file.reference.sevenzipjbinding-AllPlatforms.jar=release/modules/ext/sevenzipjbinding-AllPlatforms.jar
file.reference.sevenzipjbinding.jar=release/modules/ext/sevenzipjbinding.jar
file.reference.sleuthkit-4.12.0.jar=release/modules/ext/sleuthkit-4.12.0.jar
file.reference.sleuthkit-caseuco-4.12.0.jar=release/modules/ext/sleuthkit-caseuco-4.12.0.jar
file.reference.sleuthkit-4.12.1.jar=release/modules/ext/sleuthkit-4.12.1.jar
file.reference.sleuthkit-caseuco-4.12.1.jar=release/modules/ext/sleuthkit-caseuco-4.12.1.jar
file.reference.slf4j-api-1.7.36.jar=release/modules/ext/slf4j-api-1.7.36.jar
file.reference.snakeyaml-2.0.jar=release/modules/ext/snakeyaml-2.0.jar
file.reference.SparseBitSet-1.1.jar=release/modules/ext/SparseBitSet-1.1.jar
file.reference.spotbugs-annotations-4.6.0.jar=release/modules/ext/spotbugs-annotations-4.6.0.jar
file.reference.sqlite-jdbc-3.42.0.0.jar=release/modules/ext/sqlite-jdbc-3.42.0.0.jar
file.reference.sqlite-jdbc-3.42.0.1.jar=release/modules/ext/sqlite-jdbc-3.42.0.1.jar
file.reference.txw2-2.3.3.jar=release/modules/ext/txw2-2.3.3.jar
file.reference.xalan-2.7.2.jar=release/modules/ext/xalan-2.7.2.jar
file.reference.xml-apis-1.4.01.jar=release/modules/ext/xml-apis-1.4.01.jar
@ -107,4 +107,4 @@ license.file=../LICENSE-2.0.txt
nbm.homepage=http://www.sleuthkit.org/
nbm.module.author=Brian Carrier
nbm.needs.restart=true
spec.version.base=10.24
spec.version.base=10.25

View File

@ -718,12 +718,12 @@
<binary-origin>release/modules/ext/sevenzipjbinding.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/sleuthkit-4.12.0.jar</runtime-relative-path>
<binary-origin>release/modules/ext/sleuthkit-4.12.0.jar</binary-origin>
<runtime-relative-path>ext/sleuthkit-4.12.1.jar</runtime-relative-path>
<binary-origin>release/modules/ext/sleuthkit-4.12.1.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/sleuthkit-caseuco-4.12.0.jar</runtime-relative-path>
<binary-origin>release/modules/ext/sleuthkit-caseuco-4.12.0.jar</binary-origin>
<runtime-relative-path>ext/sleuthkit-caseuco-4.12.1.jar</runtime-relative-path>
<binary-origin>release/modules/ext/sleuthkit-caseuco-4.12.1.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/slf4j-api-1.7.36.jar</runtime-relative-path>
@ -742,8 +742,8 @@
<binary-origin>release/modules/ext/spotbugs-annotations-4.6.0.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/sqlite-jdbc-3.42.0.0.jar</runtime-relative-path>
<binary-origin>release/modules/ext/sqlite-jdbc-3.42.0.0.jar</binary-origin>
<runtime-relative-path>ext/sqlite-jdbc-3.42.0.1.jar</runtime-relative-path>
<binary-origin>release/modules/ext/sqlite-jdbc-3.42.0.1.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/txw2-2.3.3.jar</runtime-relative-path>

View File

@ -0,0 +1,9 @@
# Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
# Click nbfs://nbhost/SystemFileSystem/Templates/Other/properties.properties to edit this template
CTIntegrationMissingDialog.title=Cyber Triage Importer Module Required
CTIntegrationMissingDialog.descriptionLabel.text=<html><body><p>The Cyber Triage Importer Module is required to open this case. </p><p>To open this case:</p><ul><li>Extract the module from the Integrations tab in the Cyber Triage options panel.</li><li>Select the 'Plugins' option from the 'Tools' menu, and go to the 'Downloaded' tab.</li><li>Click 'Add Plugins...' and select the path of the plugin.</li><li>Press 'Install' to finish the installation.</li></ul></body></html>
CTIntegrationMissingDialog.docsLabel.text=<html>For more information, refer to the Cyber Triage Users Guide</html>
CTIntegrationMissingDialog.okButton.text=OK

View File

@ -0,0 +1,9 @@
# Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
# Click nbfs://nbhost/SystemFileSystem/Templates/Other/properties.properties to edit this template
CTIntegrationMissingDialog.title=Cyber Triage Importer Module Required
CTIntegrationMissingDialog.descriptionLabel.text=<html><body><p>The Cyber Triage Importer Module is required to open this case. </p><p>To open this case:</p><ul><li>Extract the module from the Integrations tab in the Cyber Triage options panel.</li><li>Select the 'Plugins' option from the 'Tools' menu, and go to the 'Downloaded' tab.</li><li>Click 'Add Plugins...' and select the path of the plugin.</li><li>Press 'Install' to finish the installation.</li></ul></body></html>
CTIntegrationMissingDialog.docsLabel.text=<html>For more information, refer to the Cyber Triage Users Guide</html>
CTIntegrationMissingDialog.okButton.text=OK

View File

@ -1,24 +1,18 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JDialogFormInfo">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
<TitledBorder title="Disclaimer">
<ResourceString PropertyName="titleX" bundle="com/basistech/df/cybertriage/autopsy/ctoptions/Bundle.properties" key="LicenseDisclaimerPanel.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</TitledBorder>
</Border>
</Property>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[2147483647, 90]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[562, 90]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[400, 90]"/>
<Property name="defaultCloseOperation" type="int" value="2"/>
<Property name="title" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/Bundle.properties" key="CTIntegrationMissingDialog.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="alwaysOnTop" type="boolean" value="true"/>
<Property name="resizable" type="boolean" value="false"/>
</Properties>
<SyntheticProperties>
<SyntheticProperty name="formSizePolicy" type="int" value="1"/>
<SyntheticProperty name="generateCenter" type="boolean" value="false"/>
</SyntheticProperties>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
@ -29,17 +23,19 @@
<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,0,90,0,0,2,50"/>
<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,0,-65,0,0,1,-9"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
<SubComponents>
<Component class="javax.swing.JLabel" name="disclaimer">
<Component class="javax.swing.JLabel" name="descriptionLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/ctoptions/Bundle.properties" key="LicenseDisclaimerPanel.disclaimer.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/Bundle.properties" key="CTIntegrationMissingDialog.descriptionLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[483, 116]"/>
</Property>
<Property name="verticalAlignment" type="int" value="1"/>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
@ -51,10 +47,13 @@
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JLabel" name="purchaseFromLabel">
<Component class="javax.swing.JLabel" name="docsLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/ctoptions/Bundle.properties" key="LicenseDisclaimerPanel.purchaseFromLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/Bundle.properties" key="CTIntegrationMissingDialog.docsLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[312, 16]"/>
</Property>
</Properties>
<AuxValues>
@ -63,14 +62,14 @@
</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="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="5" insetsBottom="5" insetsRight="3" anchor="18" weightX="0.0" weightY="0.0"/>
<GridBagConstraints gridX="0" gridY="1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="5" insetsBottom="5" insetsRight="0" anchor="18" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JLabel" name="link">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/ctoptions/Bundle.properties" key="LicenseDisclaimerPanel.link.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="&quot;&lt;html&gt;&lt;span style=\&quot;color: blue; text-decoration: underline\&quot;&gt;&quot; + DOCS_PAGE_URL + &quot;&lt;/span&gt;&lt;/html&gt;&quot;" type="code"/>
</Property>
<Property name="cursor" type="java.awt.Cursor" editor="org.netbeans.modules.form.editors2.CursorEditor">
<Color id="Hand Cursor"/>
@ -79,24 +78,20 @@
<Events>
<EventHandler event="mouseClicked" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="linkMouseClicked"/>
</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="1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="5" insetsRight="5" anchor="18" weightX="1.0" weightY="0.0"/>
<GridBagConstraints gridX="1" gridY="1" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="5" insetsBottom="5" insetsRight="5" anchor="18" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Container class="javax.swing.JPanel" name="spacer">
<Container class="javax.swing.JPanel" name="paddingPanel">
<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="2" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="1.0"/>
<GridBagConstraints gridX="0" gridY="2" gridWidth="2" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="1.0"/>
</Constraint>
</Constraints>
@ -113,5 +108,24 @@
</DimensionLayout>
</Layout>
</Container>
<Component class="javax.swing.JButton" name="okButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/Bundle.properties" key="CTIntegrationMissingDialog.okButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="okButtonActionPerformed"/>
</Events>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="1" gridY="2" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="10" insetsLeft="5" insetsBottom="5" insetsRight="5" anchor="12" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
</SubComponents>
</Form>

View File

@ -0,0 +1,165 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2023 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 com.basistech.df.cybertriage.autopsy;
import java.awt.Desktop;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.logging.Level;
import javax.swing.JComponent;
import org.sleuthkit.autopsy.coreutils.Logger;
/**
* Provides directions with how to enable CT integration with Autopsy when
* trying to open a CT exported case.
*/
public class CTIntegrationMissingDialog extends javax.swing.JDialog {
private static final String DOCS_PAGE_URL = "https://docs.cybertriage.com/en/latest/chapters/integrations/autopsy.html";
private static final Logger LOGGER = Logger.getLogger(CTIntegrationMissingDialog.class.getName());
/**
* Creates new form CTIntegrationMissingDialog
*/
public CTIntegrationMissingDialog(java.awt.Frame parent, boolean modal) {
super(parent, modal);
initComponents();
}
/**
* 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 descriptionLabel = new javax.swing.JLabel();
javax.swing.JLabel docsLabel = new javax.swing.JLabel();
link = new javax.swing.JLabel();
javax.swing.JPanel paddingPanel = new javax.swing.JPanel();
javax.swing.JButton okButton = new javax.swing.JButton();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
setTitle(org.openide.util.NbBundle.getMessage(CTIntegrationMissingDialog.class, "CTIntegrationMissingDialog.title")); // NOI18N
setAlwaysOnTop(true);
setResizable(false);
getContentPane().setLayout(new java.awt.GridBagLayout());
org.openide.awt.Mnemonics.setLocalizedText(descriptionLabel, org.openide.util.NbBundle.getMessage(CTIntegrationMissingDialog.class, "CTIntegrationMissingDialog.descriptionLabel.text")); // NOI18N
descriptionLabel.setMinimumSize(new java.awt.Dimension(483, 116));
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.gridwidth = 2;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
getContentPane().add(descriptionLabel, gridBagConstraints);
org.openide.awt.Mnemonics.setLocalizedText(docsLabel, org.openide.util.NbBundle.getMessage(CTIntegrationMissingDialog.class, "CTIntegrationMissingDialog.docsLabel.text")); // NOI18N
docsLabel.setMinimumSize(new java.awt.Dimension(312, 16));
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.insets = new java.awt.Insets(0, 5, 5, 0);
getContentPane().add(docsLabel, gridBagConstraints);
org.openide.awt.Mnemonics.setLocalizedText(link, "<html><span style=\"color: blue; text-decoration: underline\">" + DOCS_PAGE_URL + "</span></html>");
link.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
link.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseClicked(java.awt.event.MouseEvent evt) {
linkMouseClicked(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 1;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(0, 5, 5, 5);
getContentPane().add(link, gridBagConstraints);
javax.swing.GroupLayout paddingPanelLayout = new javax.swing.GroupLayout(paddingPanel);
paddingPanel.setLayout(paddingPanelLayout);
paddingPanelLayout.setHorizontalGroup(
paddingPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 0, Short.MAX_VALUE)
);
paddingPanelLayout.setVerticalGroup(
paddingPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 0, Short.MAX_VALUE)
);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 2;
gridBagConstraints.gridwidth = 2;
gridBagConstraints.weighty = 1.0;
getContentPane().add(paddingPanel, gridBagConstraints);
org.openide.awt.Mnemonics.setLocalizedText(okButton, org.openide.util.NbBundle.getMessage(CTIntegrationMissingDialog.class, "CTIntegrationMissingDialog.okButton.text")); // NOI18N
okButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
okButtonActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 2;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHEAST;
gridBagConstraints.insets = new java.awt.Insets(10, 5, 5, 5);
getContentPane().add(okButton, gridBagConstraints);
pack();
}// </editor-fold>//GEN-END:initComponents
private void linkMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_linkMouseClicked
if (Desktop.isDesktopSupported()) {
try {
Desktop.getDesktop().browse(new URI(DOCS_PAGE_URL));
} catch (IOException | URISyntaxException e) {
LOGGER.log(Level.SEVERE, "Error opening link to: " + DOCS_PAGE_URL, e);
}
} else {
LOGGER.log(Level.WARNING, "Desktop API is not supported. Link cannot be opened.");
}
}//GEN-LAST:event_linkMouseClicked
private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed
dispose();
}//GEN-LAST:event_okButtonActionPerformed
public void showDialog(JComponent parentComp) {
setLocationRelativeTo(parentComp == null ? getParent() : parentComp);
pack();
setVisible(true);
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JLabel link;
// End of variables declaration//GEN-END:variables
}

View File

@ -25,9 +25,12 @@ import com.basistech.df.cybertriage.autopsy.ctapi.json.CTCloudBean;
import com.basistech.df.cybertriage.autopsy.ctapi.json.CTCloudBeanResponse;
import com.basistech.df.cybertriage.autopsy.ctapi.json.DecryptedLicenseResponse;
import com.basistech.df.cybertriage.autopsy.ctapi.json.FileReputationRequest;
import com.basistech.df.cybertriage.autopsy.ctapi.json.FileUploadRequest;
import com.basistech.df.cybertriage.autopsy.ctapi.json.LicenseRequest;
import com.basistech.df.cybertriage.autopsy.ctapi.json.LicenseResponse;
import com.basistech.df.cybertriage.autopsy.ctapi.json.MetadataUploadRequest;
import com.basistech.df.cybertriage.autopsy.ctapi.util.CTHostIDGenerationUtil;
import java.io.InputStream;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
@ -45,6 +48,8 @@ public class CTApiDAO {
private static final String LICENSE_REQUEST_PATH = "/_ah/api/license/v1/activate";
private static final String AUTH_TOKEN_REQUEST_PATH = "/_ah/api/auth/v2/generate_token";
private static final String CTCLOUD_SERVER_HASH_PATH = "/_ah/api/reputation/v1/query/file/hash/md5?query_types=CORRELATION,MALWARE";
private static final String CTCLOUD_UPLOAD_FILE_METADATA_PATH = "/_ah/api/reputation/v1/upload/meta";
private static final String AUTOPSY_PRODUCT = "AUTOPSY";
private static final CTApiDAO instance = new CTApiDAO();
@ -74,15 +79,28 @@ public class CTApiDAO {
}
public AuthTokenResponse getAuthToken(DecryptedLicenseResponse decrypted) throws CTCloudException {
return getAuthToken(decrypted, null);
}
public AuthTokenResponse getAuthToken(DecryptedLicenseResponse decrypted, Long fileUploadSize) throws CTCloudException {
AuthTokenRequest authTokenRequest = new AuthTokenRequest()
.setAutopsyVersion(getAppVersion())
.setRequestFileUpload(false)
.setRequestFileUpload(fileUploadSize != null && fileUploadSize > 0)
.setFileUploadSize(fileUploadSize != null && fileUploadSize > 0 ? fileUploadSize : null)
.setBoostLicenseId(decrypted.getBoostLicenseId())
.setHostId(decrypted.getLicenseHostId());
return httpClient.doPost(AUTH_TOKEN_REQUEST_PATH, authTokenRequest, AuthTokenResponse.class);
}
public void uploadFile(FileUploadRequest fileUploadRequest) throws CTCloudException {
httpClient.doFileUploadPut(fileUploadRequest);
}
public void uploadMeta(AuthenticatedRequestData authenticatedRequestData, MetadataUploadRequest metaRequest) throws CTCloudException {
httpClient.doPost(CTCLOUD_UPLOAD_FILE_METADATA_PATH, getAuthParams(authenticatedRequestData), metaRequest, null);
}
private static Map<String, String> getAuthParams(AuthenticatedRequestData authenticatedRequestData) {
return new HashMap<String, String>() {
{

View File

@ -76,8 +76,7 @@ public class CTCloudException extends Exception{
public String getErrorDetails() {
if(getErrorCode() == CTCloudException.ErrorCode.UNKNOWN && Objects.nonNull(getCause())){
return String.format("Malware scan error %s occurred. Please try \"Re Scan\" from the dashboard to attempt Malware scaning again. "
+ "\nPlease contact Basis support at %s for help if the problem presists.",
return String.format("An API error %s occurred. Please try again, and contact Basis support at %s for help if the problem persists.",
StringUtils.isNotBlank(getCause().getLocalizedMessage()) ? "("+getCause().getLocalizedMessage()+")": "(Unknown)",
Constants.SUPPORT_AT_CYBERTRIAGE_DOT_COM );
}else {

View File

@ -18,148 +18,127 @@
*/
package com.basistech.df.cybertriage.autopsy.ctapi;
import com.basistech.df.cybertriage.autopsy.ctapi.CTCloudException.ErrorCode;
import com.basistech.df.cybertriage.autopsy.ctapi.json.FileUploadRequest;
import com.basistech.df.cybertriage.autopsy.ctapi.util.ObjectMapperUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.net.Authenticator;
import java.net.InetAddress;
import java.net.PasswordAuthentication;
import java.io.InputStream;
import java.net.Proxy;
import java.net.ProxySelector;
import java.net.SocketAddress;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.logging.Level;
import java.util.stream.Stream;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpStatus;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.NTCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.config.AuthSchemes;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.InputStreamEntity;
import org.apache.http.entity.StringEntity;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.client.SystemDefaultCredentialsProvider;
import org.apache.http.impl.client.WinHttpClients;
import org.apache.http.impl.conn.SystemDefaultRoutePlanner;
import org.apache.http.ssl.SSLInitializationException;
import org.netbeans.core.ProxySettings;
import org.openide.util.Lookup;
import org.sleuthkit.autopsy.coreutils.Version;
/**
* Makes the http requests to CT cloud.
*
* NOTE: regarding proxy settings, the host and port are handled by the
* NbProxySelector. Any proxy authentication is handled by NbAuthenticator which
* is installed at startup (i.e. NbAuthenticator.install). See
* GeneralOptionsModel.testHttpConnection to see how the general options panel
* tests the connection.
*/
public class CTCloudHttpClient {
class CTCloudHttpClient {
private static final CTCloudHttpClient instance = new CTCloudHttpClient();
private static final Logger LOGGER = Logger.getLogger(CTCloudHttpClient.class.getName());
private static final String HOST_URL = Version.getBuildType() == Version.Type.RELEASE ? Constants.CT_CLOUD_SERVER : Constants.CT_CLOUD_DEV_SERVER;
private static final List<String> DEFAULT_SCHEME_PRIORITY
= new ArrayList<>(Arrays.asList(
AuthSchemes.SPNEGO,
AuthSchemes.KERBEROS,
AuthSchemes.NTLM,
AuthSchemes.CREDSSP,
AuthSchemes.DIGEST,
AuthSchemes.BASIC));
private static final String NB_PROXY_SELECTOR_NAME = "org.netbeans.core.NbProxySelector";
private static final int CONNECTION_TIMEOUT_MS = 58 * 1000; // milli sec
private static final CTCloudHttpClient instance = new CTCloudHttpClient();
public static CTCloudHttpClient getInstance() {
return instance;
}
private final ObjectMapper mapper = ObjectMapperUtil.getInstance().getDefaultObjectMapper();
private final SSLContext sslContext;
private String hostName = null;
private final ProxySelector proxySelector;
private CTCloudHttpClient() {
// leave as null for now unless we want to customize this at a later date
this.sslContext = null;
this.sslContext = createSSLContext();
this.proxySelector = getProxySelector();
}
private ProxySettingArgs getProxySettings() {
if (StringUtils.isBlank(hostName)) {
try {
hostName = InetAddress.getLocalHost().getCanonicalHostName();
} catch (UnknownHostException ex) {
LOGGER.log(Level.WARNING, "An error occurred while fetching the hostname", ex);
private static URI getUri(String host, String path, Map<String, String> urlReqParams) throws URISyntaxException {
String url = host + path;
URIBuilder builder = new URIBuilder(url);
if (!MapUtils.isEmpty(urlReqParams)) {
for (Entry<String, String> e : urlReqParams.entrySet()) {
String key = e.getKey();
String value = e.getValue();
if (StringUtils.isNotBlank(key) || StringUtils.isNotBlank(value)) {
builder.addParameter(key, value);
}
}
}
int proxyPort = 0;
if (StringUtils.isNotBlank(ProxySettings.getHttpPort())) {
try {
proxyPort = Integer.parseInt(ProxySettings.getHttpsPort());
} catch (NumberFormatException ex) {
LOGGER.log(Level.WARNING, "Unable to convert port to integer");
}
}
return new ProxySettingArgs(
ProxySettings.getProxyType() != ProxySettings.DIRECT_CONNECTION,
hostName,
ProxySettings.getHttpsHost(),
proxyPort,
ProxySettings.getAuthenticationUsername(),
ProxySettings.getAuthenticationPassword(),
null
);
return builder.build();
}
public <O> O doPost(String urlPath, Object jsonBody, Class<O> classType) throws CTCloudException {
return doPost(urlPath, Collections.emptyMap(), jsonBody, classType);
}
public <O> O doPost(String urlPath, Map<String, String> urlReqParams, Object jsonBody, Class<O> classType) throws CTCloudException {
String url = HOST_URL + urlPath;
URI postURI = null;
try {
postURI = getUri(HOST_URL, urlPath, urlReqParams);
LOGGER.log(Level.INFO, "initiating http connection to ctcloud server");
try (CloseableHttpClient httpclient = createConnection(getProxySettings(), sslContext)) {
URIBuilder builder = new URIBuilder(url);
if (!MapUtils.isEmpty(urlReqParams)) {
for (Entry<String, String> e : urlReqParams.entrySet()) {
String key = e.getKey();
String value = e.getValue();
if (StringUtils.isNotBlank(key) || StringUtils.isNotBlank(value)) {
builder.addParameter(key, value);
}
}
}
try (CloseableHttpClient httpclient = createConnection(proxySelector, sslContext)) {
URI postURI = builder.build();
HttpPost postRequest = new HttpPost(postURI);
configureRequestTimeout(postRequest);
postRequest.setHeader("Content-type", "application/json");
@ -177,30 +156,92 @@ public class CTCloudHttpClient {
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
LOGGER.log(Level.INFO, "Response Received. - Status OK");
// Parse Response
HttpEntity entity = response.getEntity();
String entityStr = EntityUtils.toString(entity);
O respObj = mapper.readValue(entityStr, classType);
return respObj;
if (classType != null) {
HttpEntity entity = response.getEntity();
if (entity != null) {
String entityStr = EntityUtils.toString(entity);
if (StringUtils.isNotBlank(entityStr)) {
O respObj = mapper.readValue(entityStr, classType);
return respObj;
}
}
}
return null;
} else {
LOGGER.log(Level.WARNING, "Response Received. - Status Error {}", response.getStatusLine());
handleNonOKResponse(response, "");
}
// transform all non-CTCloudException's into a CTCloudException
} catch (CTCloudException ex) {
throw ex;
} catch (Exception ex) {
LOGGER.log(Level.WARNING, "Error when parsing response from CyberTriage Cloud", ex);
throw new CTCloudException(CTCloudException.parseUnknownException(ex), ex);
}
}
} catch (IOException ex) {
LOGGER.log(Level.WARNING, "IO Exception raised when connecting to CT Cloud using " + url, ex);
LOGGER.log(Level.WARNING, "IO Exception raised when connecting to CT Cloud using " + postURI, ex);
throw new CTCloudException(CTCloudException.ErrorCode.NETWORK_ERROR, ex);
} catch (SSLInitializationException ex) {
LOGGER.log(Level.WARNING, "No such algorithm exception raised when creating SSL connection for CT Cloud using " + postURI, ex);
throw new CTCloudException(CTCloudException.ErrorCode.NETWORK_ERROR, ex);
} catch (URISyntaxException ex) {
LOGGER.log(Level.WARNING, "Wrong URL syntax for CT Cloud " + url, ex);
LOGGER.log(Level.WARNING, "Wrong URL syntax for CT Cloud " + postURI, ex);
throw new CTCloudException(CTCloudException.ErrorCode.UNKNOWN, ex);
}
return null;
}
public void doFileUploadPut(FileUploadRequest fileUploadRequest) throws CTCloudException {
if (fileUploadRequest == null) {
throw new CTCloudException(ErrorCode.BAD_REQUEST, new IllegalArgumentException("fileUploadRequest cannot be null"));
}
String fullUrlPath = fileUploadRequest.getFullUrlPath();
String fileName = fileUploadRequest.getFileName();
InputStream fileInputStream = fileUploadRequest.getFileInputStream();
Long contentLength = fileUploadRequest.getContentLength();
if (StringUtils.isBlank(fullUrlPath) || fileInputStream == null || contentLength == null || contentLength <= 0) {
throw new CTCloudException(ErrorCode.BAD_REQUEST, new IllegalArgumentException("fullUrlPath, fileInputStream, contentLength must not be empty, null or less than 0"));
}
URI putUri;
try {
putUri = new URI(fullUrlPath);
} catch (URISyntaxException ex) {
LOGGER.log(Level.WARNING, "Wrong URL syntax for CT Cloud " + fullUrlPath, ex);
throw new CTCloudException(CTCloudException.ErrorCode.UNKNOWN, ex);
}
try (CloseableHttpClient httpclient = createConnection(proxySelector, sslContext)) {
LOGGER.log(Level.INFO, "initiating http post request to ctcloud server " + fullUrlPath);
HttpPut put = new HttpPut(putUri);
configureRequestTimeout(put);
put.addHeader("Connection", "keep-alive");
put.setEntity(new InputStreamEntity(fileInputStream, contentLength, ContentType.APPLICATION_OCTET_STREAM));
try (CloseableHttpResponse response = httpclient.execute(put)) {
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == HttpStatus.SC_OK || statusCode == HttpStatus.SC_NO_CONTENT) {
LOGGER.log(Level.INFO, "Response Received. - Status OK");
} else {
LOGGER.log(Level.WARNING, MessageFormat.format("Response Received. - Status Error {0}", response.getStatusLine()));
handleNonOKResponse(response, fileName);
}
}
} catch (SSLInitializationException ex) {
LOGGER.log(Level.WARNING, "SSL exception raised when connecting to Reversing Labs for file content upload ", ex);
throw new CTCloudException(CTCloudException.ErrorCode.NETWORK_ERROR, ex);
} catch (IOException ex) {
LOGGER.log(Level.WARNING, "IO Exception raised when connecting to Reversing Labs for file content upload ", ex);
throw new CTCloudException(CTCloudException.ErrorCode.NETWORK_ERROR, ex);
}
}
/**
* A generic way to handle the HTTP response - when the response code is NOT
* 200 OK.
@ -263,147 +304,140 @@ public class CTCloudHttpClient {
}
/**
* Creates a connection to CT Cloud with the given arguments.
* @param proxySettings The network proxy settings.
* @param sslContext The ssl context or null.
* @return The connection to CT Cloud.
* Get ProxySelector present (favoring NbProxySelector if present).
*
* @return The found ProxySelector or null.
*/
private static CloseableHttpClient createConnection(ProxySettingArgs proxySettings, SSLContext sslContext) {
HttpClientBuilder builder = getHttpClientBuilder(proxySettings);
if (sslContext != null) {
builder.setSSLContext(sslContext);
}
return builder.build();
private static ProxySelector getProxySelector() {
Collection<? extends ProxySelector> selectors = Lookup.getDefault().lookupAll(ProxySelector.class);
return (selectors != null ? selectors.stream() : Stream.empty())
.filter(s -> s != null)
.map(s -> (ProxySelector) s)
.sorted((a, b) -> {
String aName = a.getClass().getCanonicalName();
String bName = b.getClass().getCanonicalName();
boolean aIsNb = aName.equalsIgnoreCase(NB_PROXY_SELECTOR_NAME);
boolean bIsNb = bName.equalsIgnoreCase(NB_PROXY_SELECTOR_NAME);
if (aIsNb == bIsNb) {
return StringUtils.compareIgnoreCase(aName, bName);
} else {
return aIsNb ? -1 : 1;
}
})
.findFirst()
// TODO take this out to remove proxy selector logging
.map(s -> new LoggingProxySelector(s))
.orElse(null);
}
private static HttpClientBuilder getHttpClientBuilder(ProxySettingArgs proxySettings) {
/**
* Create an SSLContext object using our in-memory keystore.
*
* @return
*/
private static SSLContext createSSLContext() {
LOGGER.log(Level.INFO, "Creating custom SSL context");
try {
if (proxySettings.isSystemOrManualProxy()) {
// I'm not sure how much of this is really necessary to set up, but it works
SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
KeyManager[] keyManagers = getKeyManagers();
TrustManager[] trustManagers = getTrustManagers();
sslContext.init(keyManagers, trustManagers, new SecureRandom());
return sslContext;
} catch (NoSuchAlgorithmException | KeyManagementException ex) {
LOGGER.log(Level.SEVERE, "Error creating SSL context", ex);
return null;
}
}
Authenticator.setDefault(new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
LOGGER.info("Requesting Password Authentication...");
return super.getPasswordAuthentication();
}
});
// jvm default key manager
// based in part on this: https://stackoverflow.com/questions/1793979/registering-multiple-keystores-in-jvm/16229909
private static KeyManager[] getKeyManagers() {
LOGGER.log(Level.INFO, "Using default algorithm to create trust store: " + KeyManagerFactory.getDefaultAlgorithm());
try {
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(null, null);
return kmf.getKeyManagers();
} catch (NoSuchAlgorithmException | KeyStoreException | UnrecoverableKeyException ex) {
LOGGER.log(Level.SEVERE, "Error getting KeyManagers", ex);
return new KeyManager[0];
}
HttpClientBuilder builder = null;
HttpHost proxyHost = null;
CredentialsProvider proxyCredsProvider = null;
RequestConfig config = null;
}
if (Objects.nonNull(proxySettings.getProxyHostname()) && proxySettings.getProxyPort() > 0) {
proxyHost = new HttpHost(proxySettings.getProxyHostname(), proxySettings.getProxyPort());
// jvm default trust store
// based in part on this: https://stackoverflow.com/questions/1793979/registering-multiple-keystores-in-jvm/16229909
private static TrustManager[] getTrustManagers() {
try {
LOGGER.log(Level.INFO, "Using default algorithm to create trust store: " + TrustManagerFactory.getDefaultAlgorithm());
TrustManagerFactory tmf
= TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init((KeyStore) null);
X509TrustManager tm = (X509TrustManager) tmf.getTrustManagers()[0];
proxyCredsProvider = getProxyCredentialsProvider(proxySettings);
if (StringUtils.isNotBlank(proxySettings.getAuthScheme())) {
if (!DEFAULT_SCHEME_PRIORITY.get(0).equalsIgnoreCase(proxySettings.getAuthScheme())) {
DEFAULT_SCHEME_PRIORITY.removeIf(s -> s.equalsIgnoreCase(proxySettings.getAuthScheme()));
DEFAULT_SCHEME_PRIORITY.add(0, proxySettings.getAuthScheme());
}
}
config = RequestConfig.custom().setProxyPreferredAuthSchemes(DEFAULT_SCHEME_PRIORITY).build();
}
if (Objects.isNull(proxyCredsProvider) && WinHttpClients.isWinAuthAvailable()) {
builder = WinHttpClients.custom();
builder.useSystemProperties();
LOGGER.log(Level.WARNING, "Using Win HTTP Client");
} else {
builder = HttpClients.custom();
builder.setDefaultRequestConfig(config);
if (Objects.nonNull(proxyCredsProvider)) { // make sure non null proxycreds before setting it
builder.setDefaultCredentialsProvider(proxyCredsProvider);
}
LOGGER.log(Level.WARNING, "Using default http client");
}
if (Objects.nonNull(proxyHost)) {
builder.setProxy(proxyHost);
LOGGER.log(Level.WARNING, MessageFormat.format("Using proxy {0}", proxyHost));
}
return builder;
} else {
return HttpClients.custom();
return new TrustManager[]{tm};
} catch (KeyStoreException | NoSuchAlgorithmException ex) {
LOGGER.log(Level.SEVERE, "Error getting TrustManager", ex);
return new TrustManager[0];
}
}
/**
* Returns a CredentialsProvider for proxy, if one is configured.
* Creates a connection to CT Cloud with the given arguments.
*
* @return CredentialsProvider, if a proxy is configured with credentials,
* null otherwise
* @param proxySelector The proxy selector.
* @param sslContext The ssl context or null.
* @return The connection to CT Cloud.
*/
private static CredentialsProvider getProxyCredentialsProvider(ProxySettingArgs proxySettings) {
CredentialsProvider proxyCredsProvider = null;
if (proxySettings.isSystemOrManualProxy()) {
if (StringUtils.isNotBlank(proxySettings.getProxyUserId())) {
if (null != proxySettings.getProxyPassword() && proxySettings.getProxyPassword().length > 0) { // Password will be blank for KERBEROS / NEGOTIATE schemes.
proxyCredsProvider = new SystemDefaultCredentialsProvider();
String userId = proxySettings.getProxyUserId();
String domain = null;
if (userId.contains("\\")) {
domain = userId.split("\\\\")[0];
userId = userId.split("\\\\")[1];
}
String workStation = proxySettings.getHostName();
proxyCredsProvider.setCredentials(new AuthScope(proxySettings.getProxyHostname(), proxySettings.getProxyPort()),
new NTCredentials(userId, new String(proxySettings.getProxyPassword()), workStation, domain));
}
}
private static CloseableHttpClient createConnection(ProxySelector proxySelector, SSLContext sslContext) throws SSLInitializationException {
HttpClientBuilder builder;
if (ProxySettings.getProxyType() != ProxySettings.DIRECT_CONNECTION
&& StringUtils.isBlank(ProxySettings.getAuthenticationUsername())
&& ArrayUtils.isEmpty(ProxySettings.getAuthenticationPassword())
&& WinHttpClients.isWinAuthAvailable()) {
builder = WinHttpClients.custom();
builder.useSystemProperties();
LOGGER.log(Level.WARNING, "Using Win HTTP Client");
} else {
builder = HttpClients.custom();
// builder.setDefaultRequestConfig(config);
LOGGER.log(Level.WARNING, "Using default http client");
}
return proxyCredsProvider;
if (sslContext != null) {
builder.setSSLContext(sslContext);
}
if (proxySelector != null) {
builder.setRoutePlanner(new SystemDefaultRoutePlanner(proxySelector));
}
return builder.build();
}
private static class ProxySettingArgs {
private static class LoggingProxySelector extends ProxySelector {
private final boolean systemOrManualProxy;
private final String hostName;
private final String proxyHostname;
private final int proxyPort;
private final String proxyUserId;
private final char[] proxyPassword;
private final String authScheme;
private final ProxySelector delegate;
ProxySettingArgs(boolean systemOrManualProxy, String hostName, String proxyHostname, int proxyPort, String proxyUserId, char[] proxyPassword, String authScheme) {
this.systemOrManualProxy = systemOrManualProxy;
this.hostName = hostName;
this.proxyHostname = proxyHostname;
this.proxyPort = proxyPort;
this.proxyUserId = proxyUserId;
this.proxyPassword = proxyPassword;
this.authScheme = authScheme;
public LoggingProxySelector(ProxySelector delegate) {
this.delegate = delegate;
}
boolean isSystemOrManualProxy() {
return systemOrManualProxy;
@Override
public List<Proxy> select(URI uri) {
List<Proxy> selectedProxies = delegate.select(uri);
LOGGER.log(Level.INFO, MessageFormat.format("Proxy selected for {0} are {1}", uri, selectedProxies));
return selectedProxies;
}
String getHostName() {
return hostName;
@Override
public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {
LOGGER.log(Level.WARNING, MessageFormat.format("Connection failed connecting to {0} socket address {1}", uri, sa), ioe);
delegate.connectFailed(uri, sa, ioe);
}
String getProxyHostname() {
return proxyHostname;
}
int getProxyPort() {
return proxyPort;
}
String getProxyUserId() {
return proxyUserId;
}
char[] getProxyPassword() {
return proxyPassword;
}
public String getAuthScheme() {
return authScheme;
}
}
}

View File

@ -23,7 +23,7 @@ import java.net.URI;
/**
* Constants regarding connections to cyber triage cloud.
*/
final public class Constants {
final class Constants {
public static final String CYBER_TRIAGE = "CyberTriage";

View File

@ -1,446 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2023 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 com.basistech.df.cybertriage.autopsy.ctapi;
import java.net.*;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.prefs.PreferenceChangeListener;
import java.util.prefs.Preferences;
import org.netbeans.api.keyring.Keyring;
import org.openide.util.*;
import org.openide.util.lookup.ServiceProvider;
/**
* Taken from https://raw.githubusercontent.com/apache/netbeans/master/platform/o.n.core/src/org/netbeans/core/ProxySettings.java
* @author Jiri Rechtacek
*/
public class ProxySettings {
public static final String PROXY_HTTP_HOST = "proxyHttpHost"; // NOI18N
public static final String PROXY_HTTP_PORT = "proxyHttpPort"; // NOI18N
public static final String PROXY_HTTPS_HOST = "proxyHttpsHost"; // NOI18N
public static final String PROXY_HTTPS_PORT = "proxyHttpsPort"; // NOI18N
public static final String PROXY_SOCKS_HOST = "proxySocksHost"; // NOI18N
public static final String PROXY_SOCKS_PORT = "proxySocksPort"; // NOI18N
public static final String NOT_PROXY_HOSTS = "proxyNonProxyHosts"; // NOI18N
public static final String PROXY_TYPE = "proxyType"; // NOI18N
public static final String USE_PROXY_AUTHENTICATION = "useProxyAuthentication"; // NOI18N
public static final String PROXY_AUTHENTICATION_USERNAME = "proxyAuthenticationUsername"; // NOI18N
public static final String PROXY_AUTHENTICATION_PASSWORD = "proxyAuthenticationPassword"; // NOI18N
public static final String USE_PROXY_ALL_PROTOCOLS = "useProxyAllProtocols"; // NOI18N
public static final String DIRECT = "DIRECT"; // NOI18N
public static final String PAC = "PAC"; // NOI18N
public static final String SYSTEM_PROXY_HTTP_HOST = "systemProxyHttpHost"; // NOI18N
public static final String SYSTEM_PROXY_HTTP_PORT = "systemProxyHttpPort"; // NOI18N
public static final String SYSTEM_PROXY_HTTPS_HOST = "systemProxyHttpsHost"; // NOI18N
public static final String SYSTEM_PROXY_HTTPS_PORT = "systemProxyHttpsPort"; // NOI18N
public static final String SYSTEM_PROXY_SOCKS_HOST = "systemProxySocksHost"; // NOI18N
public static final String SYSTEM_PROXY_SOCKS_PORT = "systemProxySocksPort"; // NOI18N
public static final String SYSTEM_NON_PROXY_HOSTS = "systemProxyNonProxyHosts"; // NOI18N
public static final String SYSTEM_PAC = "systemPAC"; // NOI18N
// Only for testing purpose (Test connection in General options panel)
public static final String TEST_SYSTEM_PROXY_HTTP_HOST = "testSystemProxyHttpHost"; // NOI18N
public static final String TEST_SYSTEM_PROXY_HTTP_PORT = "testSystemProxyHttpPort"; // NOI18N
public static final String HTTP_CONNECTION_TEST_URL = "https://netbeans.apache.org";// NOI18N
private static String presetNonProxyHosts;
/** No proxy is used to connect. */
public static final int DIRECT_CONNECTION = 0;
/** Proxy setting is automatically detect in OS. */
public static final int AUTO_DETECT_PROXY = 1; // as default
/** Manually set proxy host and port. */
public static final int MANUAL_SET_PROXY = 2;
/** Proxy PAC file automatically detect in OS. */
public static final int AUTO_DETECT_PAC = 3;
/** Proxy PAC file manually set. */
public static final int MANUAL_SET_PAC = 4;
private static final Logger LOGGER = Logger.getLogger(ProxySettings.class.getName());
private static Preferences getPreferences() {
return NbPreferences.forModule (ProxySettings.class);
}
public static String getHttpHost () {
return normalizeProxyHost (getPreferences ().get (PROXY_HTTP_HOST, ""));
}
public static String getHttpPort () {
return getPreferences ().get (PROXY_HTTP_PORT, "");
}
public static String getHttpsHost () {
if (useProxyAllProtocols ()) {
return getHttpHost ();
} else {
return getPreferences ().get (PROXY_HTTPS_HOST, "");
}
}
public static String getHttpsPort () {
if (useProxyAllProtocols ()) {
return getHttpPort ();
} else {
return getPreferences ().get (PROXY_HTTPS_PORT, "");
}
}
public static String getSocksHost () {
if (useProxyAllProtocols ()) {
return getHttpHost ();
} else {
return getPreferences ().get (PROXY_SOCKS_HOST, "");
}
}
public static String getSocksPort () {
if (useProxyAllProtocols ()) {
return getHttpPort ();
} else {
return getPreferences ().get (PROXY_SOCKS_PORT, "");
}
}
public static String getNonProxyHosts () {
String hosts = getPreferences ().get (NOT_PROXY_HOSTS, getDefaultUserNonProxyHosts ());
return compactNonProxyHosts(hosts);
}
public static int getProxyType () {
int type = getPreferences ().getInt (PROXY_TYPE, AUTO_DETECT_PROXY);
if (AUTO_DETECT_PROXY == type) {
type = ProxySettings.getSystemPac() != null ? AUTO_DETECT_PAC : AUTO_DETECT_PROXY;
}
return type;
}
public static String getSystemHttpHost() {
return getPreferences().get(SYSTEM_PROXY_HTTP_HOST, "");
}
public static String getSystemHttpPort() {
return getPreferences().get(SYSTEM_PROXY_HTTP_PORT, "");
}
public static String getSystemHttpsHost() {
return getPreferences().get(SYSTEM_PROXY_HTTPS_HOST, "");
}
public static String getSystemHttpsPort() {
return getPreferences().get(SYSTEM_PROXY_HTTPS_PORT, "");
}
public static String getSystemSocksHost() {
return getPreferences().get(SYSTEM_PROXY_SOCKS_HOST, "");
}
public static String getSystemSocksPort() {
return getPreferences().get(SYSTEM_PROXY_SOCKS_PORT, "");
}
public static String getSystemNonProxyHosts() {
return getPreferences().get(SYSTEM_NON_PROXY_HOSTS, getModifiedNonProxyHosts(""));
}
public static String getSystemPac() {
return getPreferences().get(SYSTEM_PAC, null);
}
public static String getTestSystemHttpHost() {
return getPreferences().get(TEST_SYSTEM_PROXY_HTTP_HOST, "");
}
public static String getTestSystemHttpPort() {
return getPreferences().get(TEST_SYSTEM_PROXY_HTTP_PORT, "");
}
public static boolean useAuthentication () {
return getPreferences ().getBoolean (USE_PROXY_AUTHENTICATION, false);
}
public static boolean useProxyAllProtocols () {
return getPreferences ().getBoolean (USE_PROXY_ALL_PROTOCOLS, false);
}
public static String getAuthenticationUsername () {
return getPreferences ().get (PROXY_AUTHENTICATION_USERNAME, "");
}
public static char[] getAuthenticationPassword () {
String old = getPreferences().get(PROXY_AUTHENTICATION_PASSWORD, null);
if (old != null) {
getPreferences().remove(PROXY_AUTHENTICATION_PASSWORD);
setAuthenticationPassword(old.toCharArray());
}
char[] pwd = Keyring.read(PROXY_AUTHENTICATION_PASSWORD);
return pwd != null ? pwd : new char[0];
}
public static void setAuthenticationPassword(char[] password) {
Keyring.save(ProxySettings.PROXY_AUTHENTICATION_PASSWORD, password,
// XXX consider including getHttpHost and/or getHttpsHost
NbBundle.getMessage(ProxySettings.class, "ProxySettings.password.description")); // NOI18N
}
public static void addPreferenceChangeListener (PreferenceChangeListener l) {
getPreferences ().addPreferenceChangeListener (l);
}
public static void removePreferenceChangeListener (PreferenceChangeListener l) {
getPreferences ().removePreferenceChangeListener (l);
}
private static String getPresetNonProxyHosts () {
if (presetNonProxyHosts == null) {
presetNonProxyHosts = System.getProperty ("http.nonProxyHosts", ""); // NOI18N
}
return presetNonProxyHosts;
}
private static String getDefaultUserNonProxyHosts () {
return getModifiedNonProxyHosts (getSystemNonProxyHosts ());
}
private static String concatProxies(String... proxies) {
StringBuilder sb = new StringBuilder();
for (String n : proxies) {
if (n == null) {
continue;
}
n = n.trim();
if (n.isEmpty()) {
continue;
}
if (sb.length() > 0 && sb.charAt(sb.length() - 1) != '|') { // NOI18N
if (!n.startsWith("|")) { // NOI18N
sb.append('|'); // NOI18N
}
}
sb.append(n);
}
return sb.toString();
}
private static String getModifiedNonProxyHosts (String systemPreset) {
String fromSystem = systemPreset.replace (";", "|").replace (",", "|"); //NOI18N
String fromUser = getPresetNonProxyHosts () == null ? "" : getPresetNonProxyHosts ().replace (";", "|").replace (",", "|"); //NOI18N
if (Utilities.isWindows ()) {
fromSystem = addReguralToNonProxyHosts (fromSystem);
}
final String staticNonProxyHosts = NbBundle.getMessage(ProxySettings.class, "StaticNonProxyHosts"); // NOI18N
String nonProxy = concatProxies(fromUser, fromSystem, staticNonProxyHosts); // NOI18N
String localhost;
try {
localhost = InetAddress.getLocalHost().getHostName();
if (!"localhost".equals(localhost)) { // NOI18N
nonProxy = nonProxy + "|" + localhost; // NOI18N
} else {
// Avoid this error when hostname == localhost:
// Error in http.nonProxyHosts system property: sun.misc.REException: localhost is a duplicate
}
}
catch (UnknownHostException e) {
// OK. Sometimes a hostname is assigned by DNS, but a computer
// is later pulled off the network. It may then produce a bogus
// name for itself which can't actually be resolved. Normally
// "localhost" is aliased to 127.0.0.1 anyway.
}
/* per Milan's agreement it's removed. See issue #89868
try {
String localhost2 = InetAddress.getLocalHost().getCanonicalHostName();
if (!"localhost".equals(localhost2) && !localhost2.equals(localhost)) { // NOI18N
nonProxy = nonProxy + "|" + localhost2; // NOI18N
} else {
// Avoid this error when hostname == localhost:
// Error in http.nonProxyHosts system property: sun.misc.REException: localhost is a duplicate
}
}
catch (UnknownHostException e) {
// OK. Sometimes a hostname is assigned by DNS, but a computer
// is later pulled off the network. It may then produce a bogus
// name for itself which can't actually be resolved. Normally
// "localhost" is aliased to 127.0.0.1 anyway.
}
*/
return compactNonProxyHosts (nonProxy);
}
// avoid duplicate hosts
private static String compactNonProxyHosts (String hosts) {
StringTokenizer st = new StringTokenizer(hosts, ","); //NOI18N
StringBuilder nonProxyHosts = new StringBuilder();
while (st.hasMoreTokens()) {
String h = st.nextToken().trim();
if (h.length() == 0) {
continue;
}
if (nonProxyHosts.length() > 0) {
nonProxyHosts.append("|"); // NOI18N
}
nonProxyHosts.append(h);
}
st = new StringTokenizer (nonProxyHosts.toString(), "|"); //NOI18N
Set<String> set = new HashSet<String> ();
StringBuilder compactedProxyHosts = new StringBuilder();
while (st.hasMoreTokens ()) {
String t = st.nextToken ();
if (set.add (t.toLowerCase (Locale.US))) {
if (compactedProxyHosts.length() > 0) {
compactedProxyHosts.append('|'); // NOI18N
}
compactedProxyHosts.append(t);
}
}
return compactedProxyHosts.toString();
}
private static String addReguralToNonProxyHosts (String nonProxyHost) {
StringTokenizer st = new StringTokenizer (nonProxyHost, "|"); // NOI18N
StringBuilder reguralProxyHosts = new StringBuilder();
while (st.hasMoreTokens ()) {
String t = st.nextToken ();
if (t.indexOf ('*') == -1) { //NOI18N
t = t + '*'; //NOI18N
}
if (reguralProxyHosts.length() > 0)
reguralProxyHosts.append('|'); // NOI18N
reguralProxyHosts.append(t);
}
return reguralProxyHosts.toString();
}
public static String normalizeProxyHost (String proxyHost) {
if (proxyHost.toLowerCase (Locale.US).startsWith ("http://")) { // NOI18N
return proxyHost.substring (7, proxyHost.length ());
} else {
return proxyHost;
}
}
private static InetSocketAddress analyzeProxy(URI uri) {
Parameters.notNull("uri", uri); // NOI18N
List<Proxy> proxies = ProxySelector.getDefault().select(uri);
assert proxies != null : "ProxySelector cannot return null for " + uri; // NOI18N
assert !proxies.isEmpty() : "ProxySelector cannot return empty list for " + uri; // NOI18N
String protocol = uri.getScheme();
Proxy p = proxies.get(0);
if (Proxy.Type.DIRECT == p.type()) {
// return null for DIRECT proxy
return null;
}
if (protocol == null
|| ((protocol.startsWith("http") || protocol.equals("ftp")) && Proxy.Type.HTTP == p.type()) // NOI18N
|| !(protocol.startsWith("http") || protocol.equals("ftp"))) { // NOI18N
if (p.address() instanceof InetSocketAddress) {
// check is
//assert ! ((InetSocketAddress) p.address()).isUnresolved() : p.address() + " must be resolved address.";
return (InetSocketAddress) p.address();
} else {
LOGGER.log(Level.INFO, p.address() + " is not instanceof InetSocketAddress but " + p.address().getClass()); // NOI18N
return null;
}
} else {
return null;
}
}
public static void reload() {
Reloader reloader = Lookup.getDefault().lookup(Reloader.class);
reloader.reload();
}
@ServiceProvider(service = NetworkSettings.ProxyCredentialsProvider.class, position = 1000)
public static class NbProxyCredentialsProvider extends NetworkSettings.ProxyCredentialsProvider {
@Override
public String getProxyHost(URI u) {
if (getPreferences() == null) {
return null;
}
InetSocketAddress sa = analyzeProxy(u);
return sa == null ? null : sa.getHostName();
}
@Override
public String getProxyPort(URI u) {
if (getPreferences() == null) {
return null;
}
InetSocketAddress sa = analyzeProxy(u);
return sa == null ? null : Integer.toString(sa.getPort());
}
@Override
protected String getProxyUserName(URI u) {
if (getPreferences() == null) {
return null;
}
return ProxySettings.getAuthenticationUsername();
}
@Override
protected char[] getProxyPassword(URI u) {
if (getPreferences() == null) {
return null;
}
return ProxySettings.getAuthenticationPassword();
}
@Override
protected boolean isProxyAuthentication(URI u) {
if (getPreferences() == null) {
return false;
}
return getPreferences().getBoolean(USE_PROXY_AUTHENTICATION, false);
}
}
/** A bridge between <code>o.n.core</code> and <code>core.network</code>.
* An implementation of this class brings a facility to reload Network Proxy Settings
* from underlying OS.
* The module <code>core.network</code> provides a implementation which may be accessible
* via <code>Lookup.getDefault()</code>. It's not guaranteed any implementation is found on all distribution.
*
* @since 3.40
*/
public abstract static class Reloader {
/** Reloads Network Proxy Settings from underlying system.
*
*/
public abstract void reload();
}
}

View File

@ -34,6 +34,9 @@ public class AuthTokenRequest {
@JsonProperty("requestFileUpload")
private boolean requestFileUpload;
@JsonProperty("fileUploadSize")
private Long fileUploadSize;
@JsonProperty("host_id")
private String hostId;
@ -64,6 +67,16 @@ public class AuthTokenRequest {
return this;
}
public Long getFileUploadSize() {
return fileUploadSize;
}
public AuthTokenRequest setFileUploadSize(Long fileUploadSize) {
this.fileUploadSize = fileUploadSize;
return this;
}
public String getHostId() {
return hostId;
}

View File

@ -38,7 +38,7 @@ public class DecryptedLicenseResponse {
private final Long fileUploads;
private final Instant activationTime;
private final String product;
private final String limitType;
private final LicenseLimitType limitType;
private final String timezone;
private final String customerEmail;
private final String customerName;
@ -54,7 +54,7 @@ public class DecryptedLicenseResponse {
@JsonDeserialize(using = InstantEpochMillisDeserializer.class)
@JsonProperty("activationTime") Instant activationTime,
@JsonProperty("product") String product,
@JsonProperty("limitType") String limitType,
@JsonProperty("limitType") LicenseLimitType limitType,
@JsonProperty("timezone") String timezone,
@JsonProperty("customerEmail") String customerEmail,
@JsonProperty("customerName") String customerName
@ -96,7 +96,7 @@ public class DecryptedLicenseResponse {
return product;
}
public String getLimitType() {
public LicenseLimitType getLimitType() {
return limitType;
}

View File

@ -0,0 +1,69 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2023 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 com.basistech.df.cybertriage.autopsy.ctapi.json;
import java.io.InputStream;
/**
* Data for a file upload request.
*/
public class FileUploadRequest {
private String fullUrlPath;
private String fileName;
private InputStream fileInputStream;
private Long contentLength;
public String getFullUrlPath() {
return fullUrlPath;
}
public FileUploadRequest setFullUrlPath(String fullUrlPath) {
this.fullUrlPath = fullUrlPath;
return this;
}
public String getFileName() {
return fileName;
}
public FileUploadRequest setFileName(String fileName) {
this.fileName = fileName;
return this;
}
public InputStream getFileInputStream() {
return fileInputStream;
}
public FileUploadRequest setFileInputStream(InputStream fileInputStream) {
this.fileInputStream = fileInputStream;
return this;
}
public Long getContentLength() {
return contentLength;
}
public FileUploadRequest setContentLength(Long contentLength) {
this.contentLength = contentLength;
return this;
}
}

View File

@ -0,0 +1,30 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2023 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 com.basistech.df.cybertriage.autopsy.ctapi.json;
/**
* The limit type (and reset) for the license.
*/
public enum LicenseLimitType {
HOURLY,
DAILY,
WEEKLY,
MONTHLY,
NO_RESET;
}

View File

@ -32,18 +32,21 @@ public class LicenseResponse {
private final Boolean hostChanged;
private final Long hostChangesRemaining;
private final BoostLicenseResponse boostLicense;
private final String errorMsg;
@JsonCreator
public LicenseResponse(
@JsonProperty("success") Boolean success,
@JsonProperty("hostChanged") Boolean hostChanged,
@JsonProperty("hostChangesRemaining") Long hostChangesRemaining,
@JsonProperty("boostLicense") BoostLicenseResponse boostLicense
@JsonProperty("boostLicense") BoostLicenseResponse boostLicense,
@JsonProperty("errorMsg") String errorMsg
) {
this.success = success;
this.hostChanged = hostChanged;
this.hostChangesRemaining = hostChangesRemaining;
this.boostLicense = boostLicense;
this.errorMsg = errorMsg;
}
public Boolean isSuccess() {
@ -61,4 +64,8 @@ public class LicenseResponse {
public BoostLicenseResponse getBoostLicense() {
return boostLicense;
}
public String getErrorMsg() {
return errorMsg;
}
}

View File

@ -0,0 +1,109 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2023 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 com.basistech.df.cybertriage.autopsy.ctapi.json;
import com.fasterxml.jackson.annotation.JsonProperty;
public class MetadataUploadRequest {
@JsonProperty("file_upload_url")
private String fileUploadUrl;
@JsonProperty("sha1")
private String sha1;
@JsonProperty("sha256")
private String sha256;
@JsonProperty("md5")
private String md5;
@JsonProperty("filePath")
private String filePath;
@JsonProperty("fileSize")
private Long fileSizeBytes;
@JsonProperty("createdDate")
private Long createdDate;
public String getFileUploadUrl() {
return fileUploadUrl;
}
public MetadataUploadRequest setFileUploadUrl(String fileUploadUrl) {
this.fileUploadUrl = fileUploadUrl;
return this;
}
public String getSha1() {
return sha1;
}
public MetadataUploadRequest setSha1(String sha1) {
this.sha1 = sha1;
return this;
}
public String getSha256() {
return sha256;
}
public MetadataUploadRequest setSha256(String sha256) {
this.sha256 = sha256;
return this;
}
public String getMd5() {
return md5;
}
public MetadataUploadRequest setMd5(String md5) {
this.md5 = md5;
return this;
}
public String getFilePath() {
return filePath;
}
public MetadataUploadRequest setFilePath(String filePath) {
this.filePath = filePath;
return this;
}
public Long getFileSizeBytes() {
return fileSizeBytes;
}
public MetadataUploadRequest setFileSizeBytes(Long fileSizeBytes) {
this.fileSizeBytes = fileSizeBytes;
return this;
}
public Long getCreatedDate() {
return createdDate;
}
public MetadataUploadRequest setCreatedDate(Long createdDate) {
this.createdDate = createdDate;
return this;
}
}

View File

@ -34,6 +34,7 @@ import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.text.MessageFormat;
import java.util.Base64;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
@ -42,6 +43,7 @@ import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.lang3.ObjectUtils;
/**
* Decrypts the payload of boost license.
@ -58,12 +60,12 @@ public class LicenseDecryptorUtil {
private LicenseDecryptorUtil() {
}
public LicenseInfo createLicenseInfo(LicenseResponse licenseResponse) throws JsonProcessingException, InvalidLicenseException {
if (licenseResponse == null || licenseResponse.getBoostLicense() == null) {
throw new InvalidLicenseException("License or boost license are null");
if (licenseResponse == null) {
throw new InvalidLicenseException("License is null");
}
DecryptedLicenseResponse decrypted = parseLicenseJSON(licenseResponse.getBoostLicense());
return new LicenseInfo(licenseResponse, decrypted);
}
@ -78,6 +80,9 @@ public class LicenseDecryptorUtil {
* com.basistech.df.cybertriage.autopsy.ctapi.util.LicenseDecryptorUtil.InvalidLicenseException
*/
public DecryptedLicenseResponse parseLicenseJSON(BoostLicenseResponse licenseResponse) throws JsonProcessingException, InvalidLicenseException {
if (licenseResponse == null) {
throw new InvalidLicenseException("Boost license is null");
}
String decryptedJsonResponse;
try {
@ -101,6 +106,12 @@ public class LicenseDecryptorUtil {
}
private String decryptLicenseString(String encryptedJson, String ivBase64, String encryptedKey, String version) throws IOException, GeneralSecurityException, InvalidLicenseException {
if (ObjectUtils.anyNull(encryptedJson, ivBase64, encryptedKey, version)) {
throw new InvalidLicenseException(MessageFormat.format(
"encryptedJson: {0}, iv: {1}, encryptedKey: {2}, version: {3} must all be non-null",
encryptedJson, ivBase64, encryptedKey, version));
}
if (!"1.0".equals(version)) {
throw new InvalidLicenseException("Unexpected file version: " + version);
}

View File

@ -3,7 +3,7 @@
# Click nbfs://nbhost/SystemFileSystem/Templates/Other/properties.properties to edit this template
OptionsCategory_Name_CyberTriage=Cyber Triage
OptionsCategory_Keywords_CyberTriage=Cyber Triage,Cyber,Triage
LicenseDisclaimerPanel.disclaimer.text=<html>The Cyber Triage Malware Scanner module uses 40+ malware scanning engines to identify if Windows executables are malicious. It requires a non-free license to use.</html>
LicenseDisclaimerPanel.disclaimer.text=<html>The Cyber Triage Malware Scanner module uses 40+ malware scanning engines to identify if Windows executables are malicious. It requires a paid subscription to use.</html>
LicenseDisclaimerPanel.purchaseFromLabel.text=You can purchase a license from
LicenseDisclaimerPanel.link.text=<html><span style="color: blue; text-decoration: underline">https://cybertriage.com/autopsy-checkout</span></html>
LicenseDisclaimerPanel.border.title=Disclaimer
LicenseDisclaimerPanel.trialLabel.text=You can try a free 7-day trial from

View File

@ -3,7 +3,7 @@
# Click nbfs://nbhost/SystemFileSystem/Templates/Other/properties.properties to edit this template
OptionsCategory_Name_CyberTriage=Cyber Triage
OptionsCategory_Keywords_CyberTriage=Cyber Triage,Cyber,Triage
LicenseDisclaimerPanel.disclaimer.text=<html>The Cyber Triage Malware Scanner module uses 40+ malware scanning engines to identify if Windows executables are malicious. It requires a non-free license to use.</html>
LicenseDisclaimerPanel.disclaimer.text=<html>The Cyber Triage Malware Scanner module uses 40+ malware scanning engines to identify if Windows executables are malicious. It requires a paid subscription to use.</html>
LicenseDisclaimerPanel.purchaseFromLabel.text=You can purchase a license from
LicenseDisclaimerPanel.link.text=<html><span style="color: blue; text-decoration: underline">https://cybertriage.com/autopsy-checkout</span></html>
LicenseDisclaimerPanel.border.title=Disclaimer
LicenseDisclaimerPanel.trialLabel.text=You can try a free 7-day trial from

View File

@ -26,12 +26,12 @@ import java.beans.PropertyChangeListener;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.swing.JPanel;
import org.netbeans.spi.options.OptionsPanelController;
import org.openide.util.Lookup;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSettingsPanel;
/**
@ -64,12 +64,12 @@ public class CTOptionsPanel extends IngestModuleGlobalSettingsPanel {
}
})
.filter(item -> item != null)
.sorted(Comparator.comparing(p -> p.getClass().getSimpleName().toUpperCase()))
.sorted(Comparator.comparing(p -> p.getClass().getSimpleName().toUpperCase()).reversed())
.collect(Collectors.toList());
addSubOptionsPanels(new LicenseDisclaimerPanel(), this.subPanels);
addSubOptionsPanels(this.subPanels);
}
private void addSubOptionsPanels(JPanel disclaimerPanel, List<CTOptionsSubPanel> subPanels) {
private void addSubOptionsPanels(List<CTOptionsSubPanel> subPanels) {
GridBagConstraints disclaimerConstraints = new GridBagConstraints();
disclaimerConstraints.gridx = 0;
disclaimerConstraints.gridy = 0;
@ -79,8 +79,6 @@ public class CTOptionsPanel extends IngestModuleGlobalSettingsPanel {
disclaimerConstraints.weighty = 0;
disclaimerConstraints.weightx = 0;
contentPane.add(disclaimerPanel, disclaimerConstraints);
for (int i = 0; i < subPanels.size(); i++) {
CTOptionsSubPanel subPanel = subPanels.get(i);

View File

@ -1,131 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2023 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 com.basistech.df.cybertriage.autopsy.ctoptions;
import org.sleuthkit.autopsy.coreutils.Desktop;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.logging.Level;
import org.sleuthkit.autopsy.coreutils.Logger;
/**
* Disclaimer for license and place to purchase CT license.
*/
public class LicenseDisclaimerPanel extends javax.swing.JPanel {
private static final Logger LOGGER = Logger.getLogger(LicenseDisclaimerPanel.class.getName());
private static final String CHECKOUT_PAGE_URL = "https://cybertriage.com/autopsy-checkout";
/**
* Creates new form LicenseDisclaimerPanel
*/
public LicenseDisclaimerPanel() {
initComponents();
}
/**
* 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 disclaimer = new javax.swing.JLabel();
javax.swing.JLabel purchaseFromLabel = new javax.swing.JLabel();
javax.swing.JLabel link = new javax.swing.JLabel();
javax.swing.JPanel spacer = new javax.swing.JPanel();
setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(LicenseDisclaimerPanel.class, "LicenseDisclaimerPanel.border.title"))); // NOI18N
setMaximumSize(new java.awt.Dimension(2147483647, 90));
setMinimumSize(new java.awt.Dimension(562, 90));
setPreferredSize(new java.awt.Dimension(400, 90));
setLayout(new java.awt.GridBagLayout());
org.openide.awt.Mnemonics.setLocalizedText(disclaimer, org.openide.util.NbBundle.getMessage(LicenseDisclaimerPanel.class, "LicenseDisclaimerPanel.disclaimer.text")); // NOI18N
disclaimer.setVerticalAlignment(javax.swing.SwingConstants.TOP);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.gridwidth = 2;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
add(disclaimer, gridBagConstraints);
org.openide.awt.Mnemonics.setLocalizedText(purchaseFromLabel, org.openide.util.NbBundle.getMessage(LicenseDisclaimerPanel.class, "LicenseDisclaimerPanel.purchaseFromLabel.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridy = 1;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.insets = new java.awt.Insets(0, 5, 5, 3);
add(purchaseFromLabel, gridBagConstraints);
org.openide.awt.Mnemonics.setLocalizedText(link, org.openide.util.NbBundle.getMessage(LicenseDisclaimerPanel.class, "LicenseDisclaimerPanel.link.text")); // NOI18N
link.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
link.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseClicked(java.awt.event.MouseEvent evt) {
linkMouseClicked(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridy = 1;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(0, 0, 5, 5);
add(link, gridBagConstraints);
javax.swing.GroupLayout spacerLayout = new javax.swing.GroupLayout(spacer);
spacer.setLayout(spacerLayout);
spacerLayout.setHorizontalGroup(
spacerLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 0, Short.MAX_VALUE)
);
spacerLayout.setVerticalGroup(
spacerLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 0, Short.MAX_VALUE)
);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 2;
gridBagConstraints.weighty = 1.0;
add(spacer, gridBagConstraints);
}// </editor-fold>//GEN-END:initComponents
private void linkMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_linkMouseClicked
if (Desktop.isDesktopSupported()) {
try {
Desktop.getDesktop().browse(new URI(CHECKOUT_PAGE_URL));
} catch (IOException | URISyntaxException e) {
LOGGER.log(Level.SEVERE, "Error opening link to: " + CHECKOUT_PAGE_URL, e);
}
} else {
LOGGER.log(Level.WARNING, "Desktop API is not supported. Link cannot be opened.");
}
}//GEN-LAST:event_linkMouseClicked
// Variables declaration - do not modify//GEN-BEGIN:variables
// End of variables declaration//GEN-END:variables
}

View File

@ -4,18 +4,16 @@
CTLicenseDialog.title=Add a License...
CTLicenseDialog.licenseNumberLabel.text=License Number:
CTLicenseDialog.licenseNumberTextField.text=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
CTLicenseDialog.licenseNumberTextField.text=
CTLicenseDialog.cancelButton.text=Cancel
CTLicenseDialog.okButton.text=Ok
CTLicenseDialog.warningLabel.text=
CTMalwareScannerOptionsPanel.hashLookupsRemainingLabel.text=
CTMalwareScannerOptionsPanel.licenseInfoMessageLabel.text=
CTMalwareScannerOptionsPanel.countersResetLabel.text=
CTMalwareScannerOptionsPanel.licenseInfoPanel.border.title=License Info
CTMalwareScannerOptionsPanel.maxFileUploadsLabel.text=
CTMalwareScannerOptionsPanel.maxHashLookupsLabel.text=
CTMalwareScannerOptionsPanel.malwareScansMessageLabel.text=
CTMalwareScannerOptionsPanel.malwareScansPanel.border.title=Malware Scans
CTMalwareScannerOptionsPanel.malwareScansPanel.border.title=Malware Scanner
CTMalwareScannerOptionsPanel.licenseInfoAddButton.text=Add License
CTMalwareScannerOptionsPanel.licenseInfoIdLabel.text=
CTMalwareScannerOptionsPanel.licenseInfoExpiresLabel.text=
@ -24,3 +22,7 @@ CTMalwareScannerOptionsPanel.licenseInfoUserLabel.text=
EULADialog.cancelButton.text=Cancel
EULADialog.acceptButton.text=Accept
EULADialog.title=Cyber Triage End User License Agreement
CTMalwareScannerOptionsPanel.licenseInfoMessageLabel.text=
CTMalwareScannerOptionsPanel.disclaimer.text=<html>The Cyber Triage Malware Scanner module uses 40+ malware scanning engines to identify if Windows executables are malicious. It requires a paid subscription to use.</html>
CTMalwareScannerOptionsPanel.purchaseFromLabel.text=For licensing information, visit
CTLicenseDialog.licenseNumberTextField.toolTipText=AUT-XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX

View File

@ -4,24 +4,26 @@
CTLicenseDialog.title=Add a License...
CTLicenseDialog.licenseNumberLabel.text=License Number:
CTLicenseDialog.licenseNumberTextField.text=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
CTLicenseDialog.licenseNumberTextField.text=
CTLicenseDialog.cancelButton.text=Cancel
CTLicenseDialog.okButton.text=Ok
CTLicenseDialog.warningLabel.text=
CTLicenseDialog_verifyInput_licenseNumberError=<html>Please verify license number format of 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX'</html>
CTLicenseDialog_verifyInput_licenseNumberError=<html>Please enter a license number</html>
CTMalwareScannerOptionsPanel.hashLookupsRemainingLabel.text=
CTMalwareScannerOptionsPanel.licenseInfoMessageLabel.text=
CTMalwareScannerOptionsPanel.countersResetLabel.text=
CTMalwareScannerOptionsPanel.licenseInfoPanel.border.title=License Info
CTMalwareScannerOptionsPanel.maxFileUploadsLabel.text=
CTMalwareScannerOptionsPanel.maxHashLookupsLabel.text=
CTMalwareScannerOptionsPanel.malwareScansMessageLabel.text=
CTMalwareScannerOptionsPanel.malwareScansPanel.border.title=Malware Scans
CTMalwareScannerOptionsPanel.malwareScansPanel.border.title=Malware Scanner
CTMalwareScannerOptionsPanel.licenseInfoAddButton.text=Add License
CTMalwareScannerOptionsPanel.licenseInfoIdLabel.text=
CTMalwareScannerOptionsPanel.licenseInfoExpiresLabel.text=
CTMalwareScannerOptionsPanel.fileUploadsRemainingLabel.text=
CTMalwareScannerOptionsPanel.licenseInfoUserLabel.text=
CTMalwareScannerOptionsPanel_getResetSuffix_daily=/day
CTMalwareScannerOptionsPanel_getResetSuffix_hourly=/hour
CTMalwareScannerOptionsPanel_getResetSuffix_monthly=/month
CTMalwareScannerOptionsPanel_getResetSuffix_weekly=/week
CTMalwareScannerOptionsPanel_licenseAddDialog_desc=License Number:
CTMalwareScannerOptionsPanel_licenseAddDialog_title=Add a License...
CTMalwareScannerOptionsPanel_licenseAddDialogEnteredErr_desc=The license number has already been entered
@ -29,6 +31,8 @@ CTMalwareScannerOptionsPanel_licenseAddDialogEnteredErr_title=License Number Alr
CTMalwareScannerOptionsPanel_licenseAddDialogPatternErr_desc=Please verify that license number is of format 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX'
CTMalwareScannerOptionsPanel_licenseAddDialogPatternErr_title=Invalid License Number
CTMalwareScannerOptionsPanel_LicenseFetcher_apiErr_title=Server Error
# {0} - licenseCode
CTMalwareScannerOptionsPanel_LicenseFetcher_defaultErrMsg_desc=Error activating boost license {0}
CTMalwareScannerOptionsPanel_LicenseFetcher_localErr_desc=A general error occurred while fetching license information. Please try again later.
CTMalwareScannerOptionsPanel_LicenseFetcher_localErr_title=General Error
# {0} - expiresDate
@ -45,9 +49,11 @@ CTMalwareScannerOptionsPanel_malwareScans_fileUploadsRemaining=File uploads rema
# {0} - hashLookupsRemaining
CTMalwareScannerOptionsPanel_malwareScans_hashLookupsRemaining=Hash lookups remaining: {0}
# {0} - maxDailyFileLookups
CTMalwareScannerOptionsPanel_malwareScans_maxDailyFileLookups=Max file uploads: {0}/day
# {1} - resetSuffix
CTMalwareScannerOptionsPanel_malwareScans_maxDailyFileLookups=Max file uploads: {0}{1}
# {0} - maxDailyLookups
CTMalwareScannerOptionsPanel_malwareScans_maxDailyHashLookups=Max Hash lookups: {0}/day
# {1} - resetSuffix
CTMalwareScannerOptionsPanel_malwareScans_maxDailyHashLookups=Max Hash lookups: {0}{1}
CTMalwareScannerOptionsPanel_MalwareScansFetcher_apiErr_title=Server Error
CTMalwareScannerOptionsPanel_MalwareScansFetcher_localErr_desc=A general error occurred while fetching malware scans information. Please try again later.
CTMalwareScannerOptionsPanel_MalwareScansFetcher_localErr_title=General Error
@ -56,3 +62,7 @@ CTOPtionsPanel_loadMalwareScansInfo_loading=Loading...
EULADialog.cancelButton.text=Cancel
EULADialog.acceptButton.text=Accept
EULADialog.title=Cyber Triage End User License Agreement
CTMalwareScannerOptionsPanel.licenseInfoMessageLabel.text=
CTMalwareScannerOptionsPanel.disclaimer.text=<html>The Cyber Triage Malware Scanner module uses 40+ malware scanning engines to identify if Windows executables are malicious. It requires a paid subscription to use.</html>
CTMalwareScannerOptionsPanel.purchaseFromLabel.text=For licensing information, visit
CTLicenseDialog.licenseNumberTextField.toolTipText=AUT-XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX

View File

@ -127,6 +127,9 @@
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/Bundle.properties" key="CTLicenseDialog.licenseNumberTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/Bundle.properties" key="CTLicenseDialog.licenseNumberTextField.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">

View File

@ -18,18 +18,20 @@
*/
package com.basistech.df.cybertriage.autopsy.ctoptions.ctcloud;
import java.awt.Color;
import java.util.regex.Pattern;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import org.apache.commons.lang3.StringUtils;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.corecomponents.TextPrompt;
/**
* License dialog
*/
public class CTLicenseDialog extends javax.swing.JDialog {
class CTLicenseDialog extends javax.swing.JDialog {
private static final Pattern LICENSE_PATTERN = Pattern.compile("^\\s*[a-zA-Z0-9\\-]+?\\s*$");
private static final Pattern LICENSE_PATTERN = Pattern.compile("^\\s*[a-zA-Z0-9-_]+?\\s*$");
private String licenseString = null;
/**
@ -38,6 +40,7 @@ public class CTLicenseDialog extends javax.swing.JDialog {
public CTLicenseDialog(java.awt.Frame parent, boolean modal) {
super(parent, modal);
initComponents();
configureHintText();
this.licenseNumberTextField.getDocument().putProperty("filterNewlines", Boolean.TRUE);
this.licenseNumberTextField.getDocument().addDocumentListener(new DocumentListener() {
@Override
@ -56,13 +59,23 @@ public class CTLicenseDialog extends javax.swing.JDialog {
}
});
}
private void configureHintText() {
TextPrompt textPrompt = new TextPrompt(
StringUtils.defaultString(this.licenseNumberTextField.getToolTipText()),
this.licenseNumberTextField);
textPrompt.setForeground(Color.LIGHT_GRAY);
float alpha = 0.9f; // Mostly opaque
textPrompt.changeAlpha(alpha);
}
String getValue() {
return licenseString;
}
@Messages({
"CTLicenseDialog_verifyInput_licenseNumberError=<html>Please verify license number format of 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX'</html>"
"CTLicenseDialog_verifyInput_licenseNumberError=<html>Please enter a license number</html>"
})
private void verifyInput() {
String licenseInput = StringUtils.defaultString(this.licenseNumberTextField.getText());
@ -165,6 +178,7 @@ public class CTLicenseDialog extends javax.swing.JDialog {
getContentPane().add(cancelButton, gridBagConstraints);
licenseNumberTextField.setText(org.openide.util.NbBundle.getMessage(CTLicenseDialog.class, "CTLicenseDialog.licenseNumberTextField.text")); // NOI18N
licenseNumberTextField.setToolTipText(org.openide.util.NbBundle.getMessage(CTLicenseDialog.class, "CTLicenseDialog.licenseNumberTextField.toolTipText")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
@ -177,7 +191,8 @@ public class CTLicenseDialog extends javax.swing.JDialog {
}// </editor-fold>//GEN-END:initComponents
private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed
this.licenseString = this.licenseNumberTextField.getText();
String inputText = this.licenseNumberTextField.getText();
this.licenseString = inputText == null ? null : inputText.trim();
this.dispose();
}//GEN-LAST:event_okButtonActionPerformed

View File

@ -26,7 +26,6 @@ import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Optional;
import java.util.logging.Level;
@ -40,6 +39,7 @@ public class CTLicensePersistence {
private static final String CT_SETTINGS_DIR = "CyberTriage";
private static final String CT_LICENSE_FILENAME = "CyberTriageLicense.json";
private static final String MALWARE_INGEST_SETTINGS_FILENAME = "MalwareIngestSettings.json";
private static final Logger logger = Logger.getLogger(CTLicensePersistence.class.getName());
@ -94,4 +94,8 @@ public class CTLicensePersistence {
private File getCTLicenseFile() {
return Paths.get(PlatformUtil.getModuleConfigDirectory(), CT_SETTINGS_DIR, CT_LICENSE_FILENAME).toFile();
}
private File getMalwareIngestFile() {
return Paths.get(PlatformUtil.getModuleConfigDirectory(), CT_SETTINGS_DIR, MALWARE_INGEST_SETTINGS_FILENAME).toFile();
}
}

View File

@ -11,103 +11,16 @@
<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,0,-109,0,0,1,-29"/>
<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,1,90,0,0,1,-29"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
<SubComponents>
<Container class="javax.swing.JPanel" name="licenseInfoPanel">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
<TitledBorder title="License Info">
<ResourceString PropertyName="titleX" bundle="com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/Bundle.properties" key="CTMalwareScannerOptionsPanel.licenseInfoPanel.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</TitledBorder>
</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="0" gridY="1" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="18" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
<SubComponents>
<Component class="javax.swing.JLabel" name="licenseInfoMessageLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/Bundle.properties" key="CTMalwareScannerOptionsPanel.licenseInfoMessageLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</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="0" gridWidth="2" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="5" insetsLeft="5" insetsBottom="5" insetsRight="5" anchor="18" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JLabel" name="licenseInfoUserLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/Bundle.properties" key="CTMalwareScannerOptionsPanel.licenseInfoUserLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</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="1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="5" insetsLeft="5" insetsBottom="5" insetsRight="5" anchor="18" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JLabel" name="licenseInfoExpiresLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/Bundle.properties" key="CTMalwareScannerOptionsPanel.licenseInfoExpiresLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<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="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="5" insetsLeft="5" insetsBottom="5" insetsRight="5" anchor="18" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JLabel" name="licenseInfoIdLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/Bundle.properties" key="CTMalwareScannerOptionsPanel.licenseInfoIdLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</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="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="5" insetsBottom="5" insetsRight="5" anchor="18" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JButton" name="licenseInfoAddButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/Bundle.properties" key="CTMalwareScannerOptionsPanel.licenseInfoAddButton.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="licenseInfoAddButtonActionPerformed"/>
</Events>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="1" gridY="2" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="5" insetsBottom="5" insetsRight="5" anchor="12" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="malwareScansPanel">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
<TitledBorder title="Malware Scans">
<TitledBorder title="Malware Scanner">
<ResourceString PropertyName="titleX" bundle="com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/Bundle.properties" key="CTMalwareScannerOptionsPanel.malwareScansPanel.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</TitledBorder>
</Border>
@ -121,78 +34,221 @@
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
<SubComponents>
<Component class="javax.swing.JLabel" name="malwareScansMessageLabel">
<Component class="javax.swing.JLabel" name="disclaimer">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/Bundle.properties" key="CTMalwareScannerOptionsPanel.malwareScansMessageLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/Bundle.properties" key="CTMalwareScannerOptionsPanel.disclaimer.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="verticalAlignment" type="int" value="1"/>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="0" gridWidth="2" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="5" insetsLeft="5" insetsBottom="5" insetsRight="5" anchor="18" weightX="1.0" weightY="0.0"/>
<GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="5" insetsLeft="5" insetsBottom="5" insetsRight="5" anchor="18" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JLabel" name="maxHashLookupsLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/Bundle.properties" key="CTMalwareScannerOptionsPanel.maxHashLookupsLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Container class="javax.swing.JPanel" name="licenseInfoPanel">
<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="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="5" insetsLeft="5" insetsBottom="5" insetsRight="5" anchor="18" weightX="1.0" weightY="0.0"/>
<GridBagConstraints gridX="0" gridY="1" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="18" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JLabel" name="maxFileUploadsLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/Bundle.properties" key="CTMalwareScannerOptionsPanel.maxFileUploadsLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
<SubComponents>
<Component class="javax.swing.JLabel" name="licenseInfoMessageLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/Bundle.properties" key="CTMalwareScannerOptionsPanel.licenseInfoMessageLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</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="0" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="5" insetsLeft="5" insetsBottom="5" insetsRight="5" anchor="18" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JLabel" name="licenseInfoExpiresLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/Bundle.properties" key="CTMalwareScannerOptionsPanel.licenseInfoExpiresLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</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="1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="5" insetsLeft="5" insetsBottom="5" insetsRight="5" anchor="18" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JLabel" name="licenseInfoIdLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/Bundle.properties" key="CTMalwareScannerOptionsPanel.licenseInfoIdLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<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="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="5" insetsLeft="5" insetsBottom="5" insetsRight="5" anchor="18" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JLabel" name="licenseInfoUserLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/Bundle.properties" key="CTMalwareScannerOptionsPanel.licenseInfoUserLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</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="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="5" insetsLeft="5" insetsBottom="5" insetsRight="5" anchor="18" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JButton" name="licenseInfoAddButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/Bundle.properties" key="CTMalwareScannerOptionsPanel.licenseInfoAddButton.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="licenseInfoAddButtonActionPerformed"/>
</Events>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="2" gridY="2" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="5" insetsBottom="5" insetsRight="5" anchor="12" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JLabel" name="maxFileUploadsLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/Bundle.properties" key="CTMalwareScannerOptionsPanel.maxFileUploadsLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</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="4" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="5" insetsBottom="5" insetsRight="5" anchor="18" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JLabel" name="maxHashLookupsLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/Bundle.properties" key="CTMalwareScannerOptionsPanel.maxHashLookupsLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</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="3" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="5" insetsLeft="5" insetsBottom="5" insetsRight="5" anchor="18" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JLabel" name="hashLookupsRemainingLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/Bundle.properties" key="CTMalwareScannerOptionsPanel.hashLookupsRemainingLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<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="5" insetsLeft="5" insetsBottom="5" insetsRight="5" anchor="18" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JLabel" name="malwareScansMessageLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/Bundle.properties" key="CTMalwareScannerOptionsPanel.malwareScansMessageLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</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="3" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="5" insetsLeft="5" insetsBottom="5" insetsRight="5" anchor="18" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JLabel" name="countersResetLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/Bundle.properties" key="CTMalwareScannerOptionsPanel.countersResetLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</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="5" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="5" insetsBottom="5" insetsRight="5" anchor="18" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JLabel" name="fileUploadsRemainingLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/Bundle.properties" key="CTMalwareScannerOptionsPanel.fileUploadsRemainingLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<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="5" insetsBottom="5" insetsRight="5" anchor="18" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="purchasePanel">
<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="2" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="5" insetsBottom="5" insetsRight="5" anchor="18" weightX="1.0" weightY="0.0"/>
<GridBagConstraints gridX="0" gridY="3" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="5" insetsBottom="5" insetsRight="5" anchor="18" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JLabel" name="countersResetLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/Bundle.properties" key="CTMalwareScannerOptionsPanel.countersResetLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</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="3" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="5" insetsBottom="5" insetsRight="5" anchor="18" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JLabel" name="hashLookupsRemainingLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/Bundle.properties" key="CTMalwareScannerOptionsPanel.hashLookupsRemainingLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<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="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="5" insetsLeft="5" insetsBottom="5" insetsRight="5" anchor="18" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JLabel" name="fileUploadsRemainingLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/Bundle.properties" key="CTMalwareScannerOptionsPanel.fileUploadsRemainingLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="1" gridY="2" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="5" insetsBottom="5" insetsRight="5" anchor="18" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
<SubComponents>
<Component class="javax.swing.JLabel" name="purchaseFromLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/Bundle.properties" key="CTMalwareScannerOptionsPanel.purchaseFromLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</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="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="18" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JLabel" name="purchaseLink">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="getHtmlLink(PURCHASE_URL)" type="code"/>
</Property>
<Property name="cursor" type="java.awt.Cursor" editor="org.netbeans.modules.form.editors2.CursorEditor">
<Color id="Hand Cursor"/>
</Property>
</Properties>
<Events>
<EventHandler event="mouseClicked" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="purchaseLinkMouseClicked"/>
</Events>
<AuxValues>
<AuxValue name="generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="1" gridY="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="3" insetsBottom="0" insetsRight="0" anchor="18" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Container>
</SubComponents>

View File

@ -24,18 +24,22 @@ import com.basistech.df.cybertriage.autopsy.ctapi.CTApiDAO;
import com.basistech.df.cybertriage.autopsy.ctapi.json.AuthTokenResponse;
import com.basistech.df.cybertriage.autopsy.ctapi.json.DecryptedLicenseResponse;
import com.basistech.df.cybertriage.autopsy.ctapi.json.LicenseInfo;
import com.basistech.df.cybertriage.autopsy.ctapi.json.LicenseLimitType;
import com.basistech.df.cybertriage.autopsy.ctapi.json.LicenseResponse;
import com.basistech.df.cybertriage.autopsy.ctapi.util.LicenseDecryptorUtil;
import com.basistech.df.cybertriage.autopsy.ctapi.util.LicenseDecryptorUtil.InvalidLicenseException;
import java.awt.Desktop;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Optional;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
@ -46,6 +50,7 @@ import org.openide.util.NbBundle.Messages;
import org.openide.util.lookup.ServiceProvider;
import org.openide.windows.WindowManager;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.coreutils.Logger;
/**
* Options panel to be displayed in the CTOptionsPanel for settings regarding
@ -71,6 +76,8 @@ public class CTMalwareScannerOptionsPanel extends CTOptionsSubPanel {
private volatile String licenseInfoMessage = null;
private volatile LicenseFetcher licenseFetcher = null;
private static final String PURCHASE_URL = "https://cybertriage.com/autopsy-malware-module";
private volatile AuthTokenResponse authTokenResponse = null;
private volatile String authTokenMessage = null;
private volatile AuthTokenFetcher authTokenFetcher = null;
@ -127,12 +134,33 @@ public class CTMalwareScannerOptionsPanel extends CTOptionsSubPanel {
setMalwareScansDisplay(null, null);
if (licenseInfo != null) {
loadMalwareScansInfo(licenseInfo);
this.purchaseFromLabel.setVisible(false);
this.purchaseLink.setVisible(false);
} else {
this.purchaseFromLabel.setVisible(true);
this.purchaseLink.setVisible(true);
}
}
private static String getHtmlLink(String url) {
return "<html><span style=\"color: blue; text-decoration: underline\">" + url + "</span></html>";
}
private void gotoLink(String url) {
if (Desktop.isDesktopSupported()) {
try {
Desktop.getDesktop().browse(new URI(url));
} catch (IOException | URISyntaxException e) {
logger.log(Level.SEVERE, "Error opening link to: " + url, e);
}
} else {
logger.log(Level.WARNING, "Desktop API is not supported. Link cannot be opened.");
}
}
private synchronized LicenseResponse getLicenseInfo() {
return this.licenseInfo == null ? null : this.licenseInfo.getLicenseResponse();
}
}
private synchronized void setLicenseDisplay(LicenseInfo licenseInfo, String licenseMessage) {
this.licenseInfo = licenseInfo;
@ -202,48 +230,55 @@ public class CTMalwareScannerOptionsPanel extends CTOptionsSubPanel {
private void initComponents() {
java.awt.GridBagConstraints gridBagConstraints;
malwareScansPanel = new javax.swing.JPanel();
javax.swing.JLabel disclaimer = new javax.swing.JLabel();
javax.swing.JPanel licenseInfoPanel = new javax.swing.JPanel();
licenseInfoMessageLabel = new javax.swing.JLabel();
licenseInfoUserLabel = new javax.swing.JLabel();
licenseInfoExpiresLabel = new javax.swing.JLabel();
licenseInfoIdLabel = new javax.swing.JLabel();
licenseInfoUserLabel = new javax.swing.JLabel();
licenseInfoAddButton = new javax.swing.JButton();
malwareScansPanel = new javax.swing.JPanel();
malwareScansMessageLabel = new javax.swing.JLabel();
maxHashLookupsLabel = new javax.swing.JLabel();
maxFileUploadsLabel = new javax.swing.JLabel();
countersResetLabel = new javax.swing.JLabel();
maxHashLookupsLabel = new javax.swing.JLabel();
hashLookupsRemainingLabel = new javax.swing.JLabel();
malwareScansMessageLabel = new javax.swing.JLabel();
countersResetLabel = new javax.swing.JLabel();
fileUploadsRemainingLabel = new javax.swing.JLabel();
javax.swing.JPanel purchasePanel = new javax.swing.JPanel();
purchaseFromLabel = new javax.swing.JLabel();
purchaseLink = new javax.swing.JLabel();
setLayout(new java.awt.GridBagLayout());
licenseInfoPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(CTMalwareScannerOptionsPanel.class, "CTMalwareScannerOptionsPanel.licenseInfoPanel.border.title"))); // NOI18N
malwareScansPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(CTMalwareScannerOptionsPanel.class, "CTMalwareScannerOptionsPanel.malwareScansPanel.border.title"))); // NOI18N
malwareScansPanel.setLayout(new java.awt.GridBagLayout());
org.openide.awt.Mnemonics.setLocalizedText(disclaimer, org.openide.util.NbBundle.getMessage(CTMalwareScannerOptionsPanel.class, "CTMalwareScannerOptionsPanel.disclaimer.text")); // NOI18N
disclaimer.setVerticalAlignment(javax.swing.SwingConstants.TOP);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
malwareScansPanel.add(disclaimer, gridBagConstraints);
licenseInfoPanel.setLayout(new java.awt.GridBagLayout());
org.openide.awt.Mnemonics.setLocalizedText(licenseInfoMessageLabel, org.openide.util.NbBundle.getMessage(CTMalwareScannerOptionsPanel.class, "CTMalwareScannerOptionsPanel.licenseInfoMessageLabel.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.gridwidth = 2;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
licenseInfoPanel.add(licenseInfoMessageLabel, gridBagConstraints);
org.openide.awt.Mnemonics.setLocalizedText(licenseInfoUserLabel, org.openide.util.NbBundle.getMessage(CTMalwareScannerOptionsPanel.class, "CTMalwareScannerOptionsPanel.licenseInfoUserLabel.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
licenseInfoPanel.add(licenseInfoUserLabel, gridBagConstraints);
org.openide.awt.Mnemonics.setLocalizedText(licenseInfoExpiresLabel, org.openide.util.NbBundle.getMessage(CTMalwareScannerOptionsPanel.class, "CTMalwareScannerOptionsPanel.licenseInfoExpiresLabel.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
@ -252,12 +287,21 @@ public class CTMalwareScannerOptionsPanel extends CTOptionsSubPanel {
org.openide.awt.Mnemonics.setLocalizedText(licenseInfoIdLabel, org.openide.util.NbBundle.getMessage(CTMalwareScannerOptionsPanel.class, "CTMalwareScannerOptionsPanel.licenseInfoIdLabel.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 1;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
licenseInfoPanel.add(licenseInfoIdLabel, gridBagConstraints);
org.openide.awt.Mnemonics.setLocalizedText(licenseInfoUserLabel, org.openide.util.NbBundle.getMessage(CTMalwareScannerOptionsPanel.class, "CTMalwareScannerOptionsPanel.licenseInfoUserLabel.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 2;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(0, 5, 5, 5);
licenseInfoPanel.add(licenseInfoIdLabel, gridBagConstraints);
gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
licenseInfoPanel.add(licenseInfoUserLabel, gridBagConstraints);
org.openide.awt.Mnemonics.setLocalizedText(licenseInfoAddButton, org.openide.util.NbBundle.getMessage(CTMalwareScannerOptionsPanel.class, "CTMalwareScannerOptionsPanel.licenseInfoAddButton.text")); // NOI18N
licenseInfoAddButton.addActionListener(new java.awt.event.ActionListener() {
@ -266,79 +310,108 @@ public class CTMalwareScannerOptionsPanel extends CTOptionsSubPanel {
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridx = 2;
gridBagConstraints.gridy = 2;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHEAST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(0, 5, 5, 5);
licenseInfoPanel.add(licenseInfoAddButton, gridBagConstraints);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
add(licenseInfoPanel, gridBagConstraints);
malwareScansPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(CTMalwareScannerOptionsPanel.class, "CTMalwareScannerOptionsPanel.malwareScansPanel.border.title"))); // NOI18N
malwareScansPanel.setLayout(new java.awt.GridBagLayout());
org.openide.awt.Mnemonics.setLocalizedText(malwareScansMessageLabel, org.openide.util.NbBundle.getMessage(CTMalwareScannerOptionsPanel.class, "CTMalwareScannerOptionsPanel.malwareScansMessageLabel.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.gridwidth = 2;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
malwareScansPanel.add(malwareScansMessageLabel, gridBagConstraints);
org.openide.awt.Mnemonics.setLocalizedText(maxHashLookupsLabel, org.openide.util.NbBundle.getMessage(CTMalwareScannerOptionsPanel.class, "CTMalwareScannerOptionsPanel.maxHashLookupsLabel.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
malwareScansPanel.add(maxHashLookupsLabel, gridBagConstraints);
org.openide.awt.Mnemonics.setLocalizedText(maxFileUploadsLabel, org.openide.util.NbBundle.getMessage(CTMalwareScannerOptionsPanel.class, "CTMalwareScannerOptionsPanel.maxFileUploadsLabel.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 2;
gridBagConstraints.gridy = 4;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(0, 5, 5, 5);
malwareScansPanel.add(maxFileUploadsLabel, gridBagConstraints);
licenseInfoPanel.add(maxFileUploadsLabel, gridBagConstraints);
org.openide.awt.Mnemonics.setLocalizedText(countersResetLabel, org.openide.util.NbBundle.getMessage(CTMalwareScannerOptionsPanel.class, "CTMalwareScannerOptionsPanel.countersResetLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(maxHashLookupsLabel, org.openide.util.NbBundle.getMessage(CTMalwareScannerOptionsPanel.class, "CTMalwareScannerOptionsPanel.maxHashLookupsLabel.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 3;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(0, 5, 5, 5);
malwareScansPanel.add(countersResetLabel, gridBagConstraints);
gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
licenseInfoPanel.add(maxHashLookupsLabel, gridBagConstraints);
org.openide.awt.Mnemonics.setLocalizedText(hashLookupsRemainingLabel, org.openide.util.NbBundle.getMessage(CTMalwareScannerOptionsPanel.class, "CTMalwareScannerOptionsPanel.hashLookupsRemainingLabel.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 1;
gridBagConstraints.gridy = 3;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
malwareScansPanel.add(hashLookupsRemainingLabel, gridBagConstraints);
licenseInfoPanel.add(hashLookupsRemainingLabel, gridBagConstraints);
org.openide.awt.Mnemonics.setLocalizedText(malwareScansMessageLabel, org.openide.util.NbBundle.getMessage(CTMalwareScannerOptionsPanel.class, "CTMalwareScannerOptionsPanel.malwareScansMessageLabel.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 3;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
licenseInfoPanel.add(malwareScansMessageLabel, gridBagConstraints);
org.openide.awt.Mnemonics.setLocalizedText(countersResetLabel, org.openide.util.NbBundle.getMessage(CTMalwareScannerOptionsPanel.class, "CTMalwareScannerOptionsPanel.countersResetLabel.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 5;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(0, 5, 5, 5);
licenseInfoPanel.add(countersResetLabel, gridBagConstraints);
org.openide.awt.Mnemonics.setLocalizedText(fileUploadsRemainingLabel, org.openide.util.NbBundle.getMessage(CTMalwareScannerOptionsPanel.class, "CTMalwareScannerOptionsPanel.fileUploadsRemainingLabel.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 2;
gridBagConstraints.gridy = 4;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(0, 5, 5, 5);
malwareScansPanel.add(fileUploadsRemainingLabel, gridBagConstraints);
licenseInfoPanel.add(fileUploadsRemainingLabel, gridBagConstraints);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
malwareScansPanel.add(licenseInfoPanel, gridBagConstraints);
purchasePanel.setLayout(new java.awt.GridBagLayout());
org.openide.awt.Mnemonics.setLocalizedText(purchaseFromLabel, org.openide.util.NbBundle.getMessage(CTMalwareScannerOptionsPanel.class, "CTMalwareScannerOptionsPanel.purchaseFromLabel.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
purchasePanel.add(purchaseFromLabel, gridBagConstraints);
org.openide.awt.Mnemonics.setLocalizedText(purchaseLink, getHtmlLink(PURCHASE_URL));
purchaseLink.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
purchaseLink.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseClicked(java.awt.event.MouseEvent evt) {
purchaseLinkMouseClicked(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 0;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(0, 3, 0, 0);
purchasePanel.add(purchaseLink, gridBagConstraints);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 3;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(0, 5, 5, 5);
malwareScansPanel.add(purchasePanel, gridBagConstraints);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
@ -378,6 +451,10 @@ public class CTMalwareScannerOptionsPanel extends CTOptionsSubPanel {
}
}//GEN-LAST:event_licenseInfoAddButtonActionPerformed
private void purchaseLinkMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_purchaseLinkMouseClicked
gotoLink(PURCHASE_URL);
}//GEN-LAST:event_purchaseLinkMouseClicked
@NbBundle.Messages({
"# {0} - userName",
"# {1} - email",
@ -387,9 +464,11 @@ public class CTMalwareScannerOptionsPanel extends CTOptionsSubPanel {
"# {0} - idNumber",
"CTMalwareScannerOptionsPanel_licenseInfo_id=ID: {0}",
"# {0} - maxDailyLookups",
"CTMalwareScannerOptionsPanel_malwareScans_maxDailyHashLookups=Max Hash lookups: {0}/day",
"# {1} - resetSuffix",
"CTMalwareScannerOptionsPanel_malwareScans_maxDailyHashLookups=Max Hash lookups: {0}{1}",
"# {0} - maxDailyFileLookups",
"CTMalwareScannerOptionsPanel_malwareScans_maxDailyFileLookups=Max file uploads: {0}/day",
"# {1} - resetSuffix",
"CTMalwareScannerOptionsPanel_malwareScans_maxDailyFileLookups=Max file uploads: {0}{1}",
"# {0} - countersResetDate",
"CTMalwareScannerOptionsPanel_malwareScans_countersReset=Counters reset: {0}",
"# {0} - hashLookupsRemaining",
@ -406,7 +485,12 @@ public class CTMalwareScannerOptionsPanel extends CTOptionsSubPanel {
this.licenseInfoExpiresLabel.setVisible(false);
this.licenseInfoIdLabel.setVisible(false);
this.licenseInfoUserLabel.setVisible(false);
this.purchaseFromLabel.setVisible(true);
this.purchaseLink.setVisible(true);
} else {
this.purchaseFromLabel.setVisible(false);
this.purchaseLink.setVisible(false);
this.licenseInfoExpiresLabel.setVisible(true);
this.licenseInfoExpiresLabel.setText(Bundle.CTMalwareScannerOptionsPanel_licenseInfo_expires(
this.licenseInfo.getDecryptedLicense().getExpirationDate() == null
@ -420,12 +504,10 @@ public class CTMalwareScannerOptionsPanel extends CTOptionsSubPanel {
StringUtils.defaultString(this.licenseInfo.getDecryptedLicense().getCustomerEmail())));
}
this.malwareScansPanel.setVisible(StringUtils.isNotBlank(this.authTokenMessage) || authTokenResponse != null);
this.malwareScansMessageLabel.setVisible(StringUtils.isNotBlank(this.authTokenMessage));
this.malwareScansMessageLabel.setText(this.authTokenMessage);
if (authTokenResponse == null) {
if (authTokenResponse == null || this.licenseInfo == null) {
this.maxHashLookupsLabel.setVisible(false);
this.maxFileUploadsLabel.setVisible(false);
this.countersResetLabel.setVisible(false);
@ -433,15 +515,62 @@ public class CTMalwareScannerOptionsPanel extends CTOptionsSubPanel {
this.fileUploadsRemainingLabel.setVisible(false);
} else {
this.maxHashLookupsLabel.setVisible(true);
this.maxHashLookupsLabel.setText(Bundle.CTMalwareScannerOptionsPanel_malwareScans_maxDailyHashLookups(this.authTokenResponse.getHashLookupLimit()));
this.maxHashLookupsLabel.setText(Bundle.CTMalwareScannerOptionsPanel_malwareScans_maxDailyHashLookups(
this.authTokenResponse.getHashLookupLimit(),
getResetSuffix(this.licenseInfo.getDecryptedLicense().getLimitType())));
this.maxFileUploadsLabel.setVisible(true);
this.maxFileUploadsLabel.setText(Bundle.CTMalwareScannerOptionsPanel_malwareScans_maxDailyFileLookups(this.authTokenResponse.getFileUploadLimit()));
this.maxFileUploadsLabel.setText(Bundle.CTMalwareScannerOptionsPanel_malwareScans_maxDailyFileLookups(
this.authTokenResponse.getFileUploadLimit(),
getResetSuffix(this.licenseInfo.getDecryptedLicense().getLimitType())));
this.countersResetLabel.setVisible(true);
this.countersResetLabel.setText(Bundle.CTMalwareScannerOptionsPanel_malwareScans_countersReset(this.authTokenResponse.getResetDate() == null ? "" : MALWARE_SCANS_RESET_FORMAT.format(this.authTokenResponse.getResetDate())));
this.countersResetLabel.setText(getCountersResetText(this.licenseInfo.getDecryptedLicense().getLimitType(), this.authTokenResponse));
this.hashLookupsRemainingLabel.setVisible(true);
this.hashLookupsRemainingLabel.setText(Bundle.CTMalwareScannerOptionsPanel_malwareScans_hashLookupsRemaining(remaining(this.authTokenResponse.getHashLookupLimit(), this.authTokenResponse.getHashLookupCount())));
this.hashLookupsRemainingLabel.setText(
Bundle.CTMalwareScannerOptionsPanel_malwareScans_hashLookupsRemaining(
remaining(this.authTokenResponse.getHashLookupLimit(), this.authTokenResponse.getHashLookupCount())));
this.fileUploadsRemainingLabel.setVisible(true);
this.fileUploadsRemainingLabel.setText(Bundle.CTMalwareScannerOptionsPanel_malwareScans_fileUploadsRemaining(remaining(this.authTokenResponse.getFileUploadLimit(), this.authTokenResponse.getFileUploadCount())));
this.fileUploadsRemainingLabel.setText(
Bundle.CTMalwareScannerOptionsPanel_malwareScans_fileUploadsRemaining(
remaining(this.authTokenResponse.getFileUploadLimit(), this.authTokenResponse.getFileUploadCount())));
}
}
private static String getCountersResetText(LicenseLimitType limitType, AuthTokenResponse authTokenResponse) {
if (limitType == null || limitType == LicenseLimitType.NO_RESET) {
return "";
} else {
return Bundle.CTMalwareScannerOptionsPanel_malwareScans_countersReset(
MALWARE_SCANS_RESET_FORMAT.format(authTokenResponse.getResetDate()));
}
}
@Messages({
"CTMalwareScannerOptionsPanel_getResetSuffix_hourly=/hour",
"CTMalwareScannerOptionsPanel_getResetSuffix_daily=/day",
"CTMalwareScannerOptionsPanel_getResetSuffix_weekly=/week",
"CTMalwareScannerOptionsPanel_getResetSuffix_monthly=/month"
})
private String getResetSuffix(LicenseLimitType limitType) {
if (limitType == null) {
return "";
}
switch (limitType) {
case HOURLY:
return Bundle.CTMalwareScannerOptionsPanel_getResetSuffix_hourly();
case DAILY:
return Bundle.CTMalwareScannerOptionsPanel_getResetSuffix_daily();
case WEEKLY:
return Bundle.CTMalwareScannerOptionsPanel_getResetSuffix_weekly();
case MONTHLY:
return Bundle.CTMalwareScannerOptionsPanel_getResetSuffix_monthly();
case NO_RESET:
default:
return "";
}
}
@ -479,6 +608,8 @@ public class CTMalwareScannerOptionsPanel extends CTOptionsSubPanel {
@NbBundle.Messages({
"CTMalwareScannerOptionsPanel_LicenseFetcher_apiErr_title=Server Error",
"CTMalwareScannerOptionsPanel_LicenseFetcher_localErr_title=General Error",
"# {0} - licenseCode",
"CTMalwareScannerOptionsPanel_LicenseFetcher_defaultErrMsg_desc=Error activating boost license {0}",
"CTMalwareScannerOptionsPanel_LicenseFetcher_localErr_desc=A general error occurred while fetching license information. Please try again later.",})
private class LicenseFetcher extends SwingWorker<LicenseResponse, Void> {
@ -500,8 +631,41 @@ public class CTMalwareScannerOptionsPanel extends CTOptionsSubPanel {
protected void done() {
try {
LicenseResponse licenseResponse = get();
// if no result, show unauthorized
if (licenseResponse == null) {
logger.log(Level.WARNING, "An API error occurred while fetching license information. License fetch returned no result.");
JOptionPane.showMessageDialog(
CTMalwareScannerOptionsPanel.this,
CTCloudException.ErrorCode.UN_AUTHORIZED.getDescription(),
Bundle.CTMalwareScannerOptionsPanel_LicenseFetcher_apiErr_title(),
JOptionPane.ERROR_MESSAGE);
setLicenseDisplay(licenseInfo, null);
loadMalwareScansInfo(licenseInfo);
return;
}
// if not successful response
if (!Boolean.TRUE.equals(licenseResponse.isSuccess())) {
logger.log(Level.WARNING, "An API error occurred while fetching license information. License fetch was not successful");
// use default message unless error message specified
String message = Bundle.CTMalwareScannerOptionsPanel_LicenseFetcher_defaultErrMsg_desc(licenseText);
if (!StringUtils.isBlank(licenseResponse.getErrorMsg())) {
message = licenseResponse.getErrorMsg();
}
JOptionPane.showMessageDialog(
CTMalwareScannerOptionsPanel.this,
message,
Bundle.CTMalwareScannerOptionsPanel_LicenseFetcher_apiErr_title(),
JOptionPane.ERROR_MESSAGE);
setLicenseDisplay(licenseInfo, null);
loadMalwareScansInfo(licenseInfo);
return;
}
// otherwise, load
SwingUtilities.invokeLater(() -> acceptEula(licenseResponse));
} catch (InterruptedException ex) {
} catch (InterruptedException | CancellationException ex) {
// ignore cancellation; just load current license
setLicenseDisplay(licenseInfo, null);
loadMalwareScansInfo(licenseInfo);
@ -548,8 +712,8 @@ public class CTMalwareScannerOptionsPanel extends CTOptionsSubPanel {
if (this.isCancelled()) {
return null;
}
return ctApiDAO.getAuthToken(decryptedLicense);
return ctApiDAO.getAuthToken(decryptedLicense);
}
@Override
@ -557,7 +721,7 @@ public class CTMalwareScannerOptionsPanel extends CTOptionsSubPanel {
AuthTokenResponse authTokenResponse = null;
try {
authTokenResponse = get();
} catch (InterruptedException ex) {
} catch (InterruptedException | CancellationException ex) {
// ignore cancellation
} catch (ExecutionException ex) {
if (ex.getCause() != null && ex.getCause() instanceof CTCloudException cloudEx) {
@ -600,5 +764,7 @@ public class CTMalwareScannerOptionsPanel extends CTOptionsSubPanel {
private javax.swing.JPanel malwareScansPanel;
private javax.swing.JLabel maxFileUploadsLabel;
private javax.swing.JLabel maxHashLookupsLabel;
private javax.swing.JLabel purchaseFromLabel;
private javax.swing.JLabel purchaseLink;
// End of variables declaration//GEN-END:variables
}

View File

@ -36,7 +36,7 @@ import org.sleuthkit.autopsy.coreutils.Logger;
/**
* Dialog for displaying the Cyber Triage EULA before the license is saved.
*/
public class EULADialog extends javax.swing.JDialog {
class EULADialog extends javax.swing.JDialog {
private static final Logger LOGGER = Logger.getLogger(EULADialog.class.getName());
private static final String EULA_RESOURCE = "EULA.htm";

View File

@ -0,0 +1,16 @@
# Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
# Click nbfs://nbhost/SystemFileSystem/Templates/Other/properties.properties to edit this template
CTIncidentImportOptionsPanel.border.title=Local Settings
CTIncidentImportOptionsPanel.fileRepoPathLabel.text=Update the Cyber Triage Data Folder if you are not using the default location:
CTIncidentImportOptionsPanel.fileRepoPathField.text=
CTIncidentImportOptionsPanel.fileRepoBrowseButton.text=Browse
CTIncidentImportOptionsPanel.caseOpenWarningLabel.text=Some settings cannot be modified while a case is open.
CTIncidentImportOptionsPanel.fileRepoFileChooser.title=Cyber Triage Data Folder
CTIncidentImportOptionsPanel.border.title_1=Incident Importer
CTIncidentImportOptionsPanel.incidentTextLabel.text=The Cyber Triage Incident Import module allows you to open data collected by Cyber Triage in Autopsy. To use this feature you must install the Cyber Triage Import Module.
CTincidentImportOptionsPanel.instructionsTextLabel.text=
CTIncidentImportOptionsPanel.instructionsTextLabel.text=For instructions on obtaining the module refer to:
CTIncidentImportOptionsPanel.importModule.text=Cyber Triage Import Module:
CTIncidentImportOptionsPanel.importModuleDetected.text=

View File

@ -0,0 +1,18 @@
# Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
# Click nbfs://nbhost/SystemFileSystem/Templates/Other/properties.properties to edit this template
CTIncidentImportOptionsPanel.border.title=Local Settings
CTIncidentImportOptionsPanel.fileRepoPathLabel.text=Update the Cyber Triage Data Folder if you are not using the default location:
CTIncidentImportOptionsPanel.fileRepoPathField.text=
CTIncidentImportOptionsPanel.fileRepoBrowseButton.text=Browse
CTIncidentImportOptionsPanel.caseOpenWarningLabel.text=Some settings cannot be modified while a case is open.
CTIncidentImportOptionsPanel.fileRepoFileChooser.title=Cyber Triage Data Folder
CTIncidentImportOptionsPanel.border.title_1=Incident Importer
CTIncidentImportOptionsPanel.incidentTextLabel.text=The Cyber Triage Incident Import module allows you to open data collected by Cyber Triage in Autopsy. To use this feature you must install the Cyber Triage Import Module.
CTincidentImportOptionsPanel.instructionsTextLabel.text=
CTIncidentImportOptionsPanel.instructionsTextLabel.text=For instructions on obtaining the module refer to:
CTIncidentImportOptionsPanel.importModule.text=Cyber Triage Import Module:
CTIncidentImportOptionsPanel.importModuleDetected.text=
CTIncidentImportOptionsPanel_setModuleDetected_detected=Detected
CTIncidentImportOptionsPanel_setModuleDetected_notDetected=Not Detected

View File

@ -0,0 +1,199 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
<TitledBorder title="Incident Importer">
<ResourceString PropertyName="titleX" bundle="com/basistech/df/cybertriage/autopsy/incidentoptions/Bundle.properties" key="CTIncidentImportOptionsPanel.border.title_1" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</TitledBorder>
</Border>
</Property>
</Properties>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
<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,0,-50,0,0,1,-17"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
<SubComponents>
<Container class="javax.swing.JPanel" name="incidentTextPanel">
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
<SubComponents>
<Component class="javax.swing.JLabel" name="incidentTextLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/incidentoptions/Bundle.properties" key="CTIncidentImportOptionsPanel.incidentTextLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</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="0" gridWidth="2" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="5" insetsLeft="5" insetsBottom="5" insetsRight="5" anchor="18" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JLabel" name="importModule">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/incidentoptions/Bundle.properties" key="CTIncidentImportOptionsPanel.importModule.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="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="5" insetsLeft="5" insetsBottom="5" insetsRight="3" anchor="10" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JLabel" name="importModuleDetected">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/incidentoptions/Bundle.properties" key="CTIncidentImportOptionsPanel.importModuleDetected.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<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="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="5" insetsLeft="0" insetsBottom="5" insetsRight="5" anchor="18" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="instructionsPanel">
<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="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="18" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
<SubComponents>
<Component class="javax.swing.JLabel" name="instructionsTextLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/incidentoptions/Bundle.properties" key="CTIncidentImportOptionsPanel.instructionsTextLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<AccessibilityProperties>
<Property name="AccessibleContext.accessibleName" type="java.lang.String" value="For instructions on obtaining the module refer to:"/>
</AccessibilityProperties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="5" insetsLeft="5" insetsBottom="5" insetsRight="0" anchor="18" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JLabel" name="instructionsLinkLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="getHtmlLink(CT_IMPORTER_DOC_LINK)" type="code"/>
</Property>
<Property name="cursor" type="java.awt.Cursor" editor="org.netbeans.modules.form.editors2.CursorEditor">
<Color id="Hand Cursor"/>
</Property>
</Properties>
<Events>
<EventHandler event="mouseClicked" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="instructionsLinkLabelMouseClicked"/>
</Events>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="1" gridY="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="5" insetsLeft="5" insetsBottom="5" insetsRight="5" anchor="18" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="repoPanel">
<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="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="18" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
<SubComponents>
<Component class="javax.swing.JLabel" name="fileRepoPathLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/incidentoptions/Bundle.properties" key="CTIncidentImportOptionsPanel.fileRepoPathLabel.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="0" gridWidth="2" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="5" insetsLeft="5" insetsBottom="5" insetsRight="5" anchor="18" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JTextField" name="fileRepoPathField">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/incidentoptions/Bundle.properties" key="CTIncidentImportOptionsPanel.fileRepoPathField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<AccessibilityProperties>
<Property name="AccessibleContext.accessibleName" type="java.lang.String" value=""/>
</AccessibilityProperties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="fileRepoPathFieldActionPerformed"/>
</Events>
<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="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="5" insetsBottom="5" insetsRight="5" anchor="18" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JButton" name="fileRepoBrowseButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/incidentoptions/Bundle.properties" key="CTIncidentImportOptionsPanel.fileRepoBrowseButton.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="fileRepoBrowseButtonActionPerformed"/>
</Events>
<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="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="5" insetsBottom="5" insetsRight="5" anchor="18" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JLabel" name="caseOpenWarningLabel">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/modules/hashdatabase/warning16.png"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/incidentoptions/Bundle.properties" key="CTIncidentImportOptionsPanel.caseOpenWarningLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</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="2" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="5" insetsBottom="5" insetsRight="5" anchor="17" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Form>

View File

@ -0,0 +1,336 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2023 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 com.basistech.df.cybertriage.autopsy.incidentoptions;
import com.basistech.df.cybertriage.autopsy.ctoptions.subpanel.CTOptionsSubPanel;
import java.awt.Desktop;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Collection;
import java.util.Collections;
import java.util.logging.Level;
import java.util.stream.Stream;
import org.sleuthkit.autopsy.coreutils.Logger;
import javax.swing.JFileChooser;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import org.apache.commons.lang3.StringUtils;
import org.netbeans.spi.options.OptionsPanelController;
import org.openide.util.Lookup;
import org.openide.util.NbBundle.Messages;
import org.openide.util.lookup.ServiceProvider;
import org.sleuthkit.autopsy.casemodule.AutopsyContentProvider;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.guiutils.JFileChooserFactory;
/**
* Options panel for CyberTriage options for importing a CyberTriage incident
*/
@ServiceProvider(service = CTOptionsSubPanel.class)
public class CTIncidentImportOptionsPanel extends CTOptionsSubPanel {
private static final Logger logger = Logger.getLogger(CTIncidentImportOptionsPanel.class.getName());
private static final String CT_IMPORTER_DOC_LINK = "https://docs.cybertriage.com/en/latest/chapters/integrations/autopsy.html";
private static final String CT_STANDARD_CONTENT_PROVIDER_NAME = "CTStandardContentProvider";
private final JFileChooserFactory fileRepoChooserFactory = new JFileChooserFactory();
private final CTSettingsPersistence ctPersistence = CTSettingsPersistence.getInstance();
private static String getHtmlLink(String url) {
return "<html><span style=\"color: blue; text-decoration: underline\">" + url + "</span></html>";
}
/**
* Creates new form CTIncidentImportOptionsPanel
*/
public CTIncidentImportOptionsPanel() {
initComponents();
this.fileRepoPathField.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void changedUpdate(DocumentEvent e) {
fireSettingsChanged();
}
@Override
public void insertUpdate(DocumentEvent e) {
fireSettingsChanged();
}
@Override
public void removeUpdate(DocumentEvent e) {
fireSettingsChanged();
}
});
Case.addEventTypeSubscriber(Collections.singleton(Case.Events.CURRENT_CASE), (evt) -> {
CTIncidentImportOptionsPanel.this.setEnabledItems(evt.getNewValue() != null);
});
}
private void setCTSettingsDisplay(CTSettings ctSettings) {
this.fileRepoPathField.setText(ctSettings.getFileRepoPath());
}
@Override
public synchronized void saveSettings() {
ctPersistence.saveCTSettings(getSettings());
}
@Override
public synchronized void loadSettings() {
CTSettings ctSettings = ctPersistence.loadCTSettings();
setCTSettingsDisplay(ctSettings);
setModuleDetected();
setEnabledItems(Case.isCaseOpen());
}
@Messages({
"CTIncidentImportOptionsPanel_setModuleDetected_detected=Detected",
"CTIncidentImportOptionsPanel_setModuleDetected_notDetected=Not Detected"
})
private void setModuleDetected() {
Collection<? extends AutopsyContentProvider> contentProviders = Lookup.getDefault().lookupAll(AutopsyContentProvider.class);
boolean detected = ((Collection<? extends AutopsyContentProvider>) (contentProviders != null ? contentProviders : Collections.emptyList())).stream()
.anyMatch(p -> p != null && StringUtils.defaultString(p.getName()).toUpperCase().startsWith(CT_STANDARD_CONTENT_PROVIDER_NAME.toUpperCase()));
this.importModuleDetected.setText(detected
? Bundle.CTIncidentImportOptionsPanel_setModuleDetected_detected()
: Bundle.CTIncidentImportOptionsPanel_setModuleDetected_notDetected());
}
private void setEnabledItems(boolean caseOpen) {
this.caseOpenWarningLabel.setVisible(caseOpen);
this.fileRepoBrowseButton.setEnabled(!caseOpen);
this.fileRepoPathField.setEnabled(!caseOpen);
}
private void fireSettingsChanged() {
this.firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}
private CTSettings getSettings() {
return new CTSettings().setFileRepoPath(this.fileRepoPathField.getText());
}
@Override
public boolean valid() {
return new File(this.fileRepoPathField.getText()).isDirectory();
}
/**
* 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;
incidentTextPanel = new javax.swing.JPanel();
incidentTextLabel = new javax.swing.JLabel();
javax.swing.JLabel importModule = new javax.swing.JLabel();
importModuleDetected = new javax.swing.JLabel();
instructionsPanel = new javax.swing.JPanel();
instructionsTextLabel = new javax.swing.JLabel();
instructionsLinkLabel = new javax.swing.JLabel();
repoPanel = new javax.swing.JPanel();
javax.swing.JLabel fileRepoPathLabel = new javax.swing.JLabel();
fileRepoPathField = new javax.swing.JTextField();
fileRepoBrowseButton = new javax.swing.JButton();
caseOpenWarningLabel = new javax.swing.JLabel();
setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(CTIncidentImportOptionsPanel.class, "CTIncidentImportOptionsPanel.border.title_1"))); // NOI18N
setLayout(new java.awt.GridBagLayout());
incidentTextPanel.setLayout(new java.awt.GridBagLayout());
org.openide.awt.Mnemonics.setLocalizedText(incidentTextLabel, org.openide.util.NbBundle.getMessage(CTIncidentImportOptionsPanel.class, "CTIncidentImportOptionsPanel.incidentTextLabel.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.gridwidth = 2;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
incidentTextPanel.add(incidentTextLabel, gridBagConstraints);
org.openide.awt.Mnemonics.setLocalizedText(importModule, org.openide.util.NbBundle.getMessage(CTIncidentImportOptionsPanel.class, "CTIncidentImportOptionsPanel.importModule.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 3);
incidentTextPanel.add(importModule, gridBagConstraints);
org.openide.awt.Mnemonics.setLocalizedText(importModuleDetected, org.openide.util.NbBundle.getMessage(CTIncidentImportOptionsPanel.class, "CTIncidentImportOptionsPanel.importModuleDetected.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 1;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(5, 0, 5, 5);
incidentTextPanel.add(importModuleDetected, gridBagConstraints);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
add(incidentTextPanel, gridBagConstraints);
instructionsPanel.setLayout(new java.awt.GridBagLayout());
org.openide.awt.Mnemonics.setLocalizedText(instructionsTextLabel, org.openide.util.NbBundle.getMessage(CTIncidentImportOptionsPanel.class, "CTIncidentImportOptionsPanel.instructionsTextLabel.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 0);
instructionsPanel.add(instructionsTextLabel, gridBagConstraints);
instructionsTextLabel.getAccessibleContext().setAccessibleName("For instructions on obtaining the module refer to:");
org.openide.awt.Mnemonics.setLocalizedText(instructionsLinkLabel, getHtmlLink(CT_IMPORTER_DOC_LINK));
instructionsLinkLabel.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
instructionsLinkLabel.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseClicked(java.awt.event.MouseEvent evt) {
instructionsLinkLabelMouseClicked(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 0;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
instructionsPanel.add(instructionsLinkLabel, gridBagConstraints);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
add(instructionsPanel, gridBagConstraints);
repoPanel.setLayout(new java.awt.GridBagLayout());
org.openide.awt.Mnemonics.setLocalizedText(fileRepoPathLabel, org.openide.util.NbBundle.getMessage(CTIncidentImportOptionsPanel.class, "CTIncidentImportOptionsPanel.fileRepoPathLabel.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.gridwidth = 2;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
repoPanel.add(fileRepoPathLabel, gridBagConstraints);
fileRepoPathField.setText(org.openide.util.NbBundle.getMessage(CTIncidentImportOptionsPanel.class, "CTIncidentImportOptionsPanel.fileRepoPathField.text")); // NOI18N
fileRepoPathField.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
fileRepoPathFieldActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(0, 5, 5, 5);
repoPanel.add(fileRepoPathField, gridBagConstraints);
fileRepoPathField.getAccessibleContext().setAccessibleName("");
org.openide.awt.Mnemonics.setLocalizedText(fileRepoBrowseButton, org.openide.util.NbBundle.getMessage(CTIncidentImportOptionsPanel.class, "CTIncidentImportOptionsPanel.fileRepoBrowseButton.text")); // NOI18N
fileRepoBrowseButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
fileRepoBrowseButtonActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 1;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.insets = new java.awt.Insets(0, 5, 5, 5);
repoPanel.add(fileRepoBrowseButton, gridBagConstraints);
caseOpenWarningLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/modules/hashdatabase/warning16.png"))); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(caseOpenWarningLabel, org.openide.util.NbBundle.getMessage(CTIncidentImportOptionsPanel.class, "CTIncidentImportOptionsPanel.caseOpenWarningLabel.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 2;
gridBagConstraints.gridwidth = 2;
gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
gridBagConstraints.insets = new java.awt.Insets(0, 5, 5, 5);
repoPanel.add(caseOpenWarningLabel, gridBagConstraints);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 2;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
add(repoPanel, gridBagConstraints);
}// </editor-fold>//GEN-END:initComponents
private void fileRepoBrowseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_fileRepoBrowseButtonActionPerformed
JFileChooser fileChooser = fileRepoChooserFactory.getChooser();
fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
fileChooser.setMultiSelectionEnabled(false);
File curSelectedDir = StringUtils.isBlank(this.fileRepoPathField.getText()) ? null : new File(this.fileRepoPathField.getText());
if (curSelectedDir == null || !curSelectedDir.isDirectory()) {
curSelectedDir = new File(CTSettings.getDefaultFileRepoPath());
}
fileChooser.setCurrentDirectory(curSelectedDir);
fileChooser.setDialogTitle(org.openide.util.NbBundle.getMessage(CTIncidentImportOptionsPanel.class, "CTIncidentImportOptionsPanel.fileRepoFileChooser.title"));
int retVal = fileChooser.showOpenDialog(this);
if (retVal == JFileChooser.APPROVE_OPTION) {
this.fileRepoPathField.setText(fileChooser.getSelectedFile().getAbsolutePath());
}
}//GEN-LAST:event_fileRepoBrowseButtonActionPerformed
private void fileRepoPathFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_fileRepoPathFieldActionPerformed
// TODO add your handling code here:
}//GEN-LAST:event_fileRepoPathFieldActionPerformed
private void instructionsLinkLabelMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_instructionsLinkLabelMouseClicked
gotoLink(CT_IMPORTER_DOC_LINK);
}//GEN-LAST:event_instructionsLinkLabelMouseClicked
private void gotoLink(String url) {
if (Desktop.isDesktopSupported()) {
try {
Desktop.getDesktop().browse(new URI(url));
} catch (IOException | URISyntaxException e) {
logger.log(Level.SEVERE, "Error opening link to: " + url, e);
}
} else {
logger.log(Level.WARNING, "Desktop API is not supported. Link cannot be opened.");
}
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JLabel caseOpenWarningLabel;
private javax.swing.JButton fileRepoBrowseButton;
private javax.swing.JTextField fileRepoPathField;
private javax.swing.JLabel importModuleDetected;
private javax.swing.JLabel incidentTextLabel;
private javax.swing.JPanel incidentTextPanel;
private javax.swing.JLabel instructionsLinkLabel;
private javax.swing.JPanel instructionsPanel;
private javax.swing.JLabel instructionsTextLabel;
private javax.swing.JPanel repoPanel;
// End of variables declaration//GEN-END:variables
}

View File

@ -0,0 +1,102 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2023 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 com.basistech.df.cybertriage.autopsy.incidentoptions;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Objects;
import java.util.logging.Level;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.apache.commons.lang3.StringUtils;
import org.openide.modules.Places;
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
/**
* CT settings that don't include license information. This code must be kept
* in-sync with code in CT Autopsy Importer NBM.
*/
public class CTSettings {
private static final Logger LOGGER = Logger.getLogger(CTSettings.class.getCanonicalName());
private static final String DEFAULT_FILE_REPO_PATH = getAppDataLocalDirectory();
private static final String CYBERTRIAGE_FOLDER = "cybertriage";
private static final String CYBERTRIAGE_DOT_FOLDER = "." + CYBERTRIAGE_FOLDER;
// based on com.basistech.df.cybertriage.utils.SystemProperties
private static String getAppDataLocalDirectory() {
if (Objects.nonNull(Places.getUserDirectory()) && Places.getUserDirectory().getAbsolutePath().endsWith("testuserdir")) { // APP is in testing .. this should return the test path
LOGGER.log(Level.INFO, "Application Data (test mode) Path: " + Places.getUserDirectory().getAbsolutePath());
return Places.getUserDirectory().getAbsolutePath();
}
// try to use LOCALAPPDATA on windows
String localDataStr = System.getenv("LOCALAPPDATA");
if (StringUtils.isNotBlank(localDataStr)) {
Path localAppPath = Paths.get(localDataStr, CYBERTRIAGE_FOLDER);
try {
Files.createDirectories(localAppPath);
LOGGER.log(Level.INFO, "Application Data Path: " + localAppPath.toString());
return localAppPath.toString();
} catch (IOException ex) {
LOGGER.log(Level.SEVERE, "IO Error using " + localAppPath.toString(), ex);
}
}
// try to use ~/.cybertriage anywhere else
if (!PlatformUtil.isWindowsOS()) {
String homePathStr = System.getenv("HOME");
if (StringUtils.isNotBlank(homePathStr)) {
Path localAppPath = Paths.get(homePathStr, CYBERTRIAGE_DOT_FOLDER);
try {
Files.createDirectories(localAppPath);
LOGGER.log(Level.INFO, "Non-windows Application Data Path: " + localAppPath.toString());
return localAppPath.toString();
} catch (IOException ex) {
LOGGER.log(Level.SEVERE, "IO Error using " + localAppPath.toString(), ex);
}
}
}
// defer to user directory otherwise
return Places.getUserDirectory().getAbsolutePath(); // In case of an IO Error
}
public static String getDefaultFileRepoPath() {
return DEFAULT_FILE_REPO_PATH;
}
static CTSettings getDefaultSettings() {
return new CTSettings()
.setFileRepoPath(DEFAULT_FILE_REPO_PATH);
}
private String fileRepoPath = DEFAULT_FILE_REPO_PATH;
public String getFileRepoPath() {
return fileRepoPath;
}
public CTSettings setFileRepoPath(String fileRepoPath) {
this.fileRepoPath = fileRepoPath;
return this;
}
}

View File

@ -0,0 +1,85 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2023 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 com.basistech.df.cybertriage.autopsy.incidentoptions;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.File;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.logging.Level;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
/**
* Handles persisting CT Settings. This code must be kept in-sync with code in
* CT Autopsy Importer NBM.
*/
public class CTSettingsPersistence {
private static final String CT_SETTINGS_DIR = "CyberTriage";
private static final String CT_SETTINGS_FILENAME = "CyberTriageSettings.json";
private static final Logger logger = Logger.getLogger(CTSettingsPersistence.class.getName());
private static final CTSettingsPersistence instance = new CTSettingsPersistence();
private final ObjectMapper objectMapper = new ObjectMapper();
public static CTSettingsPersistence getInstance() {
return instance;
}
public synchronized boolean saveCTSettings(CTSettings ctSettings) {
if (ctSettings != null) {
File settingsFile = getCTSettingsFile();
settingsFile.getParentFile().mkdirs();
try {
objectMapper.writeValue(settingsFile, ctSettings);
return true;
} catch (IOException ex) {
logger.log(Level.WARNING, "There was an error writing CyberTriage settings to file: " + settingsFile.getAbsolutePath(), ex);
}
}
return false;
}
public synchronized CTSettings loadCTSettings() {
CTSettings settings = null;
File settingsFile = getCTSettingsFile();
if (settingsFile.isFile()) {
try {
settings = objectMapper.readValue(settingsFile, CTSettings.class);
} catch (IOException ex) {
logger.log(Level.WARNING, "There was an error reading CyberTriage settings to file: " + settingsFile.getAbsolutePath(), ex);
}
}
return settings == null
? CTSettings.getDefaultSettings()
: settings;
}
private File getCTSettingsFile() {
return Paths.get(PlatformUtil.getModuleConfigDirectory(), CT_SETTINGS_DIR, CT_SETTINGS_FILENAME).toFile();
}
}

View File

@ -21,14 +21,10 @@ package com.basistech.df.cybertriage.autopsy.malwarescan;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.Consumer;
/**
@ -36,7 +32,7 @@ import java.util.function.Consumer;
* blocks (and subsequently add and flush operations) until previous batch
* finishes.
*/
public class BatchProcessor<T> {
class BatchProcessor<T> {
private ExecutorService processingExecutorService = Executors.newSingleThreadExecutor();

View File

@ -0,0 +1,7 @@
MalwareScanIngestSettingsPanel.uploadFilesCheckbox.AccessibleContext.accessibleName=Upload file content for files that do not have results
MalwareScanIngestSettingsPanel.uploadFilesCheckbox.label=Upload file content for files that do not have results
MalwareScanIngestSettingsPanel.uploadFilesCheckbox.text=Upload file content for files that do not have results
DataSourceIntegrityIngestSettingsPanel.queryFilesTextArea.text=Query for existing results using file\u2019s hash
MalwareScanIngestSettingsPanel.ingestSettingsLabel.text=Ingest Settings
MalwareScanIngestSettingsPanel.paidLicenseTextArea.text=This module requires a paid license. \nSee the Global Options panel for details
MalwareScanIngestSettingsPanel.queryFilesCheckbox.text=Query for existing results using file\u2019s hash

View File

@ -1,3 +1,7 @@
MalwareScanIngestModule_longPollForNotFound_fileLookupPolling_desc=Waiting for all uploaded files to complete scanning.
MalwareScanIngestModule_longPollForNotFound_fileLookupPolling_title=Waiting for File Upload Results
MalwareScanIngestModule_longPollForNotFound_timeout_desc=There was a timeout while waiting for file uploads to be processed. Please try again later.
MalwareScanIngestModule_longPollForNotFound_timeout_title=File Upload Results Timeout
MalwareScanIngestModule_malwareTypeDisplayName=Malware
# {0} - errorResponse
MalwareScanIngestModule_SharedProcessing_authTokenResponseError_desc=Received error: ''{0}'' when fetching the API authentication token for the license
@ -6,6 +10,8 @@ MalwareScanIngestModule_SharedProcessing_createAnalysisResult_No=NO
MalwareScanIngestModule_SharedProcessing_createAnalysisResult_Yes=YES
MalwareScanIngestModule_SharedProcessing_exhaustedHashLookups_desc=The remaining hash lookups for this license have been exhausted
MalwareScanIngestModule_SharedProcessing_exhaustedHashLookups_title=Hash Lookups Exhausted
MalwareScanIngestModule_SharedProcessing_exhaustedResultsHashLookups_desc=Not all files were processed because hash lookup limits were exceeded. Please try again when your limits reset.
MalwareScanIngestModule_SharedProcessing_exhaustedResultsHashLookups_title=Lookup Limits Exceeded
MalwareScanIngestModule_SharedProcessing_flushTimeout_desc=A timeout occurred while finishing processing
MalwareScanIngestModule_SharedProcessing_flushTimeout_title=Processing Timeout
MalwareScanIngestModule_SharedProcessing_generalProcessingError_desc=An error occurred while processing hash lookup results
@ -16,12 +22,29 @@ MalwareScanIngestModule_SharedProcessing_repServicenResponseError_title=Lookup A
MalwareScanIngestModule_ShareProcessing_batchTimeout_desc=Batch processing timed out
MalwareScanIngestModule_ShareProcessing_batchTimeout_title=Batch Processing Timeout
# {0} - remainingLookups
MalwareScanIngestModule_ShareProcessing_lowLimitWarning_desc=This license only has {0} lookups remaining
MalwareScanIngestModule_ShareProcessing_lowLimitWarning_title=Hash Lookups Low
MalwareScanIngestModule_ShareProcessing_lowLookupsLimitWarning_desc=This license only has {0} lookups remaining.
MalwareScanIngestModule_ShareProcessing_lowLookupsLimitWarning_title=Hash Lookups Low
# {0} - remainingUploads
MalwareScanIngestModule_ShareProcessing_lowUploadsLimitWarning_desc=This license only has {0} file uploads remaining.
MalwareScanIngestModule_ShareProcessing_lowUploadsLimitWarning_title=File Uploads Limit Low
MalwareScanIngestModule_ShareProcessing_noLicense_desc=No Cyber Triage license could be loaded. Cyber Triage processing will be disabled.
MalwareScanIngestModule_ShareProcessing_noLicense_title=No Cyber Triage License
MalwareScanIngestModule_ShareProcessing_noRemaining_desc=There are no more remaining hash lookups for this license at this time. Cyber Triage processing will be disabled.
MalwareScanIngestModule_ShareProcessing_noRemaining_title=No remaining lookups
MalwareScanIngestModuleFactory_description=The malware scan ingest module queries the Cyber Triage cloud API for any possible malicious executables.
MalwareScanIngestModule_ShareProcessing_noLookupsRemaining_desc=There are no more remaining hash lookups for this license at this time. Malware scanning will be disabled.
MalwareScanIngestModule_ShareProcessing_noLookupsRemaining_title=No remaining lookups
MalwareScanIngestModule_ShareProcessing_noUploadsRemaining_desc=There are no more remaining file uploads for this license at this time. File uploading will be disabled.
MalwareScanIngestModule_ShareProcessing_noUploadsRemaining_title=No remaining file uploads
MalwareScanIngestModule_uploadFile_noRemainingFileUploads_desc=There are no more file uploads on this license at this time. File uploads will be disabled for remaining uploads.
MalwareScanIngestModule_uploadFile_noRemainingFileUploads_title=No Remaining File Uploads
# {0} - objectId
MalwareScanIngestModule_uploadFile_notUploadable_desc=A file did not meet requirements for upload (object id: {0}).
MalwareScanIngestModule_uploadFile_notUploadable_title=Not Able to Upload
MalwareScanIngestModuleFactory_description=Identifies executable files with malware.
MalwareScanIngestModuleFactory_displayName=Cyber Triage Malware Scanner
MalwareScanIngestModuleFactory_version=1.0.0
MalwareScanIngestSettingsPanel.uploadFilesCheckbox.AccessibleContext.accessibleName=Upload file content for files that do not have results
MalwareScanIngestSettingsPanel.uploadFilesCheckbox.label=Upload file content for files that do not have results
MalwareScanIngestSettingsPanel.uploadFilesCheckbox.text=Upload file content for files that do not have results
DataSourceIntegrityIngestSettingsPanel.queryFilesTextArea.text=Query for existing results using file\u2019s hash
MalwareScanIngestSettingsPanel.ingestSettingsLabel.text=Ingest Settings
MalwareScanIngestSettingsPanel.paidLicenseTextArea.text=This module requires a paid license. \nSee the Global Options panel for details
MalwareScanIngestSettingsPanel.queryFilesCheckbox.text=Query for existing results using file\u2019s hash

View File

@ -25,6 +25,8 @@ import org.sleuthkit.autopsy.ingest.FileIngestModule;
import org.sleuthkit.autopsy.ingest.IngestModuleFactoryAdapter;
import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSettingsPanel;
import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings;
import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettingsPanel;
import org.sleuthkit.autopsy.ingest.NoIngestModuleIngestJobSettings;
/**
* Factory for malware scan ingest modules.
@ -32,7 +34,7 @@ import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings;
@ServiceProvider(service = org.sleuthkit.autopsy.ingest.IngestModuleFactory.class)
@Messages({
"MalwareScanIngestModuleFactory_displayName=Cyber Triage Malware Scanner",
"MalwareScanIngestModuleFactory_description=The malware scan ingest module queries the Cyber Triage cloud API for any possible malicious executables.",
"MalwareScanIngestModuleFactory_description=Identifies executable files with malware.",
"MalwareScanIngestModuleFactory_version=1.0.0"
})
public class MalwareScanIngestModuleFactory extends IngestModuleFactoryAdapter {
@ -66,7 +68,7 @@ public class MalwareScanIngestModuleFactory extends IngestModuleFactoryAdapter {
@Override
public FileIngestModule createFileIngestModule(IngestModuleIngestJobSettings ingestOptions) {
return new MalwareScanIngestModule();
return new MalwareScanIngestModule((MalwareScanIngestSettings) ingestOptions);
}
@Override
@ -81,4 +83,23 @@ public class MalwareScanIngestModuleFactory extends IngestModuleFactoryAdapter {
return optionsPanel;
}
@Override
public boolean hasIngestJobSettingsPanel() {
return true;
}
@Override
public IngestModuleIngestJobSettingsPanel getIngestJobSettingsPanel(IngestModuleIngestJobSettings settings) {
if (settings instanceof MalwareScanIngestSettings) {
return new MalwareScanIngestSettingsPanel((MalwareScanIngestSettings) settings);
}
/*
* Compatibility check for older versions.
*/
if (settings instanceof NoIngestModuleIngestJobSettings) {
return new MalwareScanIngestSettingsPanel(new MalwareScanIngestSettings());
}
throw new IllegalArgumentException("Expected settings argument to be an instance of IngestSettings");
}
}

View File

@ -0,0 +1,96 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2023 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 com.basistech.df.cybertriage.autopsy.malwarescan;
import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings;
/**
* Ingest job settings for the Malware scanner module.
*/
final class MalwareScanIngestSettings implements IngestModuleIngestJobSettings {
private static final long serialVersionUID = 1L;
private static final boolean DEFAULT_QUERY_FILES = true;
private static final boolean DEFAULT_UPLOAD_FILES = true;
public boolean queryFiles;
public boolean uploadFiles;
/**
* Instantiate the ingest job settings with default values.
*/
MalwareScanIngestSettings() {
this.queryFiles = DEFAULT_QUERY_FILES;
this.uploadFiles = DEFAULT_UPLOAD_FILES;
}
/**
* Instantiate the ingest job settings.
*
* @param computeHashes Compute hashes if none are present
* @param verifyHashes Verify hashes if any are present
*/
MalwareScanIngestSettings(boolean queryFiles, boolean uploadFiles) {
this.queryFiles = queryFiles;
this.uploadFiles = uploadFiles;
}
@Override
public long getVersionNumber() {
return serialVersionUID;
}
/**
* Should files be queried?
*
* @return true if files should be queried, false otherwise
*/
public boolean shouldQueryFiles() {
return queryFiles;
}
/**
* Set whether files should be queried.
*
* @param queryFiles true if files should be queried
*/
void setqueryFiles(boolean queryFiles) {
this.queryFiles = queryFiles;
}
/**
* Should files be uploaded?
*
* @return true if files should be uploaded, false otherwise
*/
public boolean shouldUploadFiles() {
return uploadFiles;
}
/**
* Set whether files should be uploaded.
*
* @param uploadFiles true if files should be uploaded
*/
void setUploadFiles(boolean uploadFiles) {
this.uploadFiles = uploadFiles;
}
}

View File

@ -0,0 +1,123 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<Properties>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[300, 155]"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace min="6" pref="6" max="-2" attributes="0"/>
<Component id="ingestSettingsLabel" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<EmptySpace min="6" pref="6" max="-2" attributes="0"/>
<Component id="uploadFilesCheckbox" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="queryFilesCheckbox" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="5" max="-2" attributes="0"/>
<Component id="paidLicenseTextArea" min="-2" pref="243" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace min="-2" pref="185" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="ingestSettingsLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="18" max="-2" attributes="0"/>
<Component id="queryFilesCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="uploadFilesCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="18" max="-2" attributes="0"/>
<Component id="paidLicenseTextArea" min="-2" pref="32" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JCheckBox" name="queryFilesCheckbox">
<Properties>
<Property name="selected" type="boolean" value="true"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/malwarescan/Bundle.properties" key="MalwareScanIngestSettingsPanel.queryFilesCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
</Component>
<Component class="javax.swing.JCheckBox" name="uploadFilesCheckbox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/malwarescan/Bundle.properties" key="MalwareScanIngestSettingsPanel.uploadFilesCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="focusable" type="boolean" value="false"/>
<Property name="label" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/malwarescan/Bundle.properties" key="MalwareScanIngestSettingsPanel.uploadFilesCheckbox.label" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<AccessibilityProperties>
<Property name="AccessibleContext.accessibleName" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/malwarescan/Bundle.properties" key="MalwareScanIngestSettingsPanel.uploadFilesCheckbox.AccessibleContext.accessibleName" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</AccessibilityProperties>
</Component>
<Component class="javax.swing.JLabel" name="ingestSettingsLabel">
<Properties>
<Property name="font" type="java.awt.Font" editor="org.netbeans.modules.form.editors2.FontEditor">
<FontInfo relative="true">
<Font bold="true" component="ingestSettingsLabel" property="font" relativeSize="true" size="0"/>
</FontInfo>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/malwarescan/Bundle.properties" key="MalwareScanIngestSettingsPanel.ingestSettingsLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JTextArea" name="paidLicenseTextArea">
<Properties>
<Property name="columns" type="int" value="20"/>
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
<Font name="Segoe UI" size="12" style="1"/>
</Property>
<Property name="rows" type="int" value="5"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/malwarescan/Bundle.properties" key="MalwareScanIngestSettingsPanel.paidLicenseTextArea.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="wrapStyleWord" type="boolean" value="true"/>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="null"/>
</Property>
<Property name="cursor" type="java.awt.Cursor" editor="org.netbeans.modules.form.editors2.CursorEditor">
<Color id="Default Cursor"/>
</Property>
<Property name="focusable" type="boolean" value="false"/>
<Property name="opaque" type="boolean" value="false"/>
<Property name="requestFocusEnabled" type="boolean" value="false"/>
</Properties>
</Component>
</SubComponents>
</Form>

View File

@ -0,0 +1,149 @@
/*
* Autopsy Browser
*
* Copyright 2023 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 com.basistech.df.cybertriage.autopsy.malwarescan;
import com.basistech.df.cybertriage.autopsy.ctapi.json.LicenseInfo;
import com.basistech.df.cybertriage.autopsy.ctoptions.ctcloud.CTLicensePersistence;
import java.util.Optional;
import org.sleuthkit.autopsy.modules.dataSourceIntegrity.*;
import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings;
import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettingsPanel;
/**
* Ingest job settings panel for the Malware scanner ingest.
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
final class MalwareScanIngestSettingsPanel extends IngestModuleIngestJobSettingsPanel {
private final CTLicensePersistence ctPersistence = CTLicensePersistence.getInstance();
MalwareScanIngestSettingsPanel(MalwareScanIngestSettings settings) {
initComponents();
customizeComponents(settings);
}
/**
* Update components with values from the ingest job settings.
*
* @param settings The ingest job settings.
*/
private void customizeComponents(MalwareScanIngestSettings settings) {
Optional<LicenseInfo> licenseInfoOpt = ctPersistence.loadLicenseInfo();
LicenseInfo licenseInfo = licenseInfoOpt.orElse(null);
if (licenseInfo != null) {
this.paidLicenseTextArea.setVisible(false);
this.queryFilesCheckbox.setVisible(true);
this.queryFilesCheckbox.setEnabled(false);
this.uploadFilesCheckbox.setVisible(true);
this.queryFilesCheckbox.setSelected(true);
this.uploadFilesCheckbox.setSelected(settings.shouldUploadFiles());
} else {
this.paidLicenseTextArea.setVisible(true);
this.queryFilesCheckbox.setVisible(false);
this.uploadFilesCheckbox.setVisible(false);
}
}
@Override
public IngestModuleIngestJobSettings getSettings() {
return new MalwareScanIngestSettings(queryFilesCheckbox.isSelected(), uploadFilesCheckbox.isSelected());
}
/**
* 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() {
queryFilesCheckbox = new javax.swing.JCheckBox();
uploadFilesCheckbox = new javax.swing.JCheckBox();
ingestSettingsLabel = new javax.swing.JLabel();
paidLicenseTextArea = new javax.swing.JTextArea();
setPreferredSize(new java.awt.Dimension(300, 155));
queryFilesCheckbox.setSelected(true);
org.openide.awt.Mnemonics.setLocalizedText(queryFilesCheckbox, org.openide.util.NbBundle.getMessage(MalwareScanIngestSettingsPanel.class, "MalwareScanIngestSettingsPanel.queryFilesCheckbox.text")); // NOI18N
queryFilesCheckbox.setEnabled(false);
org.openide.awt.Mnemonics.setLocalizedText(uploadFilesCheckbox, org.openide.util.NbBundle.getMessage(MalwareScanIngestSettingsPanel.class, "MalwareScanIngestSettingsPanel.uploadFilesCheckbox.text")); // NOI18N
uploadFilesCheckbox.setFocusable(false);
uploadFilesCheckbox.setLabel(org.openide.util.NbBundle.getMessage(MalwareScanIngestSettingsPanel.class, "MalwareScanIngestSettingsPanel.uploadFilesCheckbox.label")); // NOI18N
ingestSettingsLabel.setFont(ingestSettingsLabel.getFont().deriveFont(ingestSettingsLabel.getFont().getStyle() | java.awt.Font.BOLD));
org.openide.awt.Mnemonics.setLocalizedText(ingestSettingsLabel, org.openide.util.NbBundle.getMessage(MalwareScanIngestSettingsPanel.class, "MalwareScanIngestSettingsPanel.ingestSettingsLabel.text")); // NOI18N
paidLicenseTextArea.setColumns(20);
paidLicenseTextArea.setFont(new java.awt.Font("Segoe UI", 1, 12)); // NOI18N
paidLicenseTextArea.setRows(5);
paidLicenseTextArea.setText(org.openide.util.NbBundle.getMessage(MalwareScanIngestSettingsPanel.class, "MalwareScanIngestSettingsPanel.paidLicenseTextArea.text")); // NOI18N
paidLicenseTextArea.setWrapStyleWord(true);
paidLicenseTextArea.setBorder(null);
paidLicenseTextArea.setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));
paidLicenseTextArea.setFocusable(false);
paidLicenseTextArea.setOpaque(false);
paidLicenseTextArea.setRequestFocusEnabled(false);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(6, 6, 6)
.addComponent(ingestSettingsLabel))
.addGroup(layout.createSequentialGroup()
.addGap(6, 6, 6)
.addComponent(uploadFilesCheckbox))
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(queryFilesCheckbox))
.addGroup(layout.createSequentialGroup()
.addGap(5, 5, 5)
.addComponent(paidLicenseTextArea, javax.swing.GroupLayout.PREFERRED_SIZE, 243, javax.swing.GroupLayout.PREFERRED_SIZE)))
.addGap(185, 185, 185))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(ingestSettingsLabel)
.addGap(18, 18, 18)
.addComponent(queryFilesCheckbox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(uploadFilesCheckbox)
.addGap(18, 18, 18)
.addComponent(paidLicenseTextArea, javax.swing.GroupLayout.PREFERRED_SIZE, 32, javax.swing.GroupLayout.PREFERRED_SIZE))
);
uploadFilesCheckbox.getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(MalwareScanIngestSettingsPanel.class, "MalwareScanIngestSettingsPanel.uploadFilesCheckbox.AccessibleContext.accessibleName")); // NOI18N
}// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JLabel ingestSettingsLabel;
private javax.swing.JTextArea paidLicenseTextArea;
private javax.swing.JCheckBox queryFilesCheckbox;
private javax.swing.JCheckBox uploadFilesCheckbox;
// End of variables declaration//GEN-END:variables
}

View File

@ -0,0 +1,201 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2023 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 com.basistech.df.cybertriage.autopsy.malwarescan;
import com.google.common.net.InetAddresses;
import java.net.InetAddress;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.logging.Level;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException;
/**
* Utility class to anonymize paths.
*/
class PathNormalizer {
private static final Logger LOGGER = Logger.getLogger(PathNormalizer.class.getName());
private static final String ANONYMIZED_USERNAME = "<user>";
private static final String ANONYMIZED_IP = "<private_ip>";
private static final String ANONYMIZED_HOSTNAME = "<hostname>";
private static final String FORWARD_SLASH = "/";
private static final String BACK_SLASH = "\\";
private static final Pattern USER_PATH_FORWARD_SLASH_REGEX = Pattern.compile("(?<!all )([/]{0,1}\\Qusers\\E/)(?!(public|Default|defaultAccount|All Users))([^/]+)(/){0,1}", Pattern.CASE_INSENSITIVE);
private static final Pattern USER_PATH_BACK_SLASH_REGEX = Pattern.compile("(?<!all )([\\\\]{0,1}\\Qusers\\E\\\\)(?!(public|Default|defaultAccount|All Users))([^\\\\]+)([\\\\]){0,1}", Pattern.CASE_INSENSITIVE);
private static final Pattern USER_PATH_FORWARD_SLASH_REGEX_XP = Pattern.compile("([/]{0,1}\\Qdocuments and settings\\E/)(?!(Default User|All Users))([^/]+)(/){0,1}", Pattern.CASE_INSENSITIVE);
private static final Pattern USER_PATH_BACK_SLASH_REGEX_XP = Pattern.compile("([\\\\]{0,1}\\Qdocuments and settings\\E\\\\)(?!(Default User|All Users))([^\\\\]+)(\\\\){0,1}", Pattern.CASE_INSENSITIVE);
private static final Pattern UNC_PATH_FORWARD_SLASH_PATTERN = Pattern.compile("(//)([^/]+)(/){0,1}");
private static final Pattern UNC_PATH_BACK_SLASH_PATTERN = Pattern.compile("(\\\\\\\\)([^\\\\]+)(\\\\){0,1}");
private static final String USERNAME_REGEX_REPLACEMENT = "$1" + ANONYMIZED_USERNAME + "$4";
private final SleuthkitCase skCase;
PathNormalizer(SleuthkitCase skCase) {
this.skCase = skCase;
}
protected List<String> getUsernames() {
try {
return this.skCase.getOsAccountManager().getOsAccounts().stream()
.filter(acct -> acct != null)
.map(acct -> acct.getLoginName().orElse(null))
.filter(StringUtils::isNotBlank)
.collect(Collectors.toList());
} catch (TskCoreException ex) {
LOGGER.log(Level.WARNING, "There was an error getting current os accounts", ex);
return Collections.emptyList();
}
}
public String normalizePath(String inputString) {
if (StringUtils.isBlank(inputString)) {
return "";
}
String anonymousString = anonymizeUserFromPathsWithForwardSlashes(inputString);
anonymousString = anonymizeUserFromPathsWithBackSlashes(anonymousString);
anonymousString = anonymizeServerFromUNCPath(anonymousString);
return anonymousString;
}
private String anonymizeUserFromPathsWithForwardSlashes(String stringWithUsername) {
String anonymousString = stringWithUsername;
anonymousString = regexReplace(anonymousString, USER_PATH_FORWARD_SLASH_REGEX_XP, USERNAME_REGEX_REPLACEMENT);
anonymousString = regexReplace(anonymousString, USER_PATH_FORWARD_SLASH_REGEX, USERNAME_REGEX_REPLACEMENT);
anonymousString = replaceFolder(anonymousString, getUsernames(), ANONYMIZED_USERNAME, FORWARD_SLASH);
return anonymousString;
}
// Most paths in CyberTriage are normalized with forward slashes
// but there can still be strings containing paths that are not normalized such paths contained in arguments or event log payloads
private String anonymizeUserFromPathsWithBackSlashes(String stringWithUsername) {
String anonymousString = stringWithUsername;
anonymousString = regexReplace(anonymousString, USER_PATH_BACK_SLASH_REGEX_XP, USERNAME_REGEX_REPLACEMENT);
anonymousString = regexReplace(anonymousString, USER_PATH_BACK_SLASH_REGEX, USERNAME_REGEX_REPLACEMENT);
anonymousString = replaceFolder(anonymousString, getUsernames(), ANONYMIZED_USERNAME, BACK_SLASH);
return anonymousString;
}
private String anonymizeServerFromUNCPath(String inputString) {
Set<String> serverNames = new HashSet<>();
String anonymousString = inputString.toLowerCase(Locale.ENGLISH);
Matcher forwardSlashMatcher = UNC_PATH_FORWARD_SLASH_PATTERN.matcher(anonymousString);
while (forwardSlashMatcher.find()) {
String serverName = forwardSlashMatcher.group(2);
serverNames.add(serverName);
}
Matcher backSlashMatcher = UNC_PATH_BACK_SLASH_PATTERN.matcher(anonymousString);
while (backSlashMatcher.find()) {
String serverName = backSlashMatcher.group(2);
serverNames.add(serverName);
}
for (String serverName : serverNames) {
if (StringUtils.isBlank(serverName)) {
continue;
}
if (InetAddresses.isInetAddress(serverName) && isLocalIP(serverName)) {
anonymousString = replaceFolder(anonymousString, Collections.singletonList(serverName), ANONYMIZED_IP);
} else {
anonymousString = replaceFolder(anonymousString, Collections.singletonList(serverName), ANONYMIZED_HOSTNAME);
}
}
return anonymousString;
}
private static String regexReplace(String orig, Pattern pattern, String regexReplacement) {
Matcher matcher = pattern.matcher(orig);
return matcher.replaceAll(regexReplacement);
}
private static String replaceFolder(String orig, List<String> valuesToReplace, String replacementValue) {
String anonymized = orig;
anonymized = replaceFolder(anonymized, valuesToReplace, replacementValue, FORWARD_SLASH);
anonymized = replaceFolder(anonymized, valuesToReplace, replacementValue, BACK_SLASH);
return anonymized;
}
private static String replaceFolder(String orig, List<String> valuesToReplace, String replacementValue, String folderDelimiter) {
if (orig == null || valuesToReplace == null) {
return orig;
}
String anonymousString = orig;
// ensure non-null
folderDelimiter = StringUtils.defaultString(folderDelimiter);
replacementValue = StringUtils.defaultString(replacementValue);
// replace
for (String valueToReplace : valuesToReplace) {
if (StringUtils.isNotEmpty(valueToReplace)) {
anonymousString = StringUtils.replace(anonymousString,
folderDelimiter + valueToReplace + folderDelimiter,
folderDelimiter + replacementValue + folderDelimiter);
}
}
return anonymousString;
}
/**
* Returns true if IP Address is Any Local / Site Local / Link Local / Loop
* back local. Sample list "0.0.0.0", wildcard addres
* "10.1.1.1","10.10.10.10", site local address "127.0.0.0","127.2.2.2",
* loopback address "169.254.0.0","169.254.10.10", Link local address
* "172.16.0.0","172.31.245.245", site local address
*
* @param ipAddress
* @return
*/
public static boolean isLocalIP(String ipAddress) {
try {
InetAddress a = InetAddresses.forString(ipAddress);
return a.isAnyLocalAddress() || a.isSiteLocalAddress()
|| a.isLoopbackAddress() || a.isLinkLocalAddress();
} catch (IllegalArgumentException ex) {
LOGGER.log(Level.WARNING, "Invalid IP string", ex);
return false;
}
}
}

View File

@ -66,8 +66,8 @@ Case.open.msgDlg.updated.msg=Updated case database schema.\nA backup copy of the
Case.open.msgDlg.updated.title=Case Database Schema Update
Case.checkImgExist.confDlg.doesntExist.msg=One of the images associated with \n\
this case are missing. Would you like to search for them now?\n\
Previously, the image was located at:\n\
{0}\n\
Previously, the image with host, {0}, was located at:\n\
{1}\n\
Please note that you will still be able to browse directories and generate reports\n\
if you choose No, but you will not be able to view file content or run the ingest process.
Case.checkImgExist.confDlg.doesntExist.title=Missing Image

View File

@ -16,6 +16,7 @@ Case.exceptionMessage.cannotDeleteCurrentCase=Cannot delete current case, it mus
Case.exceptionMessage.cannotGetLockToDeleteCase=Cannot delete case because it is open for another user or host.
Case.exceptionMessage.cannotLocateMainWindow=Cannot locate main application window
Case.exceptionMessage.cannotOpenMultiUserCaseNoSettings=Multi-user settings are missing (see Tools, Options, Multi-user tab), cannot open a multi-user case.
Case.exceptionMessage.contentProviderCouldNotBeFound=Content provider was specified for the case but could not be loaded.
# {0} - exception message
Case.exceptionMessage.couldNotCreatCollaborationMonitor=Failed to create collaboration monitor:\n{0}.
# {0} - exception message
@ -252,8 +253,8 @@ Case.open.msgDlg.updated.msg=Updated case database schema.\nA backup copy of the
Case.open.msgDlg.updated.title=Case Database Schema Update
Case.checkImgExist.confDlg.doesntExist.msg=One of the images associated with \n\
this case are missing. Would you like to search for them now?\n\
Previously, the image was located at:\n\
{0}\n\
Previously, the image with host, {0}, was located at:\n\
{1}\n\
Please note that you will still be able to browse directories and generate reports\n\
if you choose No, but you will not be able to view file content or run the ingest process.
Case.checkImgExist.confDlg.doesntExist.title=Missing Image

View File

@ -18,6 +18,7 @@
*/
package org.sleuthkit.autopsy.casemodule;
import com.basistech.df.cybertriage.autopsy.CTIntegrationMissingDialog;
import org.sleuthkit.autopsy.featureaccess.FeatureAccessUtils;
import com.google.common.annotations.Beta;
import com.google.common.eventbus.Subscribe;
@ -177,6 +178,7 @@ public class Case {
private static final String CASE_ACTION_THREAD_NAME = "%s-case-action";
private static final String CASE_RESOURCES_THREAD_NAME = "%s-manage-case-resources";
private static final String NO_NODE_ERROR_MSG_FRAGMENT = "KeeperErrorCode = NoNode";
private static final String CT_PROVIDER_PREFIX = "CTStandardContentProvider_";
private static final Logger logger = Logger.getLogger(Case.class.getName());
private static final AutopsyEventPublisher eventPublisher = new AutopsyEventPublisher();
private static final Object caseActionSerializationLock = new Object();
@ -192,6 +194,8 @@ public class Case {
private final SleuthkitEventListener sleuthkitEventListener;
private CollaborationMonitor collaborationMonitor;
private Services caseServices;
// matches something like '\\.\PHYSICALDRIVE0'
private static final String PLACEHOLDER_DS_PATH_REGEX = "^\\s*\\\\\\\\\\.\\\\PHYSICALDRIVE\\d*\\s*$";
private volatile boolean hasDataSource = false;
private volatile boolean hasData = false;
@ -1301,9 +1305,18 @@ public class Case {
for (Map.Entry<Long, String> entry : imgPaths.entrySet()) {
long obj_id = entry.getKey();
String path = entry.getValue();
boolean fileExists = (new File(path).isFile() || DriveUtils.driveExists(path));
boolean fileExists = (new File(path).exists()|| DriveUtils.driveExists(path));
if (!fileExists) {
// CT-7336: ignore relocating datasources if file provider is present and placeholder path is used.
if (newCurrentCase.getMetadata() != null
&& !StringUtils.isBlank(newCurrentCase.getMetadata().getContentProviderName())
&& (path == null || path.matches(PLACEHOLDER_DS_PATH_REGEX))) {
continue;
}
try {
DataSource ds = newCurrentCase.getSleuthkitCase().getDataSource(obj_id);
String hostName = StringUtils.defaultString(ds.getHost() == null ? "" : ds.getHost().getName());
// Using invokeAndWait means that the dialog will
// open on the EDT but this thread will wait for an
// answer. Using invokeLater would cause this loop to
@ -1313,7 +1326,7 @@ public class Case {
public void run() {
int response = JOptionPane.showConfirmDialog(
mainFrame,
NbBundle.getMessage(Case.class, "Case.checkImgExist.confDlg.doesntExist.msg", path),
NbBundle.getMessage(Case.class, "Case.checkImgExist.confDlg.doesntExist.msg", hostName, path),
NbBundle.getMessage(Case.class, "Case.checkImgExist.confDlg.doesntExist.title"),
JOptionPane.YES_NO_OPTION);
if (response == JOptionPane.YES_OPTION) {
@ -1325,7 +1338,7 @@ public class Case {
}
});
} catch (InterruptedException | InvocationTargetException ex) {
} catch (InterruptedException | InvocationTargetException | TskCoreException | TskDataException ex) {
logger.log(Level.SEVERE, "Failed to show missing image confirmation dialog", ex); //NON-NLS
}
}
@ -2729,6 +2742,7 @@ public class Case {
"Case.progressMessage.openingCaseDatabase=Opening case database...",
"# {0} - exception message", "Case.exceptionMessage.couldNotOpenCaseDatabase=Failed to open case database:\n{0}.",
"# {0} - exception message", "Case.exceptionMessage.unsupportedSchemaVersionMessage=Unsupported case database schema version:\n{0}.",
"Case.exceptionMessage.contentProviderCouldNotBeFound=Content provider was specified for the case but could not be loaded.",
"Case.open.exception.multiUserCaseNotEnabled=Cannot open a multi-user case if multi-user cases are not enabled. See Tools, Options, Multi-User."
})
private void openCaseDataBase(ProgressIndicator progressIndicator) throws CaseActionException {
@ -2737,14 +2751,15 @@ public class Case {
String databaseName = metadata.getCaseDatabaseName();
ContentStreamProvider contentProvider = loadContentProvider(metadata.getContentProviderName());
if (StringUtils.isNotBlank(metadata.getContentProviderName()) && contentProvider == null) {
if (metadata.getContentProviderName().trim().toUpperCase().startsWith(CT_PROVIDER_PREFIX.toUpperCase())) {
new CTIntegrationMissingDialog(WindowManager.getDefault().getMainWindow(), true).showDialog(null);
}
throw new CaseActionException(Bundle.Case_exceptionMessage_contentProviderCouldNotBeFound());
}
if (CaseType.SINGLE_USER_CASE == metadata.getCaseType()) {
// only prefix with metadata directory if databaseName is a relative path
String fullDatabasePath = (new File(databaseName).isAbsolute())
? databaseName
: Paths.get(metadata.getCaseDirectory(), databaseName).toString();
caseDb = SleuthkitCase.openCase(fullDatabasePath, contentProvider);
caseDb = SleuthkitCase.openCase(metadata.getCaseDatabasePath(), contentProvider);
} else if (UserPreferences.getIsMultiUserModeEnabled()) {
caseDb = SleuthkitCase.openCase(databaseName, UserPreferences.getDatabaseConnectionInfo(), metadata.getCaseDirectory(), contentProvider);
} else {

View File

@ -29,16 +29,8 @@ import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Collectors;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
@ -51,13 +43,10 @@ import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.openide.util.Lookup;
import org.sleuthkit.autopsy.coreutils.Version;
import org.sleuthkit.autopsy.coreutils.XMLUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
@ -121,7 +110,6 @@ public final class CaseMetadata {
private static final String SCHEMA_VERSION_SIX = "6.0";
private final static String CONTENT_PROVIDER_ELEMENT_NAME = "ContentProvider";
private final static String CONTENT_PROVIDER_NAME_ELEMENT_NAME = "Name";
private final static String CONTENT_PROVIDER_ARG_DEFAULT_KEY = "DEFAULT";
/*
* Unread fields, regenerated on save.
@ -136,7 +124,7 @@ public final class CaseMetadata {
private String caseName;
private CaseDetails caseDetails;
private String caseDatabaseName;
private String caseDatabasePath; // Legacy
private String caseDatabasePath;
private String textIndexName; // Legacy
private String createdDate;
private String createdByVersion;
@ -258,7 +246,9 @@ public final class CaseMetadata {
* @return The case directory.
*/
public String getCaseDirectory() {
return metadataFilePath.getParent().toString();
return StringUtils.isBlank(this.caseDatabasePath)
? metadataFilePath.getParent().toString()
: Paths.get(this.caseDatabasePath).getParent().toString();
}
/**
@ -637,6 +627,7 @@ public final class CaseMetadata {
this.textIndexName = getElementTextContent(caseElement, TEXT_INDEX_ELEMENT, false);
break;
default:
this.caseDatabasePath = getElementTextContent(caseElement, CASE_DB_ABSOLUTE_PATH_ELEMENT_NAME, false);
this.caseDatabaseName = getElementTextContent(caseElement, CASE_DB_NAME_RELATIVE_ELEMENT_NAME, true);
this.textIndexName = getElementTextContent(caseElement, TEXT_INDEX_ELEMENT, false);
break;
@ -650,11 +641,9 @@ public final class CaseMetadata {
*/
Path possibleAbsoluteCaseDbPath = Paths.get(this.caseDatabaseName);
Path caseDirectoryPath = Paths.get(getCaseDirectory());
if (possibleAbsoluteCaseDbPath.getNameCount() > 1) {
if (possibleAbsoluteCaseDbPath.toFile().isAbsolute()) {
this.caseDatabasePath = this.caseDatabaseName;
this.caseDatabaseName = caseDirectoryPath.relativize(possibleAbsoluteCaseDbPath).toString();
} else {
this.caseDatabasePath = caseDirectoryPath.resolve(caseDatabaseName).toAbsolutePath().toString();
}
} catch (ParserConfigurationException | SAXException | IOException ex) {
@ -719,12 +708,12 @@ public final class CaseMetadata {
* @return The full path to the case database file for a single-user case.
*
* @throws UnsupportedOperationException If called for a multi-user case.
* @deprecated Do not use.
*/
@Deprecated
public String getCaseDatabasePath() throws UnsupportedOperationException {
if (Case.CaseType.SINGLE_USER_CASE == caseType) {
return Paths.get(getCaseDirectory(), caseDatabaseName).toString();
return StringUtils.isBlank(this.caseDatabasePath)
? this.metadataFilePath.getParent().resolve(this.caseDatabaseName).toString()
: this.caseDatabasePath;
} else {
throw new UnsupportedOperationException();
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2021 Basis Technology Corp.
* Copyright 2011-2023 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -64,6 +64,7 @@ import static org.sleuthkit.datamodel.BlackboardArtifact.Type.TSK_INTERESTING_IT
import static org.sleuthkit.datamodel.BlackboardArtifact.Type.TSK_TL_EVENT;
import static org.sleuthkit.datamodel.BlackboardArtifact.Type.TSK_ASSOCIATED_OBJECT;
import static org.sleuthkit.datamodel.BlackboardArtifact.Type.TSK_KEYWORD_HIT;
import static org.sleuthkit.datamodel.BlackboardArtifact.Type.TSK_MALWARE;
/**
* Classes for creating nodes for BlackboardArtifacts.
@ -72,7 +73,7 @@ public class Artifacts {
private static final Set<IngestManager.IngestJobEvent> INGEST_JOB_EVENTS_OF_INTEREST
= EnumSet.of(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED);
/**
* Base class for a parent node of artifacts.
*/
@ -242,6 +243,7 @@ public class Artifacts {
*/
@SuppressWarnings("deprecation")
private static TypeNodeKey getTypeKey(BlackboardArtifact.Type type, SleuthkitCase skCase, long dsObjId) {
int typeId = type.getTypeID();
if (TSK_EMAIL_MSG.getTypeID() == typeId) {
EmailExtracted.RootNode emailNode = new EmailExtracted(skCase, dsObjId).new RootNode();
@ -267,7 +269,9 @@ public class Artifacts {
} else if (TSK_HASHSET_HIT.getTypeID() == typeId) {
HashsetHits.RootNode hashsetHits = new HashsetHits(skCase, dsObjId).new RootNode();
return new TypeNodeKey(hashsetHits, TSK_HASHSET_HIT);
} else if (TSK_MALWARE.getTypeID() == typeId) {
MalwareHits.RootNode malwareHits = new MalwareHits(skCase, dsObjId).new RootNode();
return new TypeNodeKey(malwareHits, TSK_MALWARE);
} else {
return new TypeNodeKey(type, dsObjId);
}

View File

@ -60,6 +60,8 @@ public interface AutopsyItemVisitor<T> {
T visit(KeywordHits kh);
T visit(HashsetHits hh);
T visit(MalwareHits mh);
T visit(EmailExtracted ee);
@ -169,6 +171,11 @@ public interface AutopsyItemVisitor<T> {
return defaultVisit(hh);
}
@Override
public T visit(MalwareHits mh) {
return defaultVisit(mh);
}
@Override
public T visit(InterestingHits ih) {
return defaultVisit(ih);

View File

@ -111,6 +111,8 @@ public interface DisplayableItemNodeVisitor<T> {
T visit(HashsetHits.RootNode hhrn);
T visit(HashsetHits.HashsetNameNode hhsn);
T visit(MalwareHits.RootNode mhrn);
T visit(EmailExtracted.RootNode eern);
@ -431,6 +433,11 @@ public interface DisplayableItemNodeVisitor<T> {
return defaultVisit(hhsn);
}
@Override
public T visit(MalwareHits.RootNode mhrn) {
return defaultVisit(mhrn);
}
@Override
public T visit(InterestingHits.RootNode ihrn) {
return defaultVisit(ihrn);

View File

@ -0,0 +1,343 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2023 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.datamodel;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Observable;
import java.util.Observer;
import java.util.Set;
import java.util.logging.Level;
import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.nodes.Sheet;
import org.openide.util.NbBundle;
import org.openide.util.WeakListeners;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.autopsy.datamodel.Artifacts.UpdatableCountTypeNode;
import org.sleuthkit.datamodel.AnalysisResult;
import static org.sleuthkit.datamodel.BlackboardArtifact.Type.TSK_MALWARE;
import org.sleuthkit.datamodel.Score;
/**
* Malware hits node support. Inner classes have all of the nodes in the tree.
*/
public class MalwareHits implements AutopsyVisitableItem {
private static final Logger logger = Logger.getLogger(MalwareHits.class.getName());
private static final Set<IngestManager.IngestJobEvent> INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED);
private static final Set<IngestManager.IngestModuleEvent> INGEST_MODULE_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestModuleEvent.DATA_ADDED);
private SleuthkitCase skCase;
private final MalwareResults malwareResults;
private final long filteringDSObjId; // 0 if not filtering/grouping by data source
/**
* Constructor
*
* @param skCase Case DB
*
*/
public MalwareHits(SleuthkitCase skCase) {
this(skCase, 0);
}
/**
* Constructor
*
* @param skCase Case DB
* @param objId Object id of the data source
*
*/
public MalwareHits(SleuthkitCase skCase, long objId) {
this.skCase = skCase;
this.filteringDSObjId = objId;
malwareResults = new MalwareResults();
}
@Override
public <T> T accept(AutopsyItemVisitor<T> visitor) {
return visitor.visit(this);
}
/**
* Stores all of the malware results in a single class that is observable
* for the child nodes
*/
private class MalwareResults extends Observable implements Observer {
// list of artifacts
// NOTE: the list can be accessed by multiple worker threads and needs to be synchronized
private final Set<Long> malwareHits = new HashSet<>();
MalwareResults() {
addNotify();
update();
}
Set<Long> getArtifactIds() {
synchronized (malwareHits) {
return Collections.unmodifiableSet(malwareHits);
}
}
@SuppressWarnings("deprecation")
final void update() {
synchronized (malwareHits) {
malwareHits.clear();
}
if (skCase == null) {
return;
}
String query = "SELECT blackboard_artifacts.artifact_obj_id " //NON-NLS
+ "FROM blackboard_artifacts,tsk_analysis_results WHERE " //NON-NLS
+ "blackboard_artifacts.artifact_type_id=" + TSK_MALWARE.getTypeID() //NON-NLS
+ " AND tsk_analysis_results.artifact_obj_id=blackboard_artifacts.artifact_obj_id" //NON-NLS
+ " AND (tsk_analysis_results.significance=" + Score.Significance.NOTABLE.getId() //NON-NLS
+ " OR tsk_analysis_results.significance=" + Score.Significance.LIKELY_NOTABLE.getId() + " )"; //NON-NLS
if (filteringDSObjId > 0) {
query += " AND blackboard_artifacts.data_source_obj_id = " + filteringDSObjId; //NON-NLS
}
try (CaseDbQuery dbQuery = skCase.executeQuery(query)) {
ResultSet resultSet = dbQuery.getResultSet();
synchronized (malwareHits) {
while (resultSet.next()) {
long artifactObjId = resultSet.getLong("artifact_obj_id"); //NON-NLS
malwareHits.add(artifactObjId);
}
}
} catch (TskCoreException | SQLException ex) {
logger.log(Level.WARNING, "SQL Exception occurred: ", ex); //NON-NLS
}
setChanged();
notifyObservers();
}
private final PropertyChangeListener pcl = new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
String eventType = evt.getPropertyName();
if (eventType.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) {
/**
* Checking for a current case is a stop gap measure until a
* different way of handling the closing of cases is worked
* out. Currently, remote events may be received for a case
* that is already closed.
*/
try {
Case.getCurrentCaseThrows();
/**
* Due to some unresolved issues with how cases are
* closed, it is possible for the event to have a null
* oldValue if the event is a remote event.
*/
ModuleDataEvent eventData = (ModuleDataEvent) evt.getOldValue();
if (null != eventData && eventData.getBlackboardArtifactType().getTypeID() == TSK_MALWARE.getTypeID()) {
malwareResults.update();
}
} catch (NoCurrentCaseException notUsed) {
/**
* Case is closed, do nothing.
*/
}
} else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString())
|| eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) {
/**
* Checking for a current case is a stop gap measure until a
* different way of handling the closing of cases is worked
* out. Currently, remote events may be received for a case
* that is already closed.
*/
try {
Case.getCurrentCaseThrows();
malwareResults.update();
} catch (NoCurrentCaseException notUsed) {
/**
* Case is closed, do nothing.
*/
}
} else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
// case was closed. Remove listeners so that we don't get called with a stale case handle
if (evt.getNewValue() == null) {
removeNotify();
skCase = null;
}
}
}
};
private final PropertyChangeListener weakPcl = WeakListeners.propertyChange(pcl, null);
protected void addNotify() {
IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, weakPcl);
IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, weakPcl);
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), weakPcl);
}
protected void removeNotify() {
IngestManager.getInstance().removeIngestJobEventListener(weakPcl);
IngestManager.getInstance().removeIngestModuleEventListener(weakPcl);
Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), weakPcl);
}
@Override
protected void finalize() throws Throwable {
super.finalize();
removeNotify();
}
@Override
public void update(Observable o, Object arg) {
update();
}
}
/**
* Top-level node for all malware hits
*/
public class RootNode extends UpdatableCountTypeNode {
public RootNode() {
super(Children.create(new HitFactory(TSK_MALWARE.getDisplayName()), true),
Lookups.singleton(TSK_MALWARE.getDisplayName()),
TSK_MALWARE.getDisplayName(),
filteringDSObjId,
TSK_MALWARE);
super.setName(TSK_MALWARE.getTypeName());
// TODO make an icon
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/artifact-icon.png");
}
@Override
public boolean isLeafTypeNode() {
return true;
}
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
return visitor.visit(this);
}
@Override
protected Sheet createSheet() {
Sheet sheet = super.createSheet();
Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
if (sheetSet == null) {
sheetSet = Sheet.createPropertiesSet();
sheet.put(sheetSet);
}
sheetSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "MalwareHits.createSheet.name.name"),
NbBundle.getMessage(this.getClass(), "MalwareHits.createSheet.name.displayName"),
NbBundle.getMessage(this.getClass(), "MalwareHits.createSheet.name.desc"),
getName()));
return sheet;
}
@Override
public String getItemType() {
return getClass().getName();
}
/**
* When this method is called, the count to be displayed will be
* updated.
*/
@Override
void updateDisplayName() {
super.setDisplayName(TSK_MALWARE.getDisplayName() + " (" + malwareResults.getArtifactIds().size() + ")");
}
}
/**
* Creates the nodes for the malware hits.
*/
private class HitFactory extends BaseChildFactory<AnalysisResult> implements Observer {
private final Map<Long, AnalysisResult> artifactHits = new HashMap<>();
private HitFactory(String nodeName) {
super(nodeName);
}
@Override
protected void onAdd() {
malwareResults.addObserver(this);
}
@Override
protected void onRemove() {
malwareResults.deleteObserver(this);
}
@Override
protected Node createNodeForKey(AnalysisResult key) {
return new BlackboardArtifactNode(key);
}
@Override
public void update(Observable o, Object arg) {
refresh(true);
}
@Override
protected List<AnalysisResult> makeKeys() {
if (skCase != null) {
malwareResults.getArtifactIds().forEach((id) -> {
try {
if (!artifactHits.containsKey(id)) {
AnalysisResult art = skCase.getBlackboard().getAnalysisResultById(id);
//Cache attributes while we are off the EDT.
//See JIRA-5969
art.getAttributes();
artifactHits.put(id, art);
}
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "TSK Exception occurred", ex); //NON-NLS
}
});
return new ArrayList<>(artifactHits.values());
}
return Collections.emptyList();
}
}
}

View File

@ -1,6 +1,6 @@
Manifest-Version: 1.0
OpenIDE-Module: org.sleuthkit.autopsy.corelibs/3
OpenIDE-Module-Implementation-Version: 7
OpenIDE-Module-Implementation-Version: 8
OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/corelibs/Bundle.properties
OpenIDE-Module-Specification-Version: 1.4
AutoUpdate-Show-In-Client: true

View File

@ -144,7 +144,7 @@
<compile-dependency/>
<run-dependency>
<release-version>10</release-version>
<specification-version>10.24</specification-version>
<specification-version>10.25</specification-version>
</run-dependency>
</dependency>
<dependency>
@ -162,7 +162,7 @@
<compile-dependency/>
<run-dependency>
<release-version>6</release-version>
<specification-version>6.6</specification-version>
<specification-version>6.7</specification-version>
</run-dependency>
</dependency>
</module-dependencies>

View File

@ -1,4 +1,4 @@
file.reference.sqlite-jdbc-3.42.0.0.jar=release/modules/ext/sqlite-jdbc-3.42.0.0.jar
file.reference.sqlite-jdbc-3.42.0.1.jar=release/modules/ext/sqlite-jdbc-3.42.0.1.jar
javac.source=17
javac.compilerargs=-Xlint -Xlint:-serial
license.file=LICENSE-2.0.txt

View File

@ -127,7 +127,7 @@
<compile-dependency/>
<run-dependency>
<release-version>10</release-version>
<specification-version>10.24</specification-version>
<specification-version>10.25</specification-version>
</run-dependency>
</dependency>
<dependency>
@ -142,8 +142,8 @@
</module-dependencies>
<public-packages/>
<class-path-extension>
<runtime-relative-path>ext/sqlite-jdbc-3.42.0.0.jar</runtime-relative-path>
<binary-origin>release/modules/ext/sqlite-jdbc-3.42.0.0.jar</binary-origin>
<runtime-relative-path>ext/sqlite-jdbc-3.42.0.1.jar</runtime-relative-path>
<binary-origin>release/modules/ext/sqlite-jdbc-3.42.0.1.jar</binary-origin>
</class-path-extension>
</data>
</configuration>

View File

@ -1,7 +1,7 @@
Manifest-Version: 1.0
AutoUpdate-Show-In-Client: true
OpenIDE-Module: org.sleuthkit.autopsy.keywordsearch/6
OpenIDE-Module-Implementation-Version: 23
OpenIDE-Module-Implementation-Version: 24
OpenIDE-Module-Install: org/sleuthkit/autopsy/keywordsearch/Installer.class
OpenIDE-Module-Layer: org/sleuthkit/autopsy/keywordsearch/layer.xml
OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/keywordsearch/Bundle.properties

View File

@ -48,4 +48,4 @@ javac.compilerargs=-Xlint -Xlint:-serial
license.file=../LICENSE-2.0.txt
nbm.homepage=http://www.sleuthkit.org/autopsy/
nbm.needs.restart=true
spec.version.base=6.6
spec.version.base=6.7

View File

@ -128,7 +128,7 @@
<compile-dependency/>
<run-dependency>
<release-version>10</release-version>
<specification-version>10.24</specification-version>
<specification-version>10.25</specification-version>
</run-dependency>
</dependency>
<dependency>

View File

@ -1,3 +1,32 @@
---------------- VERSION 4.21.0 ---------------
Library Updates
- Update Java to version 17
- Update aLeapp/iLeapp executables.
- Update JNA Version
- Update SQLite library version
- Updated 3rd party libraries that have known CVE's
Ingest Module Updates:
- Recent Activity checks for malicious Chrome extensions from list provided by https://github.com/randomaccess3/detections
- Keyword Search module now can search without needing to index text into Solr.
- New Cyber Triage Malware Scanner module that uses Reversing Labs (requires license). https://www.cybertriage.com/autopsy-malware-module/
Add Data Source Updates:
- Timestamps for logical files can be added. Issue https://github.com/sleuthkit/autopsy/issues/5852, https://github.com/sleuthkit/autopsy/issues/1788
- List of logical files/folders can be edited before they are added. Issue https://github.com/sleuthkit/autopsy/issues/7347
GUI Updates:
- Add "has attachments" flag for emails. Issue https://github.com/sleuthkit/autopsy/issues/7358
- Add Score to tree view
Bugs:
- Fix path for lnk files
- Fix exporting of CSV files. Issue https://github.com/sleuthkit/autopsy/issues/6717
Misc:
- Added File Repository concept for data source files that are in a central location. Required for Cyber Triage import feature.
- Added Spanish language support, contributor https://github.com/AburtoArielPM
---------------- VERSION 4.20.0 --------------
Recent Activity Updates:
- Added Favicons, Profiles and Extensions to Chromium Browsers

View File

@ -1,6 +1,6 @@
Manifest-Version: 1.0
OpenIDE-Module: org.sleuthkit.autopsy.recentactivity/6
OpenIDE-Module-Implementation-Version: 19
OpenIDE-Module-Implementation-Version: 20
OpenIDE-Module-Layer: org/sleuthkit/autopsy/recentactivity/layer.xml
OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/recentactivity/Bundle.properties
OpenIDE-Module-Requires:

View File

@ -1,6 +1,6 @@
javac.source=17
file.reference.Rejistry-1.1-SNAPSHOT.jar=release/modules/ext/Rejistry-1.1-SNAPSHOT.jar
file.reference.sqlite-jdbc-3.42.0.0.jar=release/modules/ext/sqlite-jdbc-3.42.0.0.jar
file.reference.sqlite-jdbc-3.42.0.1.jar=release/modules/ext/sqlite-jdbc-3.42.0.1.jar
javac.compilerargs=-Xlint -Xlint:-serial
license.file=../LICENSE-2.0.txt
nbm.homepage=http://www.sleuthkit.org/autopsy/

View File

@ -88,8 +88,8 @@
<binary-origin>release/modules/ext/Rejistry-1.1-SNAPSHOT.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/sqlite-jdbc-3.42.0.0.jar</runtime-relative-path>
<binary-origin>release/modules/ext/sqlite-jdbc-3.42.0.0.jar</binary-origin>
<runtime-relative-path>ext/sqlite-jdbc-3.42.0.1.jar</runtime-relative-path>
<binary-origin>release/modules/ext/sqlite-jdbc-3.42.0.1.jar</binary-origin>
</class-path-extension>
</data>
</configuration>

View File

@ -1,3 +1,3 @@
<project name="TSK_VERSION">
<property name="TSK_VERSION" value="4.12.0"/>
<property name="TSK_VERSION" value="4.12.1"/>
</project>

View File

@ -47,7 +47,7 @@
<compile-dependency/>
<run-dependency>
<release-version>10</release-version>
<specification-version>10.24</specification-version>
<specification-version>10.25</specification-version>
</run-dependency>
</dependency>
<dependency>
@ -73,7 +73,7 @@
<compile-dependency/>
<run-dependency>
<release-version>6</release-version>
<specification-version>6.6</specification-version>
<specification-version>6.7</specification-version>
</run-dependency>
</dependency>
</module-dependencies>

View File

@ -0,0 +1,63 @@
/*! \page ct_malware_scanner_page Cyber Triage Malware Scanner Module
[TOC]
What Does It Do
========
The Cyber Triage Malware Scanner module will use the malware scanning infrastructure from Cyber Triage to identify if any Windows executables are malware. It will query an online service using the file's hash value to see if the file was already analyzed and allows you to upload files for analysis if they are new.
This module requires a commercial license from Cyber Triage.
For more information on what the module does or obtaining a license, refer to [CyberTriage.com](https://cybertriage.com/autopsy-malware-module). The remainder of this page is about the use of the module once it is licensed.
Configuration
==============
You will need to first get a paid or eval license from the above URL. The code will come in via email. Example license formats include:
- AUT-8ed86eb5-17fc-4b3a-9b75-ce638c11b070
- b826a555-951f-42ca-86ce-439a81106688
Once you have a license, you must add it on the Autopsy Options panel.
Choose the 'Cyber Triage' tab and choose 'Add License'.
\image html malware-scanner-global-options-panel-no-license.png
After you enter the license number from your email, you will then need to review and agree to the license terms.
The options panel should now display information about the lookup limits. You can always refer back to here about what your limits are and when they reset.
\image html malware-scanner-global-options-panel.png
Using the Module
======
Ingest Settings
------
For each data source, you select if you want files to be uploaded if they have not already been analyzed. By default, they are uploaded. You can choose to not upload them though. Refer to the main [website](https://cybertriage.com/autopsy-malware-module) for details on what happens when files are uploaded.
\image html malware-scanner-ingest-panel.png
Out of Scans
-------
If you go beyond your limits, you will get a dialog that not all files were analyzed. You can wait until your limits reset and then start ingest again with only the malware scanning module enabled. It will ignore the files that are already analyzed.
Seeing Results
------
Once ingest has completed, the files with malware will be listed in the Malware node in the tree.
\image html malware-artifact-tree.png
*/

View File

@ -1,5 +1,5 @@
<hr/>
<p><i>Copyright &#169; 2012-2022 Basis Technology. Generated on $date<br/>
<p><i>Copyright &#169; 2012-2023 BasisTech. Generated on $date<br/>
This work is licensed under a
<a rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/us/">Creative Commons Attribution-Share Alike 3.0 United States License</a>.
</i></p>

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

View File

@ -58,6 +58,7 @@ The following topics are available here:
- \subpage ileapp_page
- \subpage aleapp_page
- \subpage yara_page
- \subpage ct_malware_scanner_page
- Reviewing the Results
- \subpage uilayout_page

View File

@ -4,7 +4,7 @@ app.title=Autopsy
### lowercase version of above
app.name=${branding.token}
### if left unset, version will default to today's date
app.version=4.20.0
app.version=4.21.0
### build.type must be one of: DEVELOPMENT, RELEASE
#build.type=RELEASE
build.type=DEVELOPMENT

View File

@ -33,7 +33,7 @@ sub main {
update_core_project_xml();
update_unix_setup();
print "Files updated. You need to commit and push them\n";
print "Files updated and added to git. You need to commit (no -a) and push.\n";
}

View File

@ -54,7 +54,7 @@
<compile-dependency/>
<run-dependency>
<release-version>10</release-version>
<specification-version>10.24</specification-version>
<specification-version>10.25</specification-version>
</run-dependency>
</dependency>
<dependency>

View File

@ -5,7 +5,7 @@
# NOTE: update_sleuthkit_version.pl updates this value and relies
# on it keeping the same name and whitespace. Don't change it.
TSK_VERSION=4.12.0
TSK_VERSION=4.12.1
usage() {