Merge remote-tracking branch 'upstream/accounts_relationships' into build_out_CVT_GUI

This commit is contained in:
millmanorama 2017-10-25 13:38:44 +02:00
commit 1add071855
52 changed files with 2143 additions and 2350 deletions

View File

@ -0,0 +1,29 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2017 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.casemodule;
import javax.swing.JDialog;
/**
* Interface for startup window implementations
*/
public interface AutoIngestCasePanelInterface {
public void addWindowStateListener(JDialog parent);
}

View File

@ -17,13 +17,7 @@ NewCaseVisualPanel1.jLabel2.text_1=Case data will be stored in the following dir
NewCaseVisualPanel1.caseParentDirTextField.text= NewCaseVisualPanel1.caseParentDirTextField.text=
NewCaseVisualPanel1.caseDirTextField.text_1= NewCaseVisualPanel1.caseDirTextField.text_1=
CueBannerPanel.autopsyLogo.text= CueBannerPanel.autopsyLogo.text=
CueBannerPanel.createNewLabel.text=Create New Case
CueBannerPanel.openLabel.text=Open Existing Case
CueBannerPanel.closeButton.text=Close CueBannerPanel.closeButton.text=Close
CueBannerPanel.openRecentLabel.text=Open Recent Case
CueBannerPanel.newCaseButton.text=
CueBannerPanel.openCaseButton.text=
CueBannerPanel.openRecentButton.text=
OpenRecentCasePanel.cancelButton.text=Cancel OpenRecentCasePanel.cancelButton.text=Cancel
OpenRecentCasePanel.jLabel1.text=Recent Cases OpenRecentCasePanel.jLabel1.text=Recent Cases
NewCaseVisualPanel2.caseNumberTextField.text= NewCaseVisualPanel2.caseNumberTextField.text=
@ -225,3 +219,11 @@ CasePropertiesPanel.lbDbType.text=Case Type:
CasePropertiesPanel.examinerLabel.text=Examiner: CasePropertiesPanel.examinerLabel.text=Examiner:
CasePropertiesPanel.caseNumberLabel.text=Case Number: CasePropertiesPanel.caseNumberLabel.text=Case Number:
LocalDiskPanel.changeDatabasePathCheckbox.text=Update case to use VHD file upon completion LocalDiskPanel.changeDatabasePathCheckbox.text=Update case to use VHD file upon completion
CueBannerPanel.openAutoIngestCaseButton.text=
CueBannerPanel.openExistingCaseButton.text=
CueBannerPanel.openRecentCaseButton.text=
CueBannerPanel.createNewCaseButton.text=
CueBannerPanel.createNewCaseLabel.text=Create New Case
CueBannerPanel.openRecentCaseLabel.text=Open Recent Case
CueBannerPanel.openExistingCaseLabel.text=Open Existing Case
CueBannerPanel.openAutoIngestCaseLabel.text=Open Auto Ingest Case

View File

@ -12,10 +12,7 @@ NewCaseVisualPanel1.caseNameLabel.text_1=\u30b1\u30fc\u30b9\u540d\uff1a
NewCaseVisualPanel1.caseDirLabel.text=\u30d9\u30fc\u30b9\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\uff1a NewCaseVisualPanel1.caseDirLabel.text=\u30d9\u30fc\u30b9\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\uff1a
NewCaseVisualPanel1.caseDirBrowseButton.text=\u95b2\u89a7 NewCaseVisualPanel1.caseDirBrowseButton.text=\u95b2\u89a7
NewCaseVisualPanel1.jLabel2.text_1=\u30b1\u30fc\u30b9\u30c7\u30fc\u30bf\u306f\u6b21\u306e\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u306b\u4fdd\u5b58\u3055\u308c\u307e\u3059\uff1a NewCaseVisualPanel1.jLabel2.text_1=\u30b1\u30fc\u30b9\u30c7\u30fc\u30bf\u306f\u6b21\u306e\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u306b\u4fdd\u5b58\u3055\u308c\u307e\u3059\uff1a
CueBannerPanel.createNewLabel.text=\u65b0\u898f\u30b1\u30fc\u30b9\u3092\u4f5c\u6210
CueBannerPanel.openLabel.text=\u65e2\u5b58\u30b1\u30fc\u30b9\u3092\u958b\u304f
CueBannerPanel.closeButton.text=\u9589\u3058\u308b CueBannerPanel.closeButton.text=\u9589\u3058\u308b
CueBannerPanel.openRecentLabel.text=\u6700\u8fd1\u958b\u3044\u305f\u30b1\u30fc\u30b9\u3092\u958b\u304f
OpenRecentCasePanel.cancelButton.text=\u30ad\u30e3\u30f3\u30bb\u30eb OpenRecentCasePanel.cancelButton.text=\u30ad\u30e3\u30f3\u30bb\u30eb
OpenRecentCasePanel.jLabel1.text=\u6700\u8fd1\u958b\u3044\u305f\u30d5\u30a1\u30a4\u30eb OpenRecentCasePanel.jLabel1.text=\u6700\u8fd1\u958b\u3044\u305f\u30d5\u30a1\u30a4\u30eb
NewCaseVisualPanel2.examinerLabel.text=\u8abf\u67fb\u62c5\u5f53\u8005\uff1a NewCaseVisualPanel2.examinerLabel.text=\u8abf\u67fb\u62c5\u5f53\u8005\uff1a
@ -196,3 +193,7 @@ CasePropertiesPanel.lbDbName.text=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u540d\uff
CasePropertiesPanel.lbDbType.text=\u30b1\u30fc\u30b9\u30bf\u30a4\u30d7\uff1a CasePropertiesPanel.lbDbType.text=\u30b1\u30fc\u30b9\u30bf\u30a4\u30d7\uff1a
CasePropertiesPanel.examinerLabel.text=\u8abf\u67fb\u62c5\u5f53\u8005\uff1a CasePropertiesPanel.examinerLabel.text=\u8abf\u67fb\u62c5\u5f53\u8005\uff1a
CasePropertiesPanel.caseNumberLabel.text=\u30b1\u30fc\u30b9\u756a\u53f7\uff1a CasePropertiesPanel.caseNumberLabel.text=\u30b1\u30fc\u30b9\u756a\u53f7\uff1a
CueBannerPanel.createNewCaseLabel.text=\u65b0\u898f\u30b1\u30fc\u30b9\u3092\u4f5c\u6210
CueBannerPanel.openRecentCaseLabel.text=\u6700\u8fd1\u958b\u3044\u305f\u30b1\u30fc\u30b9\u3092\u958b\u304f
CueBannerPanel.openExistingCaseLabel.text=\u65e2\u5b58\u30b1\u30fc\u30b9\u3092\u958b\u304f
CueBannerPanel.openAutoIngestCaseLabel.text=\u65e2\u5b58\u30b1\u30fc\u30b9\u3092\u958b\u304f

View File

@ -16,23 +16,27 @@
<Layout> <Layout>
<DimensionLayout dim="0"> <DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0"> <Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="autopsyLogo" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="jSeparator1" min="-2" pref="5" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="2" attributes="0">
<Component id="newCaseButton" alignment="2" min="-2" max="-2" attributes="1"/>
<Component id="openRecentButton" alignment="2" min="-2" pref="70" max="-2" attributes="1"/>
<Component id="openCaseButton" alignment="2" min="-2" max="-2" attributes="1"/>
</Group>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Group type="103" alignment="1" groupAlignment="0" attributes="0"> <Group type="102" alignment="0" attributes="0">
<Component id="createNewLabel" alignment="0" min="-2" max="-2" attributes="0"/> <Component id="autopsyLogo" min="-2" max="-2" attributes="0"/>
<Component id="openRecentLabel" alignment="0" min="-2" max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Component id="openLabel" alignment="0" min="-2" max="-2" attributes="0"/> <Component id="jSeparator1" min="-2" pref="5" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="2" attributes="0">
<Component id="createNewCaseButton" alignment="2" min="-2" max="-2" attributes="1"/>
<Component id="openRecentCaseButton" alignment="2" min="-2" pref="70" max="-2" attributes="1"/>
<Component id="openExistingCaseButton" alignment="2" min="-2" max="-2" attributes="1"/>
<Component id="openAutoIngestCaseButton" alignment="2" min="-2" max="-2" attributes="1"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="createNewCaseLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="openRecentCaseLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="openExistingCaseLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="openAutoIngestCaseLabel" min="-2" max="-2" attributes="0"/>
</Group>
</Group> </Group>
<Component id="closeButton" alignment="1" min="-2" pref="73" max="-2" attributes="0"/> <Component id="closeButton" alignment="1" min="-2" pref="73" max="-2" attributes="0"/>
</Group> </Group>
@ -47,25 +51,33 @@
<Group type="103" groupAlignment="0" max="-2" attributes="0"> <Group type="103" groupAlignment="0" max="-2" attributes="0">
<Group type="102" attributes="0"> <Group type="102" attributes="0">
<Group type="103" groupAlignment="2" attributes="0"> <Group type="103" groupAlignment="2" attributes="0">
<Component id="newCaseButton" alignment="2" min="-2" pref="56" max="-2" attributes="0"/> <Component id="createNewCaseButton" alignment="2" min="-2" pref="56" max="-2" attributes="0"/>
<Component id="createNewLabel" alignment="2" min="-2" max="-2" attributes="0"/> <Component id="createNewCaseLabel" alignment="2" min="-2" max="-2" attributes="0"/>
</Group> </Group>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="2" attributes="0"> <Group type="103" groupAlignment="2" attributes="0">
<Component id="openRecentButton" alignment="2" min="-2" pref="70" max="-2" attributes="0"/> <Component id="openRecentCaseButton" alignment="2" min="-2" pref="70" max="-2" attributes="0"/>
<Component id="openRecentLabel" alignment="2" min="-2" max="-2" attributes="0"/> <Component id="openRecentCaseLabel" alignment="2" min="-2" max="-2" attributes="0"/>
</Group> </Group>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="2" attributes="0"> <Group type="103" groupAlignment="2" attributes="0">
<Component id="openCaseButton" alignment="2" min="-2" pref="58" max="-2" attributes="0"/> <Component id="openExistingCaseButton" alignment="2" min="-2" pref="58" max="-2" attributes="0"/>
<Component id="openLabel" alignment="2" min="-2" max="-2" attributes="0"/> <Component id="openExistingCaseLabel" alignment="2" min="-2" max="-2" attributes="0"/>
</Group> </Group>
<EmptySpace max="32767" attributes="0"/> <EmptySpace max="32767" attributes="0"/>
<Component id="closeButton" min="-2" max="-2" attributes="0"/> <Group type="103" groupAlignment="0" attributes="0">
<Component id="openAutoIngestCaseButton" alignment="1" min="-2" pref="58" max="-2" attributes="0"/>
<Group type="102" alignment="1" attributes="0">
<Component id="openAutoIngestCaseLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="20" max="-2" attributes="0"/>
</Group>
</Group>
</Group> </Group>
<Component id="jSeparator1" alignment="0" max="32767" attributes="0"/> <Component id="jSeparator1" alignment="0" max="32767" attributes="0"/>
<Component id="autopsyLogo" alignment="0" min="-2" pref="257" max="-2" attributes="0"/> <Component id="autopsyLogo" alignment="0" min="-2" pref="257" max="-2" attributes="0"/>
</Group> </Group>
<EmptySpace pref="10" max="32767" attributes="0"/>
<Component id="closeButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
</Group> </Group>
</Group> </Group>
@ -85,13 +97,13 @@
<AuxValue name="JavaCodeGenerator_CreateCodePost" type="java.lang.String" value="this.autopsyLogo.setText(&quot;&quot;);"/> <AuxValue name="JavaCodeGenerator_CreateCodePost" type="java.lang.String" value="this.autopsyLogo.setText(&quot;&quot;);"/>
</AuxValues> </AuxValues>
</Component> </Component>
<Component class="javax.swing.JButton" name="newCaseButton"> <Component class="javax.swing.JButton" name="createNewCaseButton">
<Properties> <Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor"> <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/casemodule/btn_icon_create_new_case.png"/> <Image iconType="3" name="/org/sleuthkit/autopsy/casemodule/btn_icon_create_new_case.png"/>
</Property> </Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="CueBannerPanel.newCaseButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/> <ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="CueBannerPanel.createNewCaseButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property> </Property>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.RADConnectionPropertyEditor"> <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="null" type="code"/> <Connection code="null" type="code"/>
@ -103,16 +115,16 @@
</Property> </Property>
</Properties> </Properties>
<Events> <Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="newCaseButtonActionPerformed"/> <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="createNewCaseButtonActionPerformed"/>
</Events> </Events>
</Component> </Component>
<Component class="javax.swing.JButton" name="openRecentButton"> <Component class="javax.swing.JButton" name="openRecentCaseButton">
<Properties> <Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor"> <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/casemodule/btn_icon_open_recent.png"/> <Image iconType="3" name="/org/sleuthkit/autopsy/casemodule/btn_icon_open_recent.png"/>
</Property> </Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="CueBannerPanel.openRecentButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/> <ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="CueBannerPanel.openRecentCaseButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property> </Property>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.RADConnectionPropertyEditor"> <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="null" type="code"/> <Connection code="null" type="code"/>
@ -124,40 +136,40 @@
</Property> </Property>
</Properties> </Properties>
<Events> <Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="openRecentButtonActionPerformed"/> <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="openRecentCaseButtonActionPerformed"/>
</Events> </Events>
</Component> </Component>
<Component class="javax.swing.JLabel" name="createNewLabel"> <Component class="javax.swing.JLabel" name="createNewCaseLabel">
<Properties> <Properties>
<Property name="font" type="java.awt.Font" editor="org.netbeans.modules.form.editors2.FontEditor"> <Property name="font" type="java.awt.Font" editor="org.netbeans.modules.form.editors2.FontEditor">
<FontInfo relative="true"> <FontInfo relative="true">
<Font bold="false" component="createNewLabel" property="font" relativeSize="false" size="13"/> <Font bold="false" component="createNewCaseLabel" property="font" relativeSize="false" size="13"/>
</FontInfo> </FontInfo>
</Property> </Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="CueBannerPanel.createNewLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/> <ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="CueBannerPanel.createNewCaseLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property> </Property>
</Properties> </Properties>
</Component> </Component>
<Component class="javax.swing.JLabel" name="openRecentLabel"> <Component class="javax.swing.JLabel" name="openRecentCaseLabel">
<Properties> <Properties>
<Property name="font" type="java.awt.Font" editor="org.netbeans.modules.form.editors2.FontEditor"> <Property name="font" type="java.awt.Font" editor="org.netbeans.modules.form.editors2.FontEditor">
<FontInfo relative="true"> <FontInfo relative="true">
<Font bold="false" component="openRecentLabel" property="font" relativeSize="false" size="13"/> <Font bold="false" component="openRecentCaseLabel" property="font" relativeSize="false" size="13"/>
</FontInfo> </FontInfo>
</Property> </Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="CueBannerPanel.openRecentLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/> <ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="CueBannerPanel.openRecentCaseLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property> </Property>
</Properties> </Properties>
</Component> </Component>
<Component class="javax.swing.JButton" name="openCaseButton"> <Component class="javax.swing.JButton" name="openExistingCaseButton">
<Properties> <Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor"> <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/casemodule/btn_icon_open_existing.png"/> <Image iconType="3" name="/org/sleuthkit/autopsy/casemodule/btn_icon_open_existing.png"/>
</Property> </Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="CueBannerPanel.openCaseButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/> <ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="CueBannerPanel.openExistingCaseButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property> </Property>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.RADConnectionPropertyEditor"> <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="null" type="code"/> <Connection code="null" type="code"/>
@ -172,18 +184,18 @@
</Property> </Property>
</Properties> </Properties>
<Events> <Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="openCaseButtonActionPerformed"/> <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="openExistingCaseButtonActionPerformed"/>
</Events> </Events>
</Component> </Component>
<Component class="javax.swing.JLabel" name="openLabel"> <Component class="javax.swing.JLabel" name="openExistingCaseLabel">
<Properties> <Properties>
<Property name="font" type="java.awt.Font" editor="org.netbeans.modules.form.editors2.FontEditor"> <Property name="font" type="java.awt.Font" editor="org.netbeans.modules.form.editors2.FontEditor">
<FontInfo relative="true"> <FontInfo relative="true">
<Font bold="false" component="openLabel" property="font" relativeSize="false" size="13"/> <Font bold="false" component="openExistingCaseLabel" property="font" relativeSize="false" size="13"/>
</FontInfo> </FontInfo>
</Property> </Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="CueBannerPanel.openLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/> <ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="CueBannerPanel.openExistingCaseLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property> </Property>
</Properties> </Properties>
</Component> </Component>
@ -204,5 +216,41 @@
<Property name="orientation" type="int" value="1"/> <Property name="orientation" type="int" value="1"/>
</Properties> </Properties>
</Component> </Component>
<Component class="javax.swing.JButton" name="openAutoIngestCaseButton">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/casemodule/btn_icon_open_existing.png"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="CueBannerPanel.openAutoIngestCaseButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="null" type="code"/>
</Property>
<Property name="borderPainted" type="boolean" value="false"/>
<Property name="contentAreaFilled" type="boolean" value="false"/>
<Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
<Insets value="[1, 1, 1, 1]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[64, 64]"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="openAutoIngestCaseButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="openAutoIngestCaseLabel">
<Properties>
<Property name="font" type="java.awt.Font" editor="org.netbeans.modules.form.editors2.FontEditor">
<FontInfo relative="true">
<Font bold="false" component="openAutoIngestCaseLabel" property="font" relativeSize="false" size="13"/>
</FontInfo>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="CueBannerPanel.openAutoIngestCaseLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
</SubComponents> </SubComponents>
</Form> </Form>

View File

@ -26,10 +26,14 @@ import java.awt.event.KeyEvent;
import javax.swing.ImageIcon; import javax.swing.ImageIcon;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JDialog; import javax.swing.JDialog;
import javax.swing.JPanel;
import javax.swing.KeyStroke; import javax.swing.KeyStroke;
import org.openide.util.Lookup; import org.openide.util.Lookup;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.openide.windows.WindowManager; import org.openide.windows.WindowManager;
import org.sleuthkit.autopsy.casemodule.AutoIngestCasePanelInterface;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.coreutils.NetworkUtils;
/* /*
* The panel in the default Autopsy startup window. * The panel in the default Autopsy startup window.
@ -37,11 +41,14 @@ import org.openide.windows.WindowManager;
public class CueBannerPanel extends javax.swing.JPanel { public class CueBannerPanel extends javax.swing.JPanel {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private static final String LOCAL_HOST_NAME = NetworkUtils.getLocalHostName();
private static final String REVIEW_MODE_TITLE = "Cases" + " (" + LOCAL_HOST_NAME + ")";
/* /*
* This is field is static for the sake of the closeOpenRecentCasesWindow * This is field is static for the sake of the closeOpenRecentCasesWindow
* method. * method.
*/ */
private static JDialog recentCasesWindow; private static JDialog recentCasesWindow;
private static JDialog autoIngestCasePanelWindow;
public static void closeOpenRecentCasesWindow() { public static void closeOpenRecentCasesWindow() {
if (null != recentCasesWindow) { if (null != recentCasesWindow) {
@ -49,6 +56,12 @@ public class CueBannerPanel extends javax.swing.JPanel {
} }
} }
public static void closeAutoIngestCasesWindow() {
if (null != autoIngestCasePanelWindow) {
autoIngestCasePanelWindow.setVisible(false);
}
}
public CueBannerPanel() { public CueBannerPanel() {
initComponents(); initComponents();
customizeComponents(); customizeComponents();
@ -77,8 +90,13 @@ public class CueBannerPanel extends javax.swing.JPanel {
public void refresh() { public void refresh() {
enableComponents(); enableComponents();
} }
private void customizeComponents() { private void customizeComponents() {
initRecentCasesWindow();
initAutoIngestCasesWindow();
}
private void initRecentCasesWindow() {
recentCasesWindow = new JDialog( recentCasesWindow = new JDialog(
WindowManager.getDefault().getMainWindow(), WindowManager.getDefault().getMainWindow(),
NbBundle.getMessage(CueBannerPanel.class, "CueBannerPanel.title.text"), NbBundle.getMessage(CueBannerPanel.class, "CueBannerPanel.title.text"),
@ -100,15 +118,39 @@ public class CueBannerPanel extends javax.swing.JPanel {
recentCasesWindow.pack(); recentCasesWindow.pack();
recentCasesWindow.setResizable(false); recentCasesWindow.setResizable(false);
} }
private void initAutoIngestCasesWindow() {
autoIngestCasePanelWindow = new JDialog(
WindowManager.getDefault().getMainWindow(),
REVIEW_MODE_TITLE,
Dialog.ModalityType.APPLICATION_MODAL);
autoIngestCasePanelWindow.getRootPane().registerKeyboardAction(
e -> {
autoIngestCasePanelWindow.setVisible(false);
},
KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_IN_FOCUSED_WINDOW);
OpenRecentCasePanel recentCasesPanel = OpenRecentCasePanel.getInstance();
recentCasesPanel.setCloseButtonActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
autoIngestCasePanelWindow.setVisible(false);
}
});
AutoIngestCasePanelInterface autoIngestCasePanel = Lookup.getDefault().lookup(AutoIngestCasePanelInterface.class);
autoIngestCasePanel.addWindowStateListener(autoIngestCasePanelWindow);
autoIngestCasePanelWindow.add((JPanel)autoIngestCasePanel);
autoIngestCasePanelWindow.pack();
autoIngestCasePanelWindow.setResizable(false);
}
private void enableComponents() { private void enableComponents() {
if (RecentCases.getInstance().getTotalRecentCases() == 0) { boolean enableOpenRecentCaseButton = (RecentCases.getInstance().getTotalRecentCases() > 0);
openRecentButton.setEnabled(false); openRecentCaseButton.setEnabled(enableOpenRecentCaseButton);
openRecentLabel.setEnabled(false); openRecentCaseLabel.setEnabled(enableOpenRecentCaseButton);
} else {
openRecentButton.setEnabled(true); boolean showOpenAutoIngestCaseButton = (UserPreferences.getMode() == UserPreferences.SelectedMode.REVIEW);
openRecentLabel.setEnabled(true); openAutoIngestCaseButton.setVisible(showOpenAutoIngestCaseButton);
} openAutoIngestCaseLabel.setVisible(showOpenAutoIngestCaseButton);
} }
/** /**
@ -122,89 +164,110 @@ public class CueBannerPanel extends javax.swing.JPanel {
autopsyLogo = new javax.swing.JLabel(); autopsyLogo = new javax.swing.JLabel();
this.autopsyLogo.setText(""); this.autopsyLogo.setText("");
newCaseButton = new javax.swing.JButton(); createNewCaseButton = new javax.swing.JButton();
openRecentButton = new javax.swing.JButton(); openRecentCaseButton = new javax.swing.JButton();
createNewLabel = new javax.swing.JLabel(); createNewCaseLabel = new javax.swing.JLabel();
openRecentLabel = new javax.swing.JLabel(); openRecentCaseLabel = new javax.swing.JLabel();
openCaseButton = new javax.swing.JButton(); openExistingCaseButton = new javax.swing.JButton();
openLabel = new javax.swing.JLabel(); openExistingCaseLabel = new javax.swing.JLabel();
closeButton = new javax.swing.JButton(); closeButton = new javax.swing.JButton();
jSeparator1 = new javax.swing.JSeparator(); jSeparator1 = new javax.swing.JSeparator();
openAutoIngestCaseButton = new javax.swing.JButton();
openAutoIngestCaseLabel = new javax.swing.JLabel();
autopsyLogo.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/casemodule/welcome_logo.png"))); // NOI18N autopsyLogo.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/casemodule/welcome_logo.png"))); // NOI18N
autopsyLogo.setText(org.openide.util.NbBundle.getMessage(CueBannerPanel.class, "CueBannerPanel.autopsyLogo.text")); // NOI18N autopsyLogo.setText(org.openide.util.NbBundle.getMessage(CueBannerPanel.class, "CueBannerPanel.autopsyLogo.text")); // NOI18N
newCaseButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/casemodule/btn_icon_create_new_case.png"))); // NOI18N createNewCaseButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/casemodule/btn_icon_create_new_case.png"))); // NOI18N
newCaseButton.setText(org.openide.util.NbBundle.getMessage(CueBannerPanel.class, "CueBannerPanel.newCaseButton.text")); // NOI18N createNewCaseButton.setText(org.openide.util.NbBundle.getMessage(CueBannerPanel.class, "CueBannerPanel.createNewCaseButton.text")); // NOI18N
newCaseButton.setBorder(null); createNewCaseButton.setBorder(null);
newCaseButton.setBorderPainted(false); createNewCaseButton.setBorderPainted(false);
newCaseButton.setContentAreaFilled(false); createNewCaseButton.setContentAreaFilled(false);
newCaseButton.setPreferredSize(new java.awt.Dimension(64, 64)); createNewCaseButton.setPreferredSize(new java.awt.Dimension(64, 64));
newCaseButton.addActionListener(new java.awt.event.ActionListener() { createNewCaseButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) { public void actionPerformed(java.awt.event.ActionEvent evt) {
newCaseButtonActionPerformed(evt); createNewCaseButtonActionPerformed(evt);
} }
}); });
openRecentButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/casemodule/btn_icon_open_recent.png"))); // NOI18N openRecentCaseButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/casemodule/btn_icon_open_recent.png"))); // NOI18N
openRecentButton.setText(org.openide.util.NbBundle.getMessage(CueBannerPanel.class, "CueBannerPanel.openRecentButton.text")); // NOI18N openRecentCaseButton.setText(org.openide.util.NbBundle.getMessage(CueBannerPanel.class, "CueBannerPanel.openRecentCaseButton.text")); // NOI18N
openRecentButton.setBorder(null); openRecentCaseButton.setBorder(null);
openRecentButton.setBorderPainted(false); openRecentCaseButton.setBorderPainted(false);
openRecentButton.setContentAreaFilled(false); openRecentCaseButton.setContentAreaFilled(false);
openRecentButton.setPreferredSize(new java.awt.Dimension(64, 64)); openRecentCaseButton.setPreferredSize(new java.awt.Dimension(64, 64));
openRecentButton.addActionListener(new java.awt.event.ActionListener() { openRecentCaseButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) { public void actionPerformed(java.awt.event.ActionEvent evt) {
openRecentButtonActionPerformed(evt); openRecentCaseButtonActionPerformed(evt);
} }
}); });
createNewLabel.setFont(createNewLabel.getFont().deriveFont(createNewLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 13)); createNewCaseLabel.setFont(createNewCaseLabel.getFont().deriveFont(createNewCaseLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 13));
createNewLabel.setText(org.openide.util.NbBundle.getMessage(CueBannerPanel.class, "CueBannerPanel.createNewLabel.text")); // NOI18N createNewCaseLabel.setText(org.openide.util.NbBundle.getMessage(CueBannerPanel.class, "CueBannerPanel.createNewCaseLabel.text")); // NOI18N
openRecentLabel.setFont(openRecentLabel.getFont().deriveFont(openRecentLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 13)); openRecentCaseLabel.setFont(openRecentCaseLabel.getFont().deriveFont(openRecentCaseLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 13));
openRecentLabel.setText(org.openide.util.NbBundle.getMessage(CueBannerPanel.class, "CueBannerPanel.openRecentLabel.text")); // NOI18N openRecentCaseLabel.setText(org.openide.util.NbBundle.getMessage(CueBannerPanel.class, "CueBannerPanel.openRecentCaseLabel.text")); // NOI18N
openCaseButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/casemodule/btn_icon_open_existing.png"))); // NOI18N openExistingCaseButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/casemodule/btn_icon_open_existing.png"))); // NOI18N
openCaseButton.setText(org.openide.util.NbBundle.getMessage(CueBannerPanel.class, "CueBannerPanel.openCaseButton.text")); // NOI18N openExistingCaseButton.setText(org.openide.util.NbBundle.getMessage(CueBannerPanel.class, "CueBannerPanel.openExistingCaseButton.text")); // NOI18N
openCaseButton.setBorder(null); openExistingCaseButton.setBorder(null);
openCaseButton.setBorderPainted(false); openExistingCaseButton.setBorderPainted(false);
openCaseButton.setContentAreaFilled(false); openExistingCaseButton.setContentAreaFilled(false);
openCaseButton.setMargin(new java.awt.Insets(1, 1, 1, 1)); openExistingCaseButton.setMargin(new java.awt.Insets(1, 1, 1, 1));
openCaseButton.setPreferredSize(new java.awt.Dimension(64, 64)); openExistingCaseButton.setPreferredSize(new java.awt.Dimension(64, 64));
openCaseButton.addActionListener(new java.awt.event.ActionListener() { openExistingCaseButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) { public void actionPerformed(java.awt.event.ActionEvent evt) {
openCaseButtonActionPerformed(evt); openExistingCaseButtonActionPerformed(evt);
} }
}); });
openLabel.setFont(openLabel.getFont().deriveFont(openLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 13)); openExistingCaseLabel.setFont(openExistingCaseLabel.getFont().deriveFont(openExistingCaseLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 13));
openLabel.setText(org.openide.util.NbBundle.getMessage(CueBannerPanel.class, "CueBannerPanel.openLabel.text")); // NOI18N openExistingCaseLabel.setText(org.openide.util.NbBundle.getMessage(CueBannerPanel.class, "CueBannerPanel.openExistingCaseLabel.text")); // NOI18N
closeButton.setFont(closeButton.getFont().deriveFont(closeButton.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); closeButton.setFont(closeButton.getFont().deriveFont(closeButton.getFont().getStyle() & ~java.awt.Font.BOLD, 11));
closeButton.setText(org.openide.util.NbBundle.getMessage(CueBannerPanel.class, "CueBannerPanel.closeButton.text")); // NOI18N closeButton.setText(org.openide.util.NbBundle.getMessage(CueBannerPanel.class, "CueBannerPanel.closeButton.text")); // NOI18N
jSeparator1.setOrientation(javax.swing.SwingConstants.VERTICAL); jSeparator1.setOrientation(javax.swing.SwingConstants.VERTICAL);
openAutoIngestCaseButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/casemodule/btn_icon_open_existing.png"))); // NOI18N
openAutoIngestCaseButton.setText(org.openide.util.NbBundle.getMessage(CueBannerPanel.class, "CueBannerPanel.openAutoIngestCaseButton.text")); // NOI18N
openAutoIngestCaseButton.setBorder(null);
openAutoIngestCaseButton.setBorderPainted(false);
openAutoIngestCaseButton.setContentAreaFilled(false);
openAutoIngestCaseButton.setMargin(new java.awt.Insets(1, 1, 1, 1));
openAutoIngestCaseButton.setPreferredSize(new java.awt.Dimension(64, 64));
openAutoIngestCaseButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
openAutoIngestCaseButtonActionPerformed(evt);
}
});
openAutoIngestCaseLabel.setFont(openAutoIngestCaseLabel.getFont().deriveFont(openAutoIngestCaseLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 13));
openAutoIngestCaseLabel.setText(org.openide.util.NbBundle.getMessage(CueBannerPanel.class, "CueBannerPanel.openAutoIngestCaseLabel.text")); // NOI18N
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout); this.setLayout(layout);
layout.setHorizontalGroup( layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup() .addGroup(layout.createSequentialGroup()
.addContainerGap() .addContainerGap()
.addComponent(autopsyLogo)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 5, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER)
.addComponent(newCaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(openRecentButton, javax.swing.GroupLayout.PREFERRED_SIZE, 70, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(openCaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup()
.addComponent(createNewLabel) .addComponent(autopsyLogo)
.addComponent(openRecentLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(openLabel)) .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 5, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER)
.addComponent(createNewCaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(openRecentCaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, 70, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(openExistingCaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(openAutoIngestCaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(createNewCaseLabel)
.addComponent(openRecentCaseLabel)
.addComponent(openExistingCaseLabel)
.addComponent(openAutoIngestCaseLabel)))
.addComponent(closeButton, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 73, javax.swing.GroupLayout.PREFERRED_SIZE)) .addComponent(closeButton, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 73, javax.swing.GroupLayout.PREFERRED_SIZE))
.addContainerGap()) .addContainerGap())
); );
@ -215,48 +278,61 @@ public class CueBannerPanel extends javax.swing.JPanel {
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addGroup(layout.createSequentialGroup() .addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER)
.addComponent(newCaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, 56, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(createNewCaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, 56, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(createNewLabel)) .addComponent(createNewCaseLabel))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER)
.addComponent(openRecentButton, javax.swing.GroupLayout.PREFERRED_SIZE, 70, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(openRecentCaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, 70, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(openRecentLabel)) .addComponent(openRecentCaseLabel))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER)
.addComponent(openCaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, 58, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(openExistingCaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, 58, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(openLabel)) .addComponent(openExistingCaseLabel))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(closeButton)) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(openAutoIngestCaseButton, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 58, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addComponent(openAutoIngestCaseLabel)
.addGap(20, 20, 20))))
.addComponent(jSeparator1) .addComponent(jSeparator1)
.addComponent(autopsyLogo, javax.swing.GroupLayout.PREFERRED_SIZE, 257, javax.swing.GroupLayout.PREFERRED_SIZE)) .addComponent(autopsyLogo, javax.swing.GroupLayout.PREFERRED_SIZE, 257, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 10, Short.MAX_VALUE)
.addComponent(closeButton)
.addContainerGap()) .addContainerGap())
); );
}// </editor-fold>//GEN-END:initComponents }// </editor-fold>//GEN-END:initComponents
private void newCaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newCaseButtonActionPerformed private void createNewCaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_createNewCaseButtonActionPerformed
Lookup.getDefault().lookup(CaseNewActionInterface.class).actionPerformed(evt); Lookup.getDefault().lookup(CaseNewActionInterface.class).actionPerformed(evt);
}//GEN-LAST:event_newCaseButtonActionPerformed }//GEN-LAST:event_createNewCaseButtonActionPerformed
private void openCaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openCaseButtonActionPerformed private void openExistingCaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openExistingCaseButtonActionPerformed
Lookup.getDefault().lookup(CaseOpenAction.class).actionPerformed(evt); Lookup.getDefault().lookup(CaseOpenAction.class).actionPerformed(evt);
}//GEN-LAST:event_openCaseButtonActionPerformed }//GEN-LAST:event_openExistingCaseButtonActionPerformed
private void openRecentButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openRecentButtonActionPerformed private void openRecentCaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openRecentCaseButtonActionPerformed
recentCasesWindow.setLocationRelativeTo(WindowManager.getDefault().getMainWindow()); recentCasesWindow.setLocationRelativeTo(WindowManager.getDefault().getMainWindow());
OpenRecentCasePanel.getInstance(); //refreshes the recent cases table OpenRecentCasePanel.getInstance(); //refreshes the recent cases table
recentCasesWindow.setVisible(true); recentCasesWindow.setVisible(true);
}//GEN-LAST:event_openRecentButtonActionPerformed }//GEN-LAST:event_openRecentCaseButtonActionPerformed
private void openAutoIngestCaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openAutoIngestCaseButtonActionPerformed
autoIngestCasePanelWindow.setLocationRelativeTo(WindowManager.getDefault().getMainWindow());
autoIngestCasePanelWindow.setVisible(true);
}//GEN-LAST:event_openAutoIngestCaseButtonActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables // Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JLabel autopsyLogo; private javax.swing.JLabel autopsyLogo;
private javax.swing.JButton closeButton; private javax.swing.JButton closeButton;
private javax.swing.JLabel createNewLabel; private javax.swing.JButton createNewCaseButton;
private javax.swing.JLabel createNewCaseLabel;
private javax.swing.JSeparator jSeparator1; private javax.swing.JSeparator jSeparator1;
private javax.swing.JButton newCaseButton; private javax.swing.JButton openAutoIngestCaseButton;
private javax.swing.JButton openCaseButton; private javax.swing.JLabel openAutoIngestCaseLabel;
private javax.swing.JLabel openLabel; private javax.swing.JButton openExistingCaseButton;
private javax.swing.JButton openRecentButton; private javax.swing.JLabel openExistingCaseLabel;
private javax.swing.JLabel openRecentLabel; private javax.swing.JButton openRecentCaseButton;
private javax.swing.JLabel openRecentCaseLabel;
// End of variables declaration//GEN-END:variables // End of variables declaration//GEN-END:variables
} }

View File

@ -85,10 +85,6 @@ public class EamCaseEditDetailsDialog extends JDialog {
private void customizeComponents() { private void customizeComponents() {
setTextBoxListeners(); setTextBoxListeners();
setTextAreaListeners(); setTextAreaListeners();
// The organization functions of central repo are not being included in the current release.
this.pnOrganization.setVisible(false);
} }
private void setTextBoxListeners() { private void setTextBoxListeners() {

View File

@ -79,7 +79,7 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
private static final Logger logger = Logger.getLogger(DataResultViewerTable.class.getName()); private static final Logger logger = Logger.getLogger(DataResultViewerTable.class.getName());
@NbBundle.Messages("DataResultViewerTable.firstColLbl=Name") @NbBundle.Messages("DataResultViewerTable.firstColLbl=Name")
static private final String FIRST_COLUMN_LABEL = Bundle.DataResultViewerTable_firstColLbl(); static private final String FIRST_COLUMN_LABEL = Bundle.DataResultViewerTable_firstColLbl();
private static final Color TAGGED_COLOR = new Color(200, 210, 220); private static final Color TAGGED_COLOR = new Color(255, 255, 195);
/** /**
* The properties map: * The properties map:
* *

View File

@ -1429,7 +1429,14 @@ final public class Accounts implements AutopsyVisitableItem {
artifacts.forEach(artifact -> { artifacts.forEach(artifact -> {
try { try {
AccountInstance accountInstance = skCase.getCommunicationsManager().getAccountInstance(artifact); AccountInstance accountInstance = skCase.getCommunicationsManager().getAccountInstance(artifact);
accountInstance.setReviewStatus(newStatus);
if (BlackboardArtifact.ReviewStatus.APPROVED == newStatus) {
accountInstance.approveAccount();
}
else {
accountInstance.rejectAccount();
}
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, "Error changing artifact review status.", ex); //NON-NLS LOGGER.log(Level.SEVERE, "Error changing artifact review status.", ex); //NON-NLS
} }

View File

@ -1,394 +0,0 @@
/*
* Sample module in the public domain. Feel free to use this as a template
* for your modules.
*
* Contact: Brian Carrier [carrier <at> sleuthkit [dot] org]
*
* This is free and unencumbered software released into the public domain.
*
* Anyone is free to copy, modify, publish, use, compile, sell, or
* distribute this software, either in source code form or as a compiled
* binary, for any purpose, commercial or non-commercial, and by any
* means.
*
* In jurisdictions that recognize copyright laws, the author or authors
* of this software dedicate any and all copyright interest in the
* software to the public domain. We make this dedication for the benefit
* of the public at large and to the detriment of our heirs and
* successors. We intend this dedication to be an overt act of
* relinquishment in perpetuity of all present and future rights to this
* software under copyright law.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
package org.sleuthkit.autopsy.examples;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.coreutils.ErrorInfo;
import org.sleuthkit.autopsy.coreutils.ExecUtil;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.externalresults.ExternalResults;
import org.sleuthkit.autopsy.externalresults.ExternalResultsImporter;
import org.sleuthkit.autopsy.externalresults.ExternalResultsXMLParser;
import org.sleuthkit.autopsy.ingest.DataSourceIngestModule;
import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProcessTerminator;
import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProgress;
import org.sleuthkit.autopsy.ingest.IngestJobContext;
import org.sleuthkit.autopsy.ingest.IngestMessage;
import org.sleuthkit.autopsy.ingest.IngestModuleReferenceCounter;
import org.sleuthkit.autopsy.ingest.IngestServices;
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.Image;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
/**
* Sample data source ingest module that doesn't do much. Demonstrates use of
* utility classes: ExecUtils and the org.sleuthkit.autopsy.externalresults
* package.
*/
public class SampleExecutableDataSourceIngestModule implements DataSourceIngestModule {
private static final IngestModuleReferenceCounter refCounter = new IngestModuleReferenceCounter();
private static final String moduleName = SampleExecutableIngestModuleFactory.getModuleName();
private final String fileInCaseDatabase = "/WINDOWS/system32/ntmsapi.dll"; // Probably
private IngestJobContext context;
private String outputDirPath;
private String derivedFileInCaseDatabase;
@Override
public void startUp(IngestJobContext context) throws IngestModuleException {
this.context = context;
if (refCounter.incrementAndGet(context.getJobId()) == 1) {
// Create an output directory for this job.
outputDirPath = Case.getCurrentCase().getModuleDirectory() + File.separator + moduleName; //NON-NLS
File outputDir = new File(outputDirPath);
if (outputDir.exists() == false) {
outputDir.mkdirs();
}
}
}
@Override
public ProcessResult process(Content dataSource, DataSourceIngestModuleProgress progressBar) {
if (refCounter.get(context.getJobId()) == 1) {
try {
// There will be two tasks: data source analysis and import of
// the results of the analysis.
progressBar.switchToDeterminate(2);
// Do the analysis. The following sample code could be used to
// run an executable. In this case the executable would take
// two command line arguments, the path to the data source to be
// analyzed and the path to a results file to be generated. The
// results file would be an an XML file (see org.sleuthkit.autopsy.externalresults.autopsy_external_results.xsd)
// with instructions for the import of blackboard artifacts,
// derived files, and reports generated by the analysis. In this
// sample ingest module, the generation of the analysis results is
// simulated.
String resultsFilePath = outputDirPath + File.separator + String.format("job_%d_results.xml", context.getJobId());
boolean haveRealExecutable = false;
if (haveRealExecutable) {
if (dataSource instanceof Image) {
Image image = (Image) dataSource;
String dataSourcePath = image.getPaths()[0];
List<String> commandLine = new ArrayList<>();
commandLine.add("some.exe");
commandLine.add(dataSourcePath);
commandLine.add(resultsFilePath);
ProcessBuilder processBuilder = new ProcessBuilder(commandLine);
ExecUtil.execute(processBuilder, new DataSourceIngestModuleProcessTerminator(context));
} // not a disk image
else {
return ProcessResult.OK;
}
} else {
generateSimulatedResults(resultsFilePath);
}
progressBar.progress(1);
// Import the results of the analysis.
ExternalResultsXMLParser resultsParser = new ExternalResultsXMLParser(dataSource, resultsFilePath);
ExternalResults results = resultsParser.parse();
List<ErrorInfo> errors = resultsParser.getErrorInfo();
ExternalResultsImporter importer = new ExternalResultsImporter();
errors.addAll(importer.importResults(results));
for (ErrorInfo errorInfo : errors) {
IngestServices.getInstance().postMessage(IngestMessage.createErrorMessage(moduleName, "External Results Import Error", errorInfo.getMessage()));
}
progressBar.progress(2);
} catch (ParserConfigurationException | TransformerException | IOException ex) {
Logger logger = IngestServices.getInstance().getLogger(moduleName);
logger.log(Level.SEVERE, "Failed to simulate analysis and results import", ex); //NON-NLS
return ProcessResult.ERROR;
}
}
return ProcessResult.OK;
}
private void generateSimulatedResults(String resultsFilePath) throws ParserConfigurationException, IOException, TransformerConfigurationException, TransformerException {
List<String> derivedFilePaths = generateSimulatedDerivedFiles();
List<String> reportFilePaths = generateSimulatedReports();
generateSimulatedResultsFile(derivedFilePaths, reportFilePaths, resultsFilePath);
}
private List<String> generateSimulatedDerivedFiles() throws IOException {
List<String> filePaths = new ArrayList<>();
String fileContents = "This is a simulated derived file.";
for (int i = 0; i < 2; ++i) {
String fileName = String.format("job_%d_derived_file_%d.txt", context.getJobId(), i);
filePaths.add(generateFile(fileName, fileContents.getBytes()));
if (i == 0) {
this.derivedFileInCaseDatabase = this.fileInCaseDatabase + "/" + fileName;
}
}
return filePaths;
}
private List<String> generateSimulatedReports() throws IOException {
List<String> filePaths = new ArrayList<>();
String fileContents = "This is a simulated report.";
for (int i = 0; i < 2; ++i) {
String fileName = String.format("job_%d_report_%d.txt", context.getJobId(), i);
filePaths.add(generateFile(fileName, fileContents.getBytes()));
}
return filePaths;
}
private String generateFile(String fileName, byte[] fileContents) throws IOException {
String filePath = outputDirPath + File.separator + fileName;
File file = new File(filePath);
if (!file.exists()) {
file.createNewFile();
}
try (FileOutputStream fileStream = new FileOutputStream(file)) {
fileStream.write(fileContents);
fileStream.flush();
}
return filePath;
}
private void generateSimulatedResultsFile(List<String> derivedFilePaths, List<String> reportPaths, String resultsFilePath) throws ParserConfigurationException, TransformerConfigurationException, TransformerException {
// SAMPLE GENERATED BY THE CODE BELOW:
//
// <?xml version="1.0" encoding="UTF-8" standalone="no"?>
// <autopsy_results>
// <derived_files>
// <derived_file>
// <local_path>C:\cases\Small\ModuleOutput\Sample Executable Ingest Module\job_1_derived_file_0.txt</local_path>
// <parent_file>/WINDOWS/system32/ntmsapi.dll</parent_file>
// </derived_file>
// <derived_file>
// <local_path>C:\cases\Small\ModuleOutput\Sample Executable Ingest Module\job_1_derived_file_1.txt</local_path>
// <parent_file>/WINDOWS/system32/ntmsapi.dll/job_1_derived_file_0.txt</parent_file>
// </derived_file>
// </derived_files>
// <artifacts>
// <artifact type="TSK_INTERESTING_FILE_HIT">
// <source_file>/WINDOWS/system32/ntmsapi.dll</source_file>
// <attribute type="TSK_SET_NAME">
// <value>SampleInterestingFilesSet</value>
// <source_module>Sample Executable Ingest Module</source_module>
// </attribute>
// </artifact>
// <artifact type="SampleArtifactType">
// <source_file>/WINDOWS/system32/ntmsapi.dll/job_1_derived_file_0.txt</source_file>
// <attribute type="SampleArtifactAttributeType">
// <value type="text">One</value>
// </attribute>
// <attribute type="SampleArtifactAttributeType">
// <value type="int32">2</value>
// </attribute>
// <attribute type="SampleArtifactAttributeType">
// <value type="int64">3</value>
// </attribute>
// <attribute type="SampleArtifactAttributeType">
// <value type="double">4.0</value>
// </attribute>
// </artifact>
// </artifacts>
// <reports>
// <report>
// <local_path>C:\cases\Small\ModuleOutput\Sample Executable Ingest Module\job_1_report_0.txt</local_path>
// <source_module>Sample Executable Ingest Module</source_module>
// <report_name>Sample Report</report_name>
// </report>
// <report>
// <local_path>C:\cases\Small\ModuleOutput\Sample Executable Ingest Module\job_1_report_1.txt</local_path>
// <source_module>Sample Executable Ingest Module</source_module>
// </report>
// </reports>
// </autopsy_results>
// Create the XML DOM document and the root element.
DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
Document doc = docBuilder.newDocument();
Element rootElement = doc.createElement(ExternalResultsXMLParser.TagNames.ROOT_ELEM.toString());
doc.appendChild(rootElement);
// Add a derived files list element to the root element.
Element derivedFilesListElement = doc.createElement(ExternalResultsXMLParser.TagNames.DERIVED_FILES_LIST_ELEM.toString());
rootElement.appendChild(derivedFilesListElement);
// Add derived file elements to the derived files list element. Each
// file element gets required local path and parent file child elements.
// Note that the local path of the derived file must be to a location in
// the case directory or a subdirectory of the case directory and the
// parent file must be specified using the path format used in the case
// database, e.g., /WINDOWS/system32/ntmsapi.dll, where volume, file
// system, etc. are not in the path.
for (int i = 0; i < derivedFilePaths.size(); ++i) {
String filePath = derivedFilePaths.get(i);
Element derivedFileElement = doc.createElement(ExternalResultsXMLParser.TagNames.DERIVED_FILE_ELEM.toString());
derivedFilesListElement.appendChild(derivedFileElement);
Element localPathElement = doc.createElement(ExternalResultsXMLParser.TagNames.LOCAL_PATH_ELEM.toString());
localPathElement.setTextContent(filePath);
derivedFileElement.appendChild(localPathElement);
Element parentPathElement = doc.createElement(ExternalResultsXMLParser.TagNames.PARENT_FILE_ELEM.toString());
if (i == 0) {
parentPathElement.setTextContent(this.fileInCaseDatabase);
} else {
parentPathElement.setTextContent(this.derivedFileInCaseDatabase);
}
derivedFileElement.appendChild(parentPathElement);
}
// Add an artifacts list element to the root element.
Element artifactsListElement = doc.createElement(ExternalResultsXMLParser.TagNames.ARTIFACTS_LIST_ELEM.toString());
rootElement.appendChild(artifactsListElement);
// Add an artifact element to the artifacts list element with the required
// artifact type attribute. A standard artifact type is used as the type
// attribute of this artifact element.
Element artifactElement = doc.createElement(ExternalResultsXMLParser.TagNames.ARTIFACT_ELEM.toString());
artifactElement.setAttribute(ExternalResultsXMLParser.AttributeNames.TYPE_ATTR.toString(), ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getLabel());
artifactsListElement.appendChild(artifactElement);
// Add the required source file element to the artifact element. Note
// that source file must be either the local path of a derived file or a
// file in the case database.
Element fileElement = doc.createElement(ExternalResultsXMLParser.TagNames.SOURCE_FILE_ELEM.toString());
fileElement.setTextContent(this.fileInCaseDatabase);
artifactElement.appendChild(fileElement);
// Add an artifact attribute element to the artifact element. A standard
// artifact attribute type is used as the required type XML attribute of
// the artifact attribute element.
Element artifactAttrElement = doc.createElement(ExternalResultsXMLParser.TagNames.ATTRIBUTE_ELEM.toString());
artifactAttrElement.setAttribute(ExternalResultsXMLParser.AttributeNames.TYPE_ATTR.toString(), ATTRIBUTE_TYPE.TSK_SET_NAME.getLabel());
artifactElement.appendChild(artifactAttrElement);
// Add the required value element to the artifact attribute element,
// with an optional type XML attribute of ExternalXML.VALUE_TYPE_TEXT,
// which is the default.
Element artifactAttributeValueElement = doc.createElement(ExternalResultsXMLParser.TagNames.VALUE_ELEM.toString());
artifactAttributeValueElement.setTextContent("SampleInterestingFilesSet");
artifactAttrElement.appendChild(artifactAttributeValueElement);
// Add an optional source module element to the artifact attribute
// element.
Element artifactAttrSourceElement = doc.createElement(ExternalResultsXMLParser.TagNames.SOURCE_MODULE_ELEM.toString());
artifactAttrSourceElement.setTextContent(moduleName);
artifactAttrElement.appendChild(artifactAttrSourceElement);
// Add an artifact element with a user-defined type.
artifactElement = doc.createElement(ExternalResultsXMLParser.TagNames.ARTIFACT_ELEM.toString());
artifactElement.setAttribute(ExternalResultsXMLParser.AttributeNames.TYPE_ATTR.toString(), "SampleArtifactType");
artifactsListElement.appendChild(artifactElement);
// Add the required source file element.
fileElement = doc.createElement(ExternalResultsXMLParser.TagNames.SOURCE_FILE_ELEM.toString());
fileElement.setTextContent(this.derivedFileInCaseDatabase);
artifactElement.appendChild(fileElement);
// Add artifact attribute elements with user-defined types to the
// artifact element, adding value elements of assorted types.
for (int i = 0; i < 5; ++i) {
artifactAttrElement = doc.createElement(ExternalResultsXMLParser.TagNames.ATTRIBUTE_ELEM.toString());
artifactAttrElement.setAttribute(ExternalResultsXMLParser.AttributeNames.TYPE_ATTR.toString(), "SampleArtifactAttributeType" + i);
artifactElement.appendChild(artifactAttrElement);
artifactAttributeValueElement = doc.createElement(ExternalResultsXMLParser.TagNames.VALUE_ELEM.toString());
switch (i) {
case 0:
artifactAttributeValueElement.setAttribute(ExternalResultsXMLParser.AttributeNames.TYPE_ATTR.toString(), ExternalResultsXMLParser.AttributeValues.VALUE_TYPE_TEXT.toString());
artifactAttributeValueElement.setTextContent("One");
break;
case 1:
artifactAttributeValueElement.setAttribute(ExternalResultsXMLParser.AttributeNames.TYPE_ATTR.toString(), ExternalResultsXMLParser.AttributeValues.VALUE_TYPE_INT32.toString());
artifactAttributeValueElement.setTextContent("2");
break;
case 2:
artifactAttributeValueElement.setAttribute(ExternalResultsXMLParser.AttributeNames.TYPE_ATTR.toString(), ExternalResultsXMLParser.AttributeValues.VALUE_TYPE_INT64.toString());
artifactAttributeValueElement.setTextContent("3");
break;
case 3:
artifactAttributeValueElement.setAttribute(ExternalResultsXMLParser.AttributeNames.TYPE_ATTR.toString(), ExternalResultsXMLParser.AttributeValues.VALUE_TYPE_DOUBLE.toString());
artifactAttributeValueElement.setTextContent("4.0");
break;
case 4:
artifactAttributeValueElement.setAttribute(ExternalResultsXMLParser.AttributeNames.TYPE_ATTR.toString(), ExternalResultsXMLParser.AttributeValues.VALUE_TYPE_DATETIME.toString());
artifactAttributeValueElement.setTextContent("7023372036854775839");
break;
}
artifactAttrElement.appendChild(artifactAttributeValueElement);
}
// Add a reports list element to the root element.
Element reportsListElement = doc.createElement(ExternalResultsXMLParser.TagNames.REPORTS_LIST_ELEM.toString());
rootElement.appendChild(reportsListElement);
// Add report elements to the reports list element. Each report element
// gets required local path and source module child elements. There is
// also an optional report name element. Note that the local path of the
// report must be to a location in the case directory or a subdirectory
// of the case directory and the parent file must be specified using the
// path format used in the case database, e.g., /WINDOWS/system32/ntmsapi.dll,
// where volume, file system, etc. are not in the path.
for (int i = 0; i < reportPaths.size(); ++i) {
String reportPath = reportPaths.get(i);
Element reportElement = doc.createElement(ExternalResultsXMLParser.TagNames.REPORT_ELEM.toString());
reportsListElement.appendChild(reportElement);
Element reportPathElement = doc.createElement(ExternalResultsXMLParser.TagNames.LOCAL_PATH_ELEM.toString());
reportPathElement.setTextContent(reportPath);
reportElement.appendChild(reportPathElement);
Element reportSourceModuleElement = doc.createElement(ExternalResultsXMLParser.TagNames.SOURCE_MODULE_ELEM.toString());
reportSourceModuleElement.setTextContent(moduleName);
reportElement.appendChild(reportSourceModuleElement);
if (i == 0) {
Element reportNameElement = doc.createElement(ExternalResultsXMLParser.TagNames.REPORT_NAME_ELEM.toString());
reportNameElement.setTextContent("Sample Report");
reportElement.appendChild(reportNameElement);
}
}
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource source = new DOMSource(doc);
StreamResult result = new StreamResult(new File(resultsFilePath));
transformer.transform(source, result);
}
}

View File

@ -1,79 +0,0 @@
/*
* Sample ingest module factory in the public domain.
* Feel free to use this as a template for your inget module factories.
*
* Contact: Brian Carrier [carrier <at> sleuthkit [dot] org]
*
* This is free and unencumbered software released into the public domain.
*
* Anyone is free to copy, modify, publish, use, compile, sell, or
* distribute this software, either in source code form or as a compiled
* binary, for any purpose, commercial or non-commercial, and by any
* means.
*
* In jurisdictions that recognize copyright laws, the author or authors
* of this software dedicate any and all copyright interest in the
* software to the public domain. We make this dedication for the benefit
* of the public at large and to the detriment of our heirs and
* successors. We intend this dedication to be an overt act of
* relinquishment in perpetuity of all present and future rights to this
* software under copyright law.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
package org.sleuthkit.autopsy.examples;
import org.openide.util.NbBundle;
import org.openide.util.lookup.ServiceProvider;
import static org.sleuthkit.autopsy.examples.SampleIngestModuleFactory.getModuleName;
import org.sleuthkit.autopsy.ingest.DataSourceIngestModule;
import org.sleuthkit.autopsy.ingest.IngestModuleFactory;
import org.sleuthkit.autopsy.ingest.IngestModuleFactoryAdapter;
import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings;
/**
* A factory that creates sample executable data source ingest modules.
*/
@ServiceProvider(service = IngestModuleFactory.class) // Sample is discarded at runtime
public class SampleExecutableIngestModuleFactory extends IngestModuleFactoryAdapter {
private static final String VERSION_NUMBER = "1.0.0";
// This class method allows the ingest module instances created by this
// factory to use the same display name that is provided to the Autopsy
// ingest framework by the factory.
static String getModuleName() {
return NbBundle.getMessage(SampleIngestModuleFactory.class, "SampleExecutableIngestModuleFactory.moduleName");
}
@Override
public String getModuleDisplayName() {
return getModuleName();
}
@Override
public String getModuleDescription() {
return NbBundle.getMessage(SampleIngestModuleFactory.class, "SampleExecutableIngestModuleFactory.moduleDescription");
}
@Override
public String getModuleVersionNumber() {
return VERSION_NUMBER;
}
@Override
public boolean isDataSourceIngestModuleFactory() {
return true;
}
@Override
public DataSourceIngestModule createDataSourceIngestModule(IngestModuleIngestJobSettings ingestOptions) {
return new SampleExecutableDataSourceIngestModule();
}
}

View File

@ -1,27 +0,0 @@
ExternalResultsImporter.importDerivedFiles.errMsg1.text=Could not import derived file at {0}, parent file {1} not found.
ExternalResultsImporter.importDerivedFiles.errMsg2.text=Could not import derived file at {0}, file does not exist.
ExternalResultsImporter.importDerivedFiles.errMsg3.text=Could not import derived file at {0}, error querying/updating case database.
ExternalResultsImporter.importArtifacts.caseErrMsg1.text=Could not import {0} attribute, value \= {1}, for {2} artifact from {3}, unrecognized attribute value type\: {4}.
ExternalResultsImporter.importArtifacts.errMsg1.text=Could not import {0} artifact from {1}, source file not found.
ExternalResultsImporter.importArtifacts.errMsg2.text=Could not import {0} artifact from {1}, error updating case database.
ExternalResultsImporter.importReports.errMsg1.text=Could not import report at {0}, file does not exist.
ExternalResultsImporter.importReports.errMsg2.text=Could not import report at {0}, error updating case database.
ExternalResultsImporter.findFileInCaseDatabase.errMsg1.text=Parent file path {0} is ambiguous, using first file found.
ExternalResultsImporter.getPathRelativeToCaseFolder.errMsg1.text=Did not convert {0} to relative path, not in a subdirectory of case directory {1}.
ExternalResultsImporter.getPathRelativeToCaseFolder.errMsg2.text=Expected {0} to be an absolute path to a file in a subdirectory of case directory {1}.
ExternalResultsXMLParser.parse.errMsg1.text=Did not find {0} root element of {1}.
ExternalResultsXMLParser.parse.errMsg2.text=Error parsing {0}.
ExternalResultsXMLParser.parseArtifactAttributes.errMsg1.text=Found {0} element that has no content in {1}.
ExternalResultsXMLParser.parseAttributeValueType.errMsg1.text=Found unrecognized value {0} for {1} attribute of {2} element.
ExternalResultsXMLParser.getChildElementContent.errMsg1.text=Found {0} element with {1} child element that has no content in {2}.
ExternalResultsXMLParser.getChildElementContent.errMsg2.text=Found {0} element missing {1} child element in {2}.
ExternalResultsXMLParser.getChildElement.errMsg1.text=Found multiple {0} child elements for {1} element in {2}, ignoring all but first occurrence.
ExternalResults.addArtifact.exception.msg1.text=type argument is empty.
ExternalResults.addArtifact.exception.msg2.text=source argument is empty.
ExternalResults.addReport.exception.msg1.text=localPath argument is empty.
ExternalResults.addReport.exception.msg2.text=sourceModuleName argument is empty.
ExternalResults.addDerivedFile.exception.msg1.text=localPath argument is empty.
ExternalResults.addDerivedFile.exception.msg2.text=parentPath argument is empty.
ExternalResults.Artifact.addAttribute.exception.msg1.text=type argument is empty.
ExternalResults.Artifact.addAttribute.exception.msg2.text=value argument is empty.
ExternalResults.Artifact.addAttribute.exception.msg3.text=valueType argument is empty.

View File

@ -1,27 +0,0 @@
ExternalResults.addArtifact.exception.msg1.text=\u5F15\u6570\u30BF\u30A4\u30D7\u304C\u7A7A\u767D\u3067\u3059\u3002
ExternalResults.addArtifact.exception.msg2.text=\u30BD\u30FC\u30B9\u5F15\u6570\u304C\u7A7A\u767D\u3067\u3059\u3002
ExternalResults.addDerivedFile.exception.msg1.text=\u30ED\u30FC\u30AB\u30EB\u30D1\u30B9\u5F15\u6570\u304C\u7A7A\u767D\u3067\u3059\u3002
ExternalResults.addDerivedFile.exception.msg2.text=\u30DA\u30A2\u30EC\u30F3\u30C8\u30D1\u30B9\u5F15\u6570\u304C\u7A7A\u767D\u3067\u3059\u3002
ExternalResults.addReport.exception.msg1.text=\u30ED\u30FC\u30AB\u30EB\u30D1\u30B9\u5F15\u6570\u304C\u7A7A\u767D\u3067\u3059\u3002
ExternalResults.addReport.exception.msg2.text=\u30BD\u30FC\u30B9\u30E2\u30B8\u30E5\u30FC\u30EB\u540D\u304C\u7A7A\u767D\u3067\u3059\u3002
ExternalResults.Artifact.addAttribute.exception.msg1.text=\u5F15\u6570\u30BF\u30A4\u30D7\u304C\u7A7A\u767D\u3067\u3059\u3002
ExternalResults.Artifact.addAttribute.exception.msg2.text=\u5F15\u6570\u5024\u304C\u7A7A\u767D\u3067\u3059\u3002
ExternalResultsImporter.findFileInCaseDatabase.errMsg1.text=\u30DA\u30A2\u30EC\u30F3\u30C8\u30D5\u30A1\u30A4\u30EB\u30D1\u30B9{0}\u304C\u66D6\u6627\u3067\u3059\u3002\u6700\u521D\u306B\u898B\u3064\u3051\u305F\u30D5\u30A1\u30A4\u30EB\u3092\u5229\u7528\u3057\u307E\u3059\u3002
ExternalResultsImporter.getPathRelativeToCaseFolder.errMsg1.text={0}\u3092\u76F8\u5BFE\u30D1\u30B9\u306B\u5909\u63DB\u3057\u307E\u305B\u3093\u3067\u3057\u305F\u3002\u30B1\u30FC\u30B9\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA{1}\u306E\u30B5\u30D6\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306B\u3042\u308A\u307E\u305B\u3093\u3002
ExternalResultsImporter.getPathRelativeToCaseFolder.errMsg2.text={0}\u306F\u30B1\u30FC\u30B9\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA{1}\u306E\u30B5\u30D6\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u5185\u306E\u30D5\u30A1\u30A4\u30EB\u3078\u306E\u7D76\u5BFE\u30D1\u30B9\u3068\u4E88\u60F3\u3055\u308C\u3066\u3044\u307E\u3059\u3002
ExternalResultsImporter.importArtifacts.caseErrMsg1.text={3}\u306E{2}\u30A2\u30FC\u30C6\u30A3\u30D5\u30A1\u30AF\u30C8\u306E{0}\u5C5E\u6027\u3001\u30D0\u30EA\u30E5\u30FC\uFF1D{1}\u3092\u30A4\u30F3\u30DD\u30FC\u30C8\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002\u8A8D\u8B58\u3055\u308C\u3066\u3044\u306A\u3044\u5C5E\u6027\u5024\u578B\uFF1A{4}
ExternalResultsImporter.importDerivedFiles.errMsg1.text={0}\u306B\u6D3E\u751F\u30D5\u30A1\u30A4\u30EB\u3092\u30A4\u30F3\u30DD\u30FC\u30C8\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002\u30DA\u30A2\u30EC\u30F3\u30C8\u30D5\u30A1\u30A4\u30EB{1}\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3067\u3057\u305F\u3002
ExternalResultsImporter.importDerivedFiles.errMsg2.text={0}\u306B\u6D3E\u751F\u30D5\u30A1\u30A4\u30EB\u3092\u30A4\u30F3\u30DD\u30FC\u30C8\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002\u30D5\u30A1\u30A4\u30EB\u304C\u5B58\u5728\u3057\u307E\u305B\u3093\u3002
ExternalResultsImporter.importDerivedFiles.errMsg3.text={0}\u306B\u6D3E\u751F\u30D5\u30A1\u30A4\u30EB\u3092\u30A4\u30F3\u30DD\u30FC\u30C8\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002\u30B1\u30FC\u30B9\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u3067\u306E\u30AF\u30A8\u30EA\u30FC\uFF0F\u30A2\u30C3\u30D7\u30C7\u30FC\u30C8\u306E\u5B9F\u884C\u4E2D\u306B\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F\u3002
ExternalResultsImporter.importReports.errMsg1.text={0}\u306B\u30EC\u30DD\u30FC\u30C8\u3092\u30A4\u30F3\u30DD\u30FC\u30C8\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002\u30D5\u30A1\u30A4\u30EB\u304C\u5B58\u5728\u3057\u307E\u305B\u3093\u3002
ExternalResultsImporter.importReports.errMsg2.text={0}\u306B\u30EC\u30DD\u30FC\u30C8\u3092\u30A4\u30F3\u30DD\u30FC\u30C8\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002\u30B1\u30FC\u30B9\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u306E\u30A2\u30C3\u30D7\u30C7\u30FC\u30C8\u306B\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F\u3002
ExternalResultsXMLParser.parse.errMsg2.text={0}\u306E\u30D1\u30FC\u30B9\u4E2D\u306B\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F\u3002
ExternalResults.Artifact.addAttribute.exception.msg3.text=\u5024\u578B\u5F15\u6570\u304C\u7A7A\u767D\u3067\u3059\u3002
ExternalResultsImporter.importArtifacts.errMsg1.text={1}\u306E{0}\u30A2\u30FC\u30C6\u30A3\u30D5\u30A1\u30AF\u30C8\u3092\u30A4\u30F3\u30DD\u30FC\u30C8\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002\u30BD\u30FC\u30B9\u30D5\u30A1\u30A4\u30EB\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3067\u3057\u305F\u3002
ExternalResultsImporter.importArtifacts.errMsg2.text={1}\u306E{0}\u30A2\u30FC\u30C6\u30A3\u30D5\u30A1\u30AF\u30C8\u3092\u30A4\u30F3\u30DD\u30FC\u30C8\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002\u30B1\u30FC\u30B9\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u306E\u30A2\u30C3\u30D7\u30C7\u30FC\u30C8\u4E2D\u306B\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F\u3002
ExternalResultsXMLParser.getChildElement.errMsg1.text={2}\u306B\u3066\u8907\u6570\u306E{1}\u30A8\u30EC\u30E1\u30F3\u30C8\u306E{0}\u30C1\u30E3\u30A4\u30EB\u30C9\u30A8\u30EC\u30E1\u30F3\u30C8\u304C\u898B\u3064\u304B\u308A\u307E\u3057\u305F\u3002\u4E00\u756A\u76EE\u4EE5\u5916\u306F\u7121\u8996\u3057\u307E\u3059\u3002
ExternalResultsXMLParser.getChildElementContent.errMsg1.text={2}\u306B\u30B3\u30F3\u30C6\u30F3\u30C4\u304C\u306A\u304F\u3001{1}\u30C1\u30E3\u30A4\u30EB\u30C9\u30A8\u30EC\u30E1\u30F3\u30C8\u304C\u3042\u308B\u3001{0}\u30A8\u30EC\u30E1\u30F3\u30C8\u304C\u898B\u3064\u304B\u308A\u307E\u3057\u305F\u3002
ExternalResultsXMLParser.getChildElementContent.errMsg2.text={2}\u306B\u3066{1}\u30C1\u30E3\u30A4\u30EB\u30C9\u30A8\u30EC\u30E1\u30F3\u30C8\u304C\u306A\u3044{0}\u30A8\u30EC\u30E1\u30F3\u30C8\u304C\u898B\u3064\u304B\u308A\u307E\u3057\u305F\u3002
ExternalResultsXMLParser.parse.errMsg1.text={1}\u306E{0}\u30EB\u30FC\u30C8\u30A8\u30EC\u30E1\u30F3\u30C8\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3067\u3057\u305F\u3002
ExternalResultsXMLParser.parseArtifactAttributes.errMsg1.text={1}\u306B\u30B3\u30F3\u30C6\u30F3\u30C4\u304C\u306A\u3044{0}\u30A8\u30EC\u30E1\u30F3\u30C8\u304C\u898B\u3064\u304B\u308A\u307E\u3057\u305F\u3002
ExternalResultsXMLParser.parseAttributeValueType.errMsg1.text={2}\u30A8\u30EC\u30E1\u30F3\u30C8\u306E{1}\u5C5E\u6027\u306B\u5BFE\u3057\u3066\u3001\u8A8D\u8B58\u3055\u308C\u306A\u3044\u30D0\u30EA\u30E5\u30FC{0}\u304C\u898B\u3064\u304B\u308A\u307E\u3057\u305F\u3002

View File

@ -1,212 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2014 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.externalresults;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.openide.util.NbBundle;
import org.sleuthkit.datamodel.Content;
/**
*
*/
final public class ExternalResults {
private final Content dataSource;
private final List<Artifact> artifacts = new ArrayList<>();
private final List<Report> reports = new ArrayList<>();
private final List<DerivedFile> derivedFiles = new ArrayList<>();
ExternalResults(Content dataSource) {
this.dataSource = dataSource;
}
Content getDataSource() {
return this.dataSource;
}
Artifact addArtifact(String type, String sourceFilePath) {
if (type.isEmpty()) {
throw new IllegalArgumentException(
NbBundle.getMessage(this.getClass(), "ExternalResults.addArtifact.exception.msg1.text"));
}
if (sourceFilePath.isEmpty()) {
throw new IllegalArgumentException(
NbBundle.getMessage(this.getClass(), "ExternalResults.addArtifact.exception.msg2.text"));
}
Artifact artifact = new Artifact(type, sourceFilePath);
artifacts.add(artifact);
return artifact;
}
List<Artifact> getArtifacts() {
return Collections.unmodifiableList(artifacts);
}
void addReport(String localPath, String sourceModuleName, String reportName) {
if (localPath.isEmpty()) {
throw new IllegalArgumentException(
NbBundle.getMessage(this.getClass(), "ExternalResults.addReport.exception.msg1.text"));
}
if (sourceModuleName.isEmpty()) {
throw new IllegalArgumentException(
NbBundle.getMessage(this.getClass(), "ExternalResults.addReport.exception.msg2.text"));
}
Report report = new Report(localPath, sourceModuleName, reportName);
reports.add(report);
}
List<Report> getReports() {
return Collections.unmodifiableList(reports);
}
void addDerivedFile(String localPath, String parentPath) {
if (localPath.isEmpty()) {
throw new IllegalArgumentException(
NbBundle.getMessage(this.getClass(), "ExternalResults.addDerivedFile.exception.msg1.text"));
}
if (parentPath.isEmpty()) {
throw new IllegalArgumentException(
NbBundle.getMessage(this.getClass(), "ExternalResults.addDerivedFile.exception.msg2.text"));
}
DerivedFile file = new DerivedFile(localPath, parentPath);
derivedFiles.add(file);
}
List<DerivedFile> getDerivedFiles() {
return Collections.unmodifiableList(derivedFiles);
}
static final class Artifact {
private final String type;
private final String sourceFilePath;
private final ArrayList<ArtifactAttribute> attributes = new ArrayList<>();
Artifact(String type, String sourceFilePath) {
this.type = type;
this.sourceFilePath = sourceFilePath;
}
String getType() {
return type;
}
String getSourceFilePath() {
return sourceFilePath;
}
void addAttribute(String type, String value, String valueType, String sourceModule) {
if (type.isEmpty()) {
throw new IllegalArgumentException(NbBundle.getMessage(this.getClass(),
"ExternalResults.Artifact.addAttribute.exception.msg1.text"));
}
if (value.isEmpty()) {
throw new IllegalArgumentException(NbBundle.getMessage(this.getClass(),
"ExternalResults.Artifact.addAttribute.exception.msg2.text"));
}
if (valueType.isEmpty()) {
throw new IllegalArgumentException(NbBundle.getMessage(this.getClass(),
"ExternalResults.Artifact.addAttribute.exception.msg3.text"));
}
attributes.add(new ArtifactAttribute(type, value, valueType, sourceModule));
}
List<ArtifactAttribute> getAttributes() {
return Collections.unmodifiableList(attributes);
}
}
static final class ArtifactAttribute {
private final String type;
private final String valueType;
private final String value;
private final String sourceModule;
private ArtifactAttribute(String type, String value, String valueType, String sourceModule) {
this.type = type;
this.value = value;
this.valueType = valueType;
this.sourceModule = sourceModule;
}
String getType() {
return type;
}
String getValue() {
return value;
}
String getValueType() {
return valueType;
}
String getSourceModule() {
return sourceModule;
}
}
static final class Report {
private final String localPath;
private final String sourceModuleName;
private final String reportName;
Report(String localPath, String sourceModuleName, String displayName) {
this.localPath = localPath;
this.sourceModuleName = sourceModuleName;
this.reportName = displayName;
}
String getLocalPath() {
return localPath;
}
String getSourceModuleName() {
return sourceModuleName;
}
String getReportName() {
return reportName;
}
}
static final class DerivedFile {
private final String localPath;
private final String parentPath;
DerivedFile(String localPath, String parentPath) {
this.localPath = localPath;
this.parentPath = parentPath;
}
String getLocalPath() {
return localPath;
}
String getParentPath() {
return parentPath;
}
}
}

View File

@ -1,308 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2016 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this localFile 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.externalresults;
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.logging.Level;
import org.openide.util.NbBundle;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.services.Blackboard;
import org.sleuthkit.autopsy.casemodule.services.FileManager;
import org.sleuthkit.autopsy.coreutils.ErrorInfo;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import org.sleuthkit.autopsy.ingest.IngestServices;
import org.sleuthkit.autopsy.ingest.ModuleContentEvent;
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.DerivedFile;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData;
import org.sleuthkit.datamodel.TskDataException;
/**
* Uses a standard representation of results data (e.g., artifacts, derived
* files, reports) to import results generated by a process external to Autopsy
* into Autopsy.
*/
public final class ExternalResultsImporter {
private static final Logger logger = Logger.getLogger(ExternalResultsImporter.class.getName());
private static final HashSet<Integer> standardArtifactTypeIds = new HashSet<>();
private final List<ErrorInfo> errors = new ArrayList<>();
private Blackboard blackboard;
static {
for (BlackboardArtifact.ARTIFACT_TYPE artifactType : BlackboardArtifact.ARTIFACT_TYPE.values()) {
standardArtifactTypeIds.add(artifactType.getTypeID());
}
}
/**
* Import results generated by a process external to Autopsy into Autopsy.
*
* @param results A standard representation of results data (e.g.,
* artifacts, derived files, reports)from the data source.
*
* @return A collection of error messages, possibly empty. The error
* messages are already logged but are provided to allow the caller
* to provide additional user feedback via the Autopsy user
* interface.
*/
public List<ErrorInfo> importResults(ExternalResults results) {
blackboard = Case.getCurrentCase().getServices().getBlackboard();
// Import files first, they may be artifactData sources.
importDerivedFiles(results);
importArtifacts(results);
importReports(results);
List<ErrorInfo> importErrors = new ArrayList<>(this.errors);
this.errors.clear();
return importErrors;
}
private void importDerivedFiles(ExternalResults results) {
FileManager fileManager = Case.getCurrentCase().getServices().getFileManager();
for (ExternalResults.DerivedFile fileData : results.getDerivedFiles()) {
String localPath = fileData.getLocalPath();
try {
File localFile = new File(localPath);
if (localFile.exists()) {
String relativePath = this.getPathRelativeToCaseFolder(localPath);
if (!relativePath.isEmpty()) {
String parentFilePath = fileData.getParentPath();
AbstractFile parentFile = findFileInCaseDatabase(parentFilePath);
if (parentFile != null) {
DerivedFile derivedFile = fileManager.addDerivedFile(localFile.getName(), relativePath, localFile.length(),
0, 0, 0, 0, // Do not currently have file times for derived files from external processes.
true, parentFile,
"", "", "", "", // Not currently providing derivation info for derived files from external processes.
TskData.EncodingType.NONE); // Don't allow external encoded files
IngestServices.getInstance().fireModuleContentEvent(new ModuleContentEvent(derivedFile));
} else {
String errorMessage = NbBundle.getMessage(this.getClass(),
"ExternalResultsImporter.importDerivedFiles.errMsg1.text",
localPath, parentFilePath);
ExternalResultsImporter.logger.log(Level.SEVERE, errorMessage);
this.errors.add(new ErrorInfo(ExternalResultsImporter.class.getName(), errorMessage));
}
}
} else {
String errorMessage = NbBundle.getMessage(this.getClass(),
"ExternalResultsImporter.importDerivedFiles.errMsg2.text",
localPath);
ExternalResultsImporter.logger.log(Level.SEVERE, errorMessage);
this.errors.add(new ErrorInfo(ExternalResultsImporter.class.getName(), errorMessage));
}
} catch (TskCoreException ex) {
String errorMessage = NbBundle.getMessage(this.getClass(),
"ExternalResultsImporter.importDerivedFiles.errMsg3.text",
localPath);
ExternalResultsImporter.logger.log(Level.SEVERE, errorMessage, ex);
this.errors.add(new ErrorInfo(ExternalResultsImporter.class.getName(), errorMessage, ex));
}
}
}
@Messages({"ExternalResultsImporter.indexError.message=Failed to index imported artifact for keyword search."})
private void importArtifacts(ExternalResults results) {
SleuthkitCase caseDb = Case.getCurrentCase().getSleuthkitCase();
for (ExternalResults.Artifact artifactData : results.getArtifacts()) {
try {
// Add the artifact to the case database.
int artifactTypeId = caseDb.getArtifactType(artifactData.getType()).getTypeID();
if (artifactTypeId == -1) {
artifactTypeId = caseDb.addBlackboardArtifactType(artifactData.getType(), artifactData.getType()).getTypeID();
}
Content sourceFile = findFileInCaseDatabase(artifactData.getSourceFilePath());
if (sourceFile != null) {
BlackboardArtifact artifact = sourceFile.newArtifact(artifactTypeId);
// Add the artifact's attributes to the case database.
Collection<BlackboardAttribute> attributes = new ArrayList<>();
for (ExternalResults.ArtifactAttribute attributeData : artifactData.getAttributes()) {
BlackboardAttribute.Type attributeType = caseDb.getAttributeType(attributeData.getType());
if (attributeType == null) {
switch (attributeData.getValueType()) {
case "text": //NON-NLS
attributeType = caseDb.addArtifactAttributeType(attributeData.getType(), BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.fromLabel("String"), attributeData.getType()); //NON-NLS
break;
case "int32": //NON-NLS
attributeType = caseDb.addArtifactAttributeType(attributeData.getType(), BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.fromLabel("Integer"), attributeData.getType()); //NON-NLS
break;
case "int64": //NON-NLS
attributeType = caseDb.addArtifactAttributeType(attributeData.getType(), BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.fromLabel("Long"), attributeData.getType()); //NON-NLS
break;
case "double": //NON-NLS
attributeType = caseDb.addArtifactAttributeType(attributeData.getType(), BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.fromLabel("Double"), attributeData.getType()); //NON-NLS
break;
case "datetime": //NON-NLS
attributeType = caseDb.addArtifactAttributeType(attributeData.getType(), BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.fromLabel("DateTime"), attributeData.getType()); //NON-NLS
}
}
switch (attributeData.getValueType()) {
case "text": //NON-NLS
attributes.add(new BlackboardAttribute(attributeType, attributeData.getSourceModule(), attributeData.getValue()));
break;
case "int32": //NON-NLS
int intValue = Integer.parseInt(attributeData.getValue());
attributes.add(new BlackboardAttribute(attributeType, attributeData.getSourceModule(), intValue));
break;
case "int64": //NON-NLS
long longValue = Long.parseLong(attributeData.getValue());
attributes.add(new BlackboardAttribute(attributeType, attributeData.getSourceModule(), longValue));
break;
case "double": //NON-NLS
double doubleValue = Double.parseDouble(attributeData.getValue());
attributes.add(new BlackboardAttribute(attributeType, attributeData.getSourceModule(), doubleValue));
break;
case "datetime": //NON-NLS
long dateTimeValue = Long.parseLong(attributeData.getValue());
attributes.add(new BlackboardAttribute(attributeType, attributeData.getSourceModule(), dateTimeValue));
break;
default:
String errorMessage = NbBundle.getMessage(this.getClass(),
"ExternalResultsImporter.importArtifacts.caseErrMsg1.text",
attributeData.getType(), attributeData.getValue(),
artifactData.getType(), artifactData.getSourceFilePath(),
attributeData.getValueType());
ExternalResultsImporter.logger.log(Level.SEVERE, errorMessage);
this.errors.add(new ErrorInfo(ExternalResultsImporter.class.getName(), errorMessage));
break;
}
}
artifact.addAttributes(attributes);
try {
// index the artifact for keyword search
blackboard.indexArtifact(artifact);
} catch (Blackboard.BlackboardException ex) {
logger.log(Level.SEVERE, "Unable to index blackboard artifact " + artifact.getArtifactID(), ex); //NON-NLS
MessageNotifyUtil.Notify.error(
Bundle.ExternalResultsImporter_indexError_message(), artifact.getDisplayName());
}
if (standardArtifactTypeIds.contains(artifactTypeId)) {
IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent(this.getClass().getSimpleName(), BlackboardArtifact.ARTIFACT_TYPE.fromID(artifactTypeId)));
}
} else {
String errorMessage = NbBundle.getMessage(this.getClass(),
"ExternalResultsImporter.importArtifacts.errMsg1.text",
artifactData.getType(), artifactData.getSourceFilePath());
ExternalResultsImporter.logger.log(Level.SEVERE, errorMessage);
this.errors.add(new ErrorInfo(ExternalResultsImporter.class.getName(), errorMessage));
}
} catch (TskCoreException | TskDataException ex) {
String errorMessage = NbBundle.getMessage(this.getClass(),
"ExternalResultsImporter.importArtifacts.errMsg2.text",
artifactData.getType(), artifactData.getSourceFilePath());
ExternalResultsImporter.logger.log(Level.SEVERE, errorMessage, ex);
this.errors.add(new ErrorInfo(ExternalResultsImporter.class.getName(), errorMessage, ex));
}
}
}
private void importReports(ExternalResults results) {
for (ExternalResults.Report report : results.getReports()) {
String reportPath = report.getLocalPath();
try {
File reportFile = new File(reportPath);
if (reportFile.exists()) {
Case.getCurrentCase().addReport(reportPath, report.getSourceModuleName(), report.getReportName());
} else {
String errorMessage = NbBundle.getMessage(this.getClass(), "ExternalResultsImporter.importReports.errMsg1.text", reportPath);
ExternalResultsImporter.logger.log(Level.SEVERE, errorMessage);
this.errors.add(new ErrorInfo(ExternalResultsImporter.class.getName(), errorMessage));
}
} catch (TskCoreException ex) {
String errorMessage = NbBundle.getMessage(this.getClass(), "ExternalResultsImporter.importReports.errMsg2.text", reportPath);
ExternalResultsImporter.logger.log(Level.SEVERE, errorMessage, ex);
this.errors.add(new ErrorInfo(ExternalResultsImporter.class.getName(), errorMessage, ex));
}
}
}
private AbstractFile findFileInCaseDatabase(String filePath) throws TskCoreException {
AbstractFile file = null;
// Split the path into the file name and the parent path.
String fileName = filePath;
String parentPath = "";
int charPos = filePath.lastIndexOf("/");
if (charPos >= 0) {
fileName = filePath.substring(charPos + 1);
parentPath = filePath.substring(0, charPos + 1);
}
// Find the file.
String condition = "name='" + fileName + "' AND parent_path='" + parentPath + "'"; //NON-NLS
List<AbstractFile> files = Case.getCurrentCase().getSleuthkitCase().findAllFilesWhere(condition);
if (!files.isEmpty()) {
file = files.get(0);
if (files.size() > 1) {
String errorMessage = NbBundle.getMessage(this.getClass(), "ExternalResultsImporter.findFileInCaseDatabase.errMsg1.text", filePath);
this.recordError(errorMessage);
}
}
return file;
}
private String getPathRelativeToCaseFolder(String localPath) {
String relativePath = "";
String caseDirectoryPath = Case.getCurrentCase().getCaseDirectory();
Path path = Paths.get(localPath);
if (path.isAbsolute()) {
Path pathBase = Paths.get(caseDirectoryPath);
try {
Path pathRelative = pathBase.relativize(path);
relativePath = pathRelative.toString();
} catch (IllegalArgumentException ex) {
String errorMessage = NbBundle.getMessage(this.getClass(),
"ExternalResultsImporter.getPathRelativeToCaseFolder.errMsg1.text",
localPath, caseDirectoryPath);
this.recordError(errorMessage, ex);
}
} else {
String errorMessage = NbBundle.getMessage(this.getClass(),
"ExternalResultsImporter.getPathRelativeToCaseFolder.errMsg2.text",
localPath, caseDirectoryPath);
this.recordError(errorMessage);
}
return relativePath;
}
private void recordError(String errorMessage) {
ExternalResultsImporter.logger.log(Level.SEVERE, errorMessage);
this.errors.add(new ErrorInfo(this.getClass().getName(), errorMessage));
}
private void recordError(String errorMessage, Exception ex) {
ExternalResultsImporter.logger.log(Level.SEVERE, errorMessage, ex);
this.errors.add(new ErrorInfo(this.getClass().getName(), errorMessage));
}
}

View File

@ -1,50 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2014 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.externalresults;
import java.util.List;
import org.sleuthkit.autopsy.coreutils.ErrorInfo;
/**
* Interface for parsers that convert some representation of results data (e.g.,
* artifacts, derived files, reports) generated by a process external to Autopsy
* into a form ready for import into Autopsy.
*/
public interface ExternalResultsParser {
/**
* Converts some representation of results data generated by a process
* external to Autopsy and supplied to the parser via its constructor into a
* form ready for import into Autopsy.
*
* @return External results data in a form ready for import into Autopsy.
*/
ExternalResults parse();
/**
* Gets error information describing any errors encountered while parsing
* the input results representation.
*
* @return A collection of error messages, possibly empty. The error
* messages are already logged but are provided to allow the caller
* to provide additional user feedback via the Autopsy user
* interface.
*/
List<ErrorInfo> getErrorInfo();
}

View File

@ -1,352 +0,0 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2016 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.externalresults;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.ErrorInfo;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.XMLUtil;
import org.sleuthkit.datamodel.Content;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
/**
* Parses an XML representation of of results data (e.g., artifacts, derived
* files, reports) generated by a process external to Autopsy.
*/
public final class ExternalResultsXMLParser implements ExternalResultsParser {
private static final Logger logger = Logger.getLogger(ExternalResultsXMLParser.class.getName());
private static final String XSD_FILE = "autopsy_external_results.xsd"; //NON-NLS
private final Content dataSource;
private final String resultsFilePath;
private ExternalResults resultsData;
private List<ErrorInfo> errors = new ArrayList<>();
/**
* Tag names for an external results XML file.
*/
public enum TagNames {
ROOT_ELEM("autopsy_results"), //NON-NLS
DERIVED_FILES_LIST_ELEM("derived_files"), //NON-NLS
DERIVED_FILE_ELEM("derived_file"), //NON-NLS
LOCAL_PATH_ELEM("local_path"), //NON-NLS
PARENT_FILE_ELEM("parent_file"), //NON-NLS
ARTIFACTS_LIST_ELEM("artifacts"), //NON-NLS
ARTIFACT_ELEM("artifact"), //NON-NLS
SOURCE_FILE_ELEM("source_file"), //NON-NLS
ATTRIBUTE_ELEM("attribute"), //NON-NLS
VALUE_ELEM("value"), //NON-NLS
SOURCE_MODULE_ELEM("source_module"), //NON-NLS
REPORTS_LIST_ELEM("reports"), //NON-NLS
REPORT_ELEM("report"), //NON-NLS
REPORT_NAME_ELEM("report_name"); //NON-NLS
private final String text;
private TagNames(final String text) {
this.text = text;
}
@Override
public String toString() {
return this.text;
}
}
/**
* Attribute names for an external results XML file.
*/
public enum AttributeNames {
TYPE_ATTR("type"); //NON-NLS
private final String text;
private AttributeNames(final String text) {
this.text = text;
}
@Override
public String toString() {
return this.text;
}
}
/**
* Attribute values for an external results XML file.
*/
public enum AttributeValues {
VALUE_TYPE_TEXT("text"), //NON-NLS
VALUE_TYPE_INT32("int32"), //NON-NLS
VALUE_TYPE_INT64("int64"), //NON-NLS
VALUE_TYPE_DOUBLE("double"), //NON-NLS
VALUE_TYPE_DATETIME("datetime"); //NON-NLS
private final String text;
private AttributeValues(final String text) {
this.text = text;
}
@Override
public String toString() {
return this.text;
}
}
/**
* Constructor.
*
* @param dataSource The data source for the results.
* @param resultsFilePath Full path of the results file to be parsed.
*/
public ExternalResultsXMLParser(Content dataSource, String resultsFilePath) {
this.dataSource = dataSource;
this.resultsFilePath = resultsFilePath;
}
@Override
public ExternalResults parse() {
this.errors.clear();
this.resultsData = new ExternalResults(dataSource);
try {
// Note that XMLUtil.loadDoc() logs a warning if the file does not
// conform to the XSD, but still returns a Document object. Until
// this behavior is improved, validation is still required. If
// XMLUtil.loadDoc() does return null, it failed to load the
// document and it logged the error.
final Document doc = XMLUtil.loadDoc(ExternalResultsXMLParser.class, this.resultsFilePath, XSD_FILE);
if (doc != null) {
final Element rootElem = doc.getDocumentElement();
if (rootElem != null && rootElem.getNodeName().equals(TagNames.ROOT_ELEM.toString())) {
parseDerivedFiles(rootElem);
parseArtifacts(rootElem);
parseReports(rootElem);
} else {
String errorMessage = NbBundle.getMessage(this.getClass(),
"ExternalResultsXMLParser.parse.errMsg1.text",
TagNames.ROOT_ELEM.toString(), this.resultsFilePath);
recordError(errorMessage);
}
}
} catch (Exception ex) {
String errorMessage = NbBundle.getMessage(this.getClass(), "ExternalResultsXMLParser.parse.errMsg2.text", this.resultsFilePath);
recordError(errorMessage, ex);
}
return this.resultsData;
}
@Override
public List<ErrorInfo> getErrorInfo() {
return new ArrayList<>(this.errors);
}
private void parseDerivedFiles(Element rootElement) {
// Get the derived file lists.
NodeList derivedFilesListNodes = rootElement.getElementsByTagName(TagNames.DERIVED_FILES_LIST_ELEM.toString());
for (int i = 0; i < derivedFilesListNodes.getLength(); ++i) {
Element derivedFilesListElem = (Element) derivedFilesListNodes.item(i);
// Get the derived files.
NodeList derivedFileNodes = derivedFilesListElem.getElementsByTagName(TagNames.DERIVED_FILE_ELEM.toString());
for (int j = 0; j < derivedFileNodes.getLength(); ++j) {
Element derivedFileElem = (Element) derivedFileNodes.item(j);
// Get the local path of the derived file.
String path = getChildElementContent(derivedFileElem, TagNames.LOCAL_PATH_ELEM.toString(), true);
if (path.isEmpty()) {
continue;
}
// Get the parent file of the derived file.
String parentFile = getChildElementContent((Element) derivedFileNodes.item(j), TagNames.PARENT_FILE_ELEM.toString(), true);
if (parentFile.isEmpty()) {
continue;
}
this.resultsData.addDerivedFile(path, parentFile);
}
}
}
private void parseArtifacts(final Element root) {
// Get the artifact lists.
NodeList artifactsListNodes = root.getElementsByTagName(TagNames.ARTIFACTS_LIST_ELEM.toString());
for (int i = 0; i < artifactsListNodes.getLength(); ++i) {
Element artifactsListElem = (Element) artifactsListNodes.item(i);
// Get the artifacts.
NodeList artifactNodes = artifactsListElem.getElementsByTagName(TagNames.ARTIFACT_ELEM.toString());
for (int j = 0; j < artifactNodes.getLength(); ++j) {
Element artifactElem = (Element) artifactNodes.item(j);
// Get the artifact type.
final String type = getElementAttributeValue(artifactElem, AttributeNames.TYPE_ATTR.toString());
if (!type.isEmpty()) {
// Get the source file of the artifact and the attributes,
// if any.
final String sourceFilePath = this.getChildElementContent(artifactElem, TagNames.SOURCE_FILE_ELEM.toString(), true);
if (!sourceFilePath.isEmpty()) {
ExternalResults.Artifact artifact = this.resultsData.addArtifact(type, sourceFilePath);
parseArtifactAttributes(artifactElem, artifact);
}
}
}
}
}
private void parseArtifactAttributes(final Element artifactElem, ExternalResults.Artifact artifact) {
// Get the artifact attributes.
NodeList attributeNodesList = artifactElem.getElementsByTagName(TagNames.ATTRIBUTE_ELEM.toString());
for (int i = 0; i < attributeNodesList.getLength(); ++i) {
Element attributeElem = (Element) attributeNodesList.item(i);
final String type = getElementAttributeValue(attributeElem, AttributeNames.TYPE_ATTR.toString());
if (type.isEmpty()) {
continue;
}
// Get the value of the artifact attribute.
Element valueElem = this.getChildElement(attributeElem, TagNames.VALUE_ELEM.toString());
if (valueElem == null) {
continue;
}
final String value = valueElem.getTextContent();
if (value.isEmpty()) {
String errorMessage = NbBundle.getMessage(this.getClass(),
"ExternalResultsXMLParser.parseArtifactAttributes.errMsg1.text",
TagNames.VALUE_ELEM.toString(), this.resultsFilePath);
recordError(errorMessage);
continue;
}
// Get the value type.
String valueType = parseArtifactAttributeValueType(valueElem);
if (valueType.isEmpty()) {
continue;
}
// Get the optional source module.
String sourceModule = this.getChildElementContent(attributeElem, TagNames.SOURCE_MODULE_ELEM.toString(), false);
// Add the attribute to the artifact.
artifact.addAttribute(type, value, valueType, sourceModule);
}
}
private String parseArtifactAttributeValueType(Element valueElem) {
String valueType = valueElem.getAttribute(AttributeNames.TYPE_ATTR.toString());
if (valueType.isEmpty()) {
// Default to text.
valueType = AttributeValues.VALUE_TYPE_TEXT.toString();
} else if (!valueType.equals(AttributeValues.VALUE_TYPE_TEXT.toString())
&& !valueType.equals(AttributeValues.VALUE_TYPE_DOUBLE.toString())
&& !valueType.equals(AttributeValues.VALUE_TYPE_INT32.toString())
&& !valueType.equals(AttributeValues.VALUE_TYPE_INT64.toString())
&& !valueType.equals(AttributeValues.VALUE_TYPE_DATETIME.toString())) {
String errorMessage = NbBundle.getMessage(this.getClass(),
"ExternalResultsXMLParser.parseAttributeValueType.errMsg1.text",
valueType,
AttributeNames.TYPE_ATTR.toString(),
TagNames.VALUE_ELEM.toString());
this.recordError(errorMessage);
valueType = "";
}
return valueType;
}
private void parseReports(Element root) {
// Get the report lists.
NodeList reportsListNodes = root.getElementsByTagName(TagNames.REPORTS_LIST_ELEM.toString());
for (int i = 0; i < reportsListNodes.getLength(); ++i) {
Element reportsListElem = (Element) reportsListNodes.item(i);
// Get the reports.
NodeList reportNodes = reportsListElem.getElementsByTagName(TagNames.REPORT_ELEM.toString());
for (int j = 0; j < reportNodes.getLength(); ++j) {
Element reportElem = (Element) reportNodes.item(j);
// Get the local path.
String path = getChildElementContent(reportElem, TagNames.LOCAL_PATH_ELEM.toString(), true);
if (path.isEmpty()) {
continue;
}
// Get the source module.
String sourceModule = getChildElementContent(reportElem, TagNames.SOURCE_MODULE_ELEM.toString(), true);
if (path.isEmpty()) {
continue;
}
// Get the optional report name.
String reportName = getChildElementContent(reportElem, TagNames.REPORT_NAME_ELEM.toString(), false);
this.resultsData.addReport(path, sourceModule, reportName);
}
}
}
private String getElementAttributeValue(Element element, String attributeName) {
final String attributeValue = element.getAttribute(attributeName);
if (attributeValue.isEmpty()) {
logger.log(Level.SEVERE, "Found {0} element missing {1} attribute in {2}", new Object[]{ //NON-NLS
element.getTagName(),
attributeName,
this.resultsFilePath});
}
return attributeValue;
}
private String getChildElementContent(Element parentElement, String childElementTagName, boolean required) {
String content = "";
Element childElement = this.getChildElement(parentElement, childElementTagName);
if (childElement != null) {
content = childElement.getTextContent();
if (content.isEmpty()) {
String errorMessage = NbBundle.getMessage(this.getClass(),
"ExternalResultsXMLParser.getChildElementContent.errMsg1.text",
parentElement.getTagName(),
childElementTagName,
this.resultsFilePath);
this.recordError(errorMessage);
}
} else if (required) {
String errorMessage = NbBundle.getMessage(this.getClass(), "ExternalResultsXMLParser.getChildElementContent.errMsg2.text",
parentElement.getTagName(),
childElementTagName,
this.resultsFilePath);
this.recordError(errorMessage);
}
return content;
}
private Element getChildElement(Element parentElement, String childElementTagName) {
Element childElem = null;
NodeList childNodes = parentElement.getElementsByTagName(childElementTagName);
if (childNodes.getLength() > 0) {
childElem = (Element) childNodes.item(0);
if (childNodes.getLength() > 1) {
String errorMessage = NbBundle.getMessage(this.getClass(), "ExternalResultsXMLParser.getChildElement.errMsg1.text",
childElementTagName,
parentElement.getTagName(),
this.resultsFilePath);
this.recordError(errorMessage);
}
}
return childElem;
}
private void recordError(String errorMessage) {
ExternalResultsXMLParser.logger.log(Level.SEVERE, errorMessage);
this.errors.add(new ErrorInfo(this.getClass().getSimpleName(), errorMessage));
}
private void recordError(String errorMessage, Exception ex) {
ExternalResultsXMLParser.logger.log(Level.SEVERE, errorMessage, ex);
this.errors.add(new ErrorInfo(this.getClass().getSimpleName(), errorMessage, ex));
}
}

View File

@ -1,70 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="autopsy_results">
<xs:complexType>
<xs:sequence minOccurs="0" maxOccurs="1">
<xs:element minOccurs="0" maxOccurs="1" name="data_source" type="xs:string" />
<xs:element minOccurs="0" maxOccurs="unbounded" name="derived_files">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" name="derived_file">
<xs:complexType>
<xs:sequence>
<xs:element name="local_path" type="xs:string" />
<xs:element minOccurs="0" name="parent_file" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element minOccurs="0" maxOccurs="unbounded" name="artifacts">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" name="artifact">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="1" name="source_file" type="xs:string" />
<xs:element minOccurs="0" maxOccurs="unbounded" name="attribute">
<xs:complexType>
<xs:sequence>
<xs:element name="value">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="type" type="xs:string" use="optional" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="source_module" type="xs:string" />
</xs:sequence>
<xs:attribute name="type" type="xs:string" use="required" />
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="type" type="xs:string" use="required" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element minOccurs="0" maxOccurs="unbounded" name="reports">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" name="report">
<xs:complexType>
<xs:sequence>
<xs:element name="local_path" type="xs:string" />
<xs:element name="source_module" type="xs:string" />
<xs:element minOccurs="0" maxOccurs="1" name="report_name" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>

View File

@ -30,6 +30,7 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.logging.Level; import java.util.logging.Level;
import org.netbeans.api.progress.ProgressHandle; import org.netbeans.api.progress.ProgressHandle;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.core.RuntimeProperties; import org.sleuthkit.autopsy.core.RuntimeProperties;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
@ -130,6 +131,10 @@ class ImageWriter implements PropertyChangeListener{
} }
} }
@Messages({
"# {0} - data source name",
"ImageWriter.progressBar.message=Finishing acquisition of {0}"
})
private void startFinishImage(String dataSourceName){ private void startFinishImage(String dataSourceName){
synchronized(currentTasksLock){ synchronized(currentTasksLock){
@ -166,7 +171,7 @@ class ImageWriter implements PropertyChangeListener{
if(doUI){ if(doUI){
periodicTasksExecutor = new ScheduledThreadPoolExecutor(1, new ThreadFactoryBuilder().setNameFormat("image-writer-progress-update-%d").build()); //NON-NLS periodicTasksExecutor = new ScheduledThreadPoolExecutor(1, new ThreadFactoryBuilder().setNameFormat("image-writer-progress-update-%d").build()); //NON-NLS
progressHandle = ProgressHandle.createHandle("Image writer - " + dataSourceName); progressHandle = ProgressHandle.createHandle(Bundle.ImageWriter_progressBar_message(dataSourceName));
progressHandle.start(100); progressHandle.start(100);
progressUpdateTask = periodicTasksExecutor.scheduleAtFixedRate( progressUpdateTask = periodicTasksExecutor.scheduleAtFixedRate(
new ProgressUpdateTask(progressHandle, imageHandle), 0, 250, TimeUnit.MILLISECONDS); new ProgressUpdateTask(progressHandle, imageHandle), 0, 250, TimeUnit.MILLISECONDS);

View File

@ -29,7 +29,6 @@ import org.openide.NotifyDescriptor;
import org.openide.util.Lookup; import org.openide.util.Lookup;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.examples.SampleExecutableIngestModuleFactory;
import org.sleuthkit.autopsy.examples.SampleIngestModuleFactory; import org.sleuthkit.autopsy.examples.SampleIngestModuleFactory;
import org.sleuthkit.autopsy.modules.e01verify.E01VerifierModuleFactory; import org.sleuthkit.autopsy.modules.e01verify.E01VerifierModuleFactory;
import org.sleuthkit.autopsy.modules.exif.ExifParserModuleFactory; import org.sleuthkit.autopsy.modules.exif.ExifParserModuleFactory;
@ -48,7 +47,6 @@ final class IngestModuleFactoryLoader {
private static final Logger logger = Logger.getLogger(IngestModuleFactoryLoader.class.getName()); private static final Logger logger = Logger.getLogger(IngestModuleFactoryLoader.class.getName());
private static final String SAMPLE_MODULE_FACTORY_CLASS_NAME = SampleIngestModuleFactory.class.getCanonicalName(); private static final String SAMPLE_MODULE_FACTORY_CLASS_NAME = SampleIngestModuleFactory.class.getCanonicalName();
private static final String SAMPLE_EXECUTABLE_MODULE_FACTORY_CLASS_NAME = SampleExecutableIngestModuleFactory.class.getCanonicalName();
private static final ArrayList<String> coreModuleOrdering = new ArrayList<String>() { private static final ArrayList<String> coreModuleOrdering = new ArrayList<String>() {
{ {
// The ordering of the core ingest module factories implemented // The ordering of the core ingest module factories implemented
@ -141,8 +139,7 @@ final class IngestModuleFactoryLoader {
private static void addFactory(IngestModuleFactory factory, HashSet<String> moduleDisplayNames, HashMap<String, IngestModuleFactory> javaFactoriesByClass) { private static void addFactory(IngestModuleFactory factory, HashSet<String> moduleDisplayNames, HashMap<String, IngestModuleFactory> javaFactoriesByClass) {
// Ignore the sample ingest module factories implemented in Java. // Ignore the sample ingest module factories implemented in Java.
String className = factory.getClass().getCanonicalName(); String className = factory.getClass().getCanonicalName();
if (className.equals(IngestModuleFactoryLoader.SAMPLE_MODULE_FACTORY_CLASS_NAME) if (className.equals(IngestModuleFactoryLoader.SAMPLE_MODULE_FACTORY_CLASS_NAME)) {
|| className.equals(IngestModuleFactoryLoader.SAMPLE_EXECUTABLE_MODULE_FACTORY_CLASS_NAME)) {
return; return;
} }

View File

@ -192,8 +192,6 @@ public final class IngestMonitor {
} }
logMemoryUsage(); logMemoryUsage();
logDiskSpaceUsage();
if (!enoughDiskSpace()) { if (!enoughDiskSpace()) {
/* /*
* Shut down ingest by cancelling all ingest jobs. * Shut down ingest by cancelling all ingest jobs.

View File

@ -0,0 +1,122 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2017 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.experimental.autoingest;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import org.apache.commons.io.FilenameUtils;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.Content;
/*
* A runnable that adds an archive data source as well as data sources
* contained in the archive to the case database.
*/
class AddArchiveTask implements Runnable {
private final Logger logger = Logger.getLogger(AddArchiveTask.class.getName());
private final String deviceId;
private final String archivePath;
private final DataSourceProcessorProgressMonitor progressMonitor;
private final DataSourceProcessorCallback callback;
private boolean criticalErrorOccurred;
private static final String ARCHIVE_EXTRACTOR_MODULE_OUTPUT_DIR = "Archive Extractor";
/**
* Constructs a runnable task that adds an archive as well as data sources
* contained in the archive to the case database.
*
* @param deviceId An ASCII-printable identifier for the device associated
* with the data source that is intended to be unique across multiple cases
* (e.g., a UUID).
* @param archivePath Path to the archive file.
* @param progressMonitor Progress monitor to report progress during
* processing.
* @param callback Callback to call when processing is done.
*/
AddArchiveTask(String deviceId, String archivePath, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) {
this.deviceId = deviceId;
this.archivePath = archivePath;
this.callback = callback;
this.progressMonitor = progressMonitor;
}
/**
* Adds the archive to the case database.
*/
@Override
public void run() {
List<String> errorMessages = new ArrayList<>();
List<Content> newDataSources = new ArrayList<>();
DataSourceProcessorCallback.DataSourceProcessorResult result;
if (!ArchiveUtil.isArchive(Paths.get(archivePath))) {
criticalErrorOccurred = true;
logger.log(Level.SEVERE, String.format("Input data source is not a valid datasource: %s", archivePath)); //NON-NLS
errorMessages.add("Input data source is not a valid datasource: " + archivePath);
result = DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS;
callback.done(result, errorMessages, newDataSources);
}
// extract the archive and pass the extracted folder as input
Path destinationFolder = Paths.get("");
try {
Case currentCase = Case.getCurrentCase();
// get file name without full path or extension
String dataSourceFileNameNoExt = FilenameUtils.getBaseName(archivePath);
// create folder to extract archive to
destinationFolder = Paths.get(currentCase.getModuleDirectory(), ARCHIVE_EXTRACTOR_MODULE_OUTPUT_DIR, dataSourceFileNameNoExt + "_" + TimeStampUtils.createTimeStamp());
destinationFolder.toFile().mkdirs();
// extract contents of ZIP archive into destination folder
//ArchiveUtil.unpackArchiveFile(archivePath, destinationFolder.toString());
// do processing
} catch (Exception ex) {
criticalErrorOccurred = true;
errorMessages.add(ex.getMessage());
logger.log(Level.SEVERE, String.format("Critical error occurred while extracting archive %s", archivePath), ex); //NON-NLS
} finally {
if (criticalErrorOccurred) {
result = DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS;
} else if (!errorMessages.isEmpty()) {
result = DataSourceProcessorCallback.DataSourceProcessorResult.NONCRITICAL_ERRORS;
} else {
result = DataSourceProcessorCallback.DataSourceProcessorResult.NO_ERRORS;
}
callback.done(result, errorMessages, newDataSources);
}
}
/*
* Attempts to cancel adding the archive to the case database.
*/
public void cancelTask() {
}
}

View File

@ -0,0 +1,98 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2017 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.experimental.autoingest;
import java.util.List;
import java.util.UUID;
import javax.annotation.concurrent.Immutable;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback;
import org.sleuthkit.datamodel.Content;
/**
* A "callback" that collects the results of running a data source processor on
* a data source and unblocks the job processing thread when the data source
* processor finishes running in its own thread.
*/
@Immutable
class AddDataSourceCallback extends DataSourceProcessorCallback {
private final Case caseForJob;
private final DataSource dataSourceInfo;
private final UUID taskId;
private final Object lock;
/**
* Constructs a "callback" that collects the results of running a data
* source processor on a data source and unblocks the job processing thread
* when the data source processor finishes running in its own thread.
*
* @param caseForJob The case for the current job.
* @param dataSourceInfo The data source
* @param taskId The task id to associate with ingest job events.
*/
AddDataSourceCallback(Case caseForJob, DataSource dataSourceInfo, UUID taskId, Object lock) {
this.caseForJob = caseForJob;
this.dataSourceInfo = dataSourceInfo;
this.taskId = taskId;
this.lock = lock;
}
/**
* Called by the data source processor when it finishes running in its own
* thread.
*
* @param result The result code for the processing of the data source.
* @param errorMessages Any error messages generated during the processing
* of the data source.
* @param dataSourceContent The content produced by processing the data
* source.
*/
@Override
public void done(DataSourceProcessorCallback.DataSourceProcessorResult result, List<String> errorMessages, List<Content> dataSourceContent) {
if (!dataSourceContent.isEmpty()) {
caseForJob.notifyDataSourceAdded(dataSourceContent.get(0), taskId);
} else {
caseForJob.notifyFailedAddingDataSource(taskId);
}
dataSourceInfo.setDataSourceProcessorOutput(result, errorMessages, dataSourceContent);
dataSourceContent.addAll(dataSourceContent);
synchronized (lock) {
lock.notify();
}
}
/**
* Called by the data source processor when it finishes running in its own
* thread, if that thread is the AWT (Abstract Window Toolkit) event
* dispatch thread (EDT).
*
* @param result The result code for the processing of the data source.
* @param errorMessages Any error messages generated during the processing
* of the data source.
* @param dataSourceContent The content produced by processing the data
* source.
*/
@Override
public void doneEDT(DataSourceProcessorCallback.DataSourceProcessorResult result, List<String> errorMessages, List<Content> dataSources) {
done(result, errorMessages, dataSources);
}
}

View File

@ -0,0 +1,224 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2017 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.experimental.autoingest;
import java.nio.file.Path;
import java.util.UUID;
import javax.swing.JPanel;
import org.openide.util.NbBundle;
import org.openide.util.lookup.ServiceProvider;
import org.openide.util.lookup.ServiceProviders;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor;
import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor;
/**
* A data source processor that handles archive files. Implements the
* DataSourceProcessor service provider interface to allow integration with the
* add data source wizard. It also provides a run method overload to allow it to
* be used independently of the wizard.
*/
//@ServiceProviders(value={
// @ServiceProvider(service=DataSourceProcessor.class),
// @ServiceProvider(service=AutoIngestDataSourceProcessor.class)}
//)
@NbBundle.Messages({
"ArchiveDSP.dsType.text=Archive file"})
public class ArchiveExtractorDSProcessor implements DataSourceProcessor, AutoIngestDataSourceProcessor {
private final static String DATA_SOURCE_TYPE = Bundle.ArchiveDSP_dsType_text();
private final ArchiveFilePanel configPanel;
private String deviceId;
private String archivePath;
private boolean setDataSourceOptionsCalled;
private AddArchiveTask addArchiveTask;
/**
* Constructs an archive data source processor that
* implements the DataSourceProcessor service provider interface to allow
* integration with the add data source wizard. It also provides a run
* method overload to allow it to be used independently of the wizard.
*/
public ArchiveExtractorDSProcessor() {
configPanel = ArchiveFilePanel.createInstance(ArchiveExtractorDSProcessor.class.getName(), ArchiveUtil.getArchiveFilters());
}
@Override
public int canProcess(Path dataSourcePath) throws AutoIngestDataSourceProcessorException {
// check whether this is an archive
if (ArchiveUtil.isArchive(dataSourcePath)){
// return "high confidence" value
return 100;
}
return 0;
}
@Override
public void process(String deviceId, Path dataSourcePath, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callBack) throws AutoIngestDataSourceProcessorException {
run(deviceId, dataSourcePath.toString(), progressMonitor, callBack);
}
@Override
public String getDataSourceType() {
return DATA_SOURCE_TYPE;
}
/**
* Gets the panel that allows a user to select a data source and do any
* configuration required by the data source. The panel is less than 544
* pixels wide and less than 173 pixels high.
*
* @return A selection and configuration panel for this data source
* processor.
*/
@Override
public JPanel getPanel() {
configPanel.readSettings();
configPanel.select();
return configPanel;
}
/**
* Indicates whether the settings in the selection and configuration panel
* are valid and complete.
*
* @return True if the settings are valid and complete and the processor is
* ready to have its run method called, false otherwise.
*/
@Override
public boolean isPanelValid() {
return configPanel.validatePanel();
}
/**
* Adds a data source to the case database using a background task in a
* separate thread and the settings provided by the selection and
* configuration panel. Returns as soon as the background task is started.
* The background task uses a callback object to signal task completion and
* return results.
*
* This method should not be called unless isPanelValid returns true.
*
* @param progressMonitor Progress monitor that will be used by the
* background task to report progress.
* @param callback Callback that will be used by the background task
* to return results.
*/
@Override
public void run(DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) {
if (!setDataSourceOptionsCalled) {
configPanel.storeSettings();
deviceId = UUID.randomUUID().toString();
archivePath = configPanel.getContentPaths();
}
run(deviceId, archivePath, progressMonitor, callback);
}
/**
* Adds a data source to the case database using a background task in a
* separate thread and the given settings instead of those provided by the
* selection and configuration panel. Returns as soon as the background task
* is started and uses the callback object to signal task completion and
* return results.
*
* @param deviceId An ASCII-printable identifier for the device
* associated with the data source that is
* intended to be unique across multiple cases
* (e.g., a UUID).
* @param archivePath Path to the archive file.
* @param progressMonitor Progress monitor for reporting progress
* during processing.
* @param callback Callback to call when processing is done.
*/
public void run(String deviceId, String archivePath, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) {
addArchiveTask = new AddArchiveTask(deviceId, archivePath, progressMonitor, callback);
new Thread(addArchiveTask).start();
}
/**
* Requests cancellation of the background task that adds a data source to
* the case database, after the task is started using the run method. This
* is a "best effort" cancellation, with no guarantees that the case
* database will be unchanged. If cancellation succeeded, the list of new
* data sources returned by the background task will be empty.
*/
@Override
public void cancel() {
if (null != addArchiveTask) {
addArchiveTask.cancelTask();
}
}
@Override
public void reset() {
deviceId = null;
archivePath = null;
configPanel.reset();
setDataSourceOptionsCalled = false;
}
/**
* Extracts the contents of a ZIP archive submitted as a data source to a
* subdirectory of the auto ingest module output directory.
*
* @throws IOException if there is a problem extracting the data source from
* the archive.
private static Path extractDataSource(Path outputDirectoryPath, Path dataSourcePath) throws IOException {
String dataSourceFileNameNoExt = FilenameUtils.removeExtension(dataSourcePath.getFileName().toString());
Path destinationFolder = Paths.get(outputDirectoryPath.toString(),
AUTO_INGEST_MODULE_OUTPUT_DIR,
dataSourceFileNameNoExt + "_" + TimeStampUtils.createTimeStamp());
Files.createDirectories(destinationFolder);
int BUFFER_SIZE = 524288; // Read/write 500KB at a time
File sourceZipFile = dataSourcePath.toFile();
ZipFile zipFile;
zipFile = new ZipFile(sourceZipFile, ZipFile.OPEN_READ);
Enumeration<? extends ZipEntry> zipFileEntries = zipFile.entries();
try {
while (zipFileEntries.hasMoreElements()) {
ZipEntry entry = zipFileEntries.nextElement();
String currentEntry = entry.getName();
File destFile = new File(destinationFolder.toString(), currentEntry);
destFile = new File(destinationFolder.toString(), destFile.getName());
File destinationParent = destFile.getParentFile();
destinationParent.mkdirs();
if (!entry.isDirectory()) {
BufferedInputStream is = new BufferedInputStream(zipFile.getInputStream(entry));
int currentByte;
byte data[] = new byte[BUFFER_SIZE];
try (FileOutputStream fos = new FileOutputStream(destFile); BufferedOutputStream dest = new BufferedOutputStream(fos, BUFFER_SIZE)) {
currentByte = is.read(data, 0, BUFFER_SIZE);
while (currentByte != -1) {
dest.write(data, 0, currentByte);
currentByte = is.read(data, 0, BUFFER_SIZE);
}
}
}
}
} finally {
zipFile.close();
}
return destinationFolder;
} */
}

View File

@ -0,0 +1,94 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<Properties>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[0, 65]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[403, 65]"/>
</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">
<Component id="pathTextField" max="32767" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="browseButton" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="2" max="-2" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="pathLabel" min="-2" max="-2" attributes="0"/>
<Component id="errorLabel" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="0" pref="277" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Component id="pathLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="browseButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="pathTextField" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" pref="3" max="-2" attributes="0"/>
<Component id="errorLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JLabel" name="pathLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="ArchiveFilePanel.pathLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="browseButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="ArchiveFilePanel.browseButton.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="browseButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JTextField" name="pathTextField">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="ArchiveFilePanel.pathTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="errorLabel">
<Properties>
<Property name="foreground" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
<Color blue="0" green="0" red="ff" type="rgb"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties" key="ArchiveFilePanel.errorLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Form>

View File

@ -0,0 +1,280 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2017 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.experimental.autoingest;
import java.io.File;
import java.util.List;
import java.util.logging.Level;
import javax.swing.JFileChooser;
import javax.swing.JPanel;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.filechooser.FileFilter;
import org.apache.commons.lang3.StringUtils;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.Case;
import static org.sleuthkit.autopsy.experimental.autoingest.Bundle.*;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
import org.sleuthkit.autopsy.coreutils.DriveUtils;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
import org.sleuthkit.autopsy.coreutils.PathValidator;
/**
* Panel for adding an archive file which is supported by 7zip library (e.g.
* "zip", "rar", "arj", "7z", "7zip", "gzip, etc). Allows the user to select a
* file.
*/
class ArchiveFilePanel extends JPanel implements DocumentListener {
private static final Logger logger = Logger.getLogger(ArchiveFilePanel.class.getName());
private static final String PROP_LAST_ARCHIVE_PATH = "LBL_LastImage_PATH"; //NON-NLS
private final JFileChooser fileChooser = new JFileChooser();
/**
* Externally supplied name is used to store settings
*/
private final String contextName;
/**
* Creates new form ArchiveFilePanel
*
* @param context A string context name used to read/store last
* used settings.
* @param fileChooserFilters A list of filters to be used with the
* FileChooser.
*/
private ArchiveFilePanel(String context, List<FileFilter> fileChooserFilters) {
this.contextName = context;
initComponents();
errorLabel.setVisible(false);
fileChooser.setDragEnabled(false);
fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
fileChooser.setMultiSelectionEnabled(false);
fileChooserFilters.forEach(fileChooser::addChoosableFileFilter);
if (fileChooserFilters.isEmpty() == false) {
fileChooser.setFileFilter(fileChooserFilters.get(0));
}
}
/**
* Creates and returns an instance of a ArchiveFilePanel.
*
* @param context A string context name used to read/store last
* used settings.
* @param fileChooserFilters A list of filters to be used with the
* FileChooser.
*
* @return instance of the ArchiveFilePanel
*/
public static synchronized ArchiveFilePanel createInstance(String context, List<FileFilter> fileChooserFilters) {
ArchiveFilePanel instance = new ArchiveFilePanel(context, fileChooserFilters);
// post-constructor initialization of listener support without leaking references of uninitialized objects
instance.pathTextField.getDocument().addDocumentListener(instance);
return instance;
}
/**
* 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.
*/
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
pathLabel = new javax.swing.JLabel();
browseButton = new javax.swing.JButton();
pathTextField = new javax.swing.JTextField();
errorLabel = new javax.swing.JLabel();
setMinimumSize(new java.awt.Dimension(0, 65));
setPreferredSize(new java.awt.Dimension(403, 65));
org.openide.awt.Mnemonics.setLocalizedText(pathLabel, org.openide.util.NbBundle.getMessage(ArchiveFilePanel.class, "ArchiveFilePanel.pathLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(browseButton, org.openide.util.NbBundle.getMessage(ArchiveFilePanel.class, "ArchiveFilePanel.browseButton.text")); // NOI18N
browseButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
browseButtonActionPerformed(evt);
}
});
pathTextField.setText(org.openide.util.NbBundle.getMessage(ArchiveFilePanel.class, "ArchiveFilePanel.pathTextField.text")); // NOI18N
errorLabel.setForeground(new java.awt.Color(255, 0, 0));
org.openide.awt.Mnemonics.setLocalizedText(errorLabel, org.openide.util.NbBundle.getMessage(ArchiveFilePanel.class, "ArchiveFilePanel.errorLabel.text")); // NOI18N
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(pathTextField)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(browseButton)
.addGap(2, 2, 2))
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(pathLabel)
.addComponent(errorLabel))
.addGap(0, 277, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(pathLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(browseButton)
.addComponent(pathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGap(3, 3, 3)
.addComponent(errorLabel)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
}// </editor-fold>//GEN-END:initComponents
private void browseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseButtonActionPerformed
String oldText = getContentPaths();
// set the current directory of the FileChooser if the ArchivePath Field is valid
File currentDir = new File(oldText);
if (currentDir.exists()) {
fileChooser.setCurrentDirectory(currentDir);
}
if (fileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
String path = fileChooser.getSelectedFile().getPath();
setContentPath(path);
}
updateHelper();
}//GEN-LAST:event_browseButtonActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton browseButton;
private javax.swing.JLabel errorLabel;
private javax.swing.JLabel pathLabel;
private javax.swing.JTextField pathTextField;
// End of variables declaration//GEN-END:variables
/**
* Get the path of the user selected archive.
*
* @return the archive path
*/
public String getContentPaths() {
return pathTextField.getText();
}
/**
* Set the path of the archive file.
*
* @param s path of the archive file
*/
public void setContentPath(String s) {
pathTextField.setText(s);
}
public void reset() {
//reset the UI elements to default
pathTextField.setText(null);
}
/**
* Should we enable the next button of the wizard?
*
* @return true if a proper archive has been selected, false otherwise
*/
@NbBundle.Messages("DataSourceOnCDriveError.text=Warning: Path to multi-user data source is on \"C:\" drive")
public boolean validatePanel() {
errorLabel.setVisible(false);
String path = getContentPaths();
if (StringUtils.isBlank(path)) {
return false;
}
// display warning if there is one (but don't disable "next" button)
if (false == PathValidator.isValid(path, Case.getCurrentCase().getCaseType())) {
errorLabel.setVisible(true);
errorLabel.setText(Bundle.DataSourceOnCDriveError_text());
}
return new File(path).isFile()
|| DriveUtils.isPhysicalDrive(path)
|| DriveUtils.isPartition(path);
}
public void storeSettings() {
String archivePathName = getContentPaths();
if (null != archivePathName) {
String archivePath = archivePathName.substring(0, archivePathName.lastIndexOf(File.separator) + 1);
ModuleSettings.setConfigSetting(contextName, PROP_LAST_ARCHIVE_PATH, archivePath);
}
}
public void readSettings() {
String lastArchivePath = ModuleSettings.getConfigSetting(contextName, PROP_LAST_ARCHIVE_PATH);
if (StringUtils.isNotBlank(lastArchivePath)) {
setContentPath(lastArchivePath);
}
}
@Override
public void insertUpdate(DocumentEvent e) {
updateHelper();
}
@Override
public void removeUpdate(DocumentEvent e) {
updateHelper();
}
@Override
public void changedUpdate(DocumentEvent e) {
updateHelper();
}
/**
* Update functions are called by the pathTextField which has this set as
* it's DocumentEventListener. Each update function fires a property change
* to be caught by the parent panel.
*
*/
@NbBundle.Messages({"ArchiveFilePanel.moduleErr=Module Error",
"ArchiveFilePanel.moduleErr.msg=A module caused an error listening to ArchiveFilePanel updates."
+ " See log to determine which module. Some data could be incomplete.\n"})
private void updateHelper() {
try {
firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), false, true);
} catch (Exception e) {
logger.log(Level.SEVERE, "ArchiveFilePanel listener threw exception", e); //NON-NLS
MessageNotifyUtil.Notify.error(ArchiveFilePanel_moduleErr(), ArchiveFilePanel_moduleErr_msg());
}
}
/**
* Set the focus to the pathTextField.
*/
public void select() {
pathTextField.requestFocusInWindow();
}
}

View File

@ -26,7 +26,9 @@ import java.io.RandomAccessFile;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import javax.swing.filechooser.FileFilter;
import net.sf.sevenzipjbinding.ISequentialOutStream; import net.sf.sevenzipjbinding.ISequentialOutStream;
import net.sf.sevenzipjbinding.ISevenZipInArchive; import net.sf.sevenzipjbinding.ISevenZipInArchive;
import net.sf.sevenzipjbinding.SevenZip; import net.sf.sevenzipjbinding.SevenZip;
@ -35,18 +37,46 @@ import net.sf.sevenzipjbinding.SevenZipNativeInitializationException;
import net.sf.sevenzipjbinding.impl.RandomAccessFileInStream; import net.sf.sevenzipjbinding.impl.RandomAccessFileInStream;
import net.sf.sevenzipjbinding.simple.ISimpleInArchive; import net.sf.sevenzipjbinding.simple.ISimpleInArchive;
import net.sf.sevenzipjbinding.simple.ISimpleInArchiveItem; import net.sf.sevenzipjbinding.simple.ISimpleInArchiveItem;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.GeneralFilter;
/** /**
* Set of utilities that handles archive file extraction. Uses 7zip library. * Set of utilities that handles archive file extraction. Uses 7zip library.
*/ */
final class ArchiveUtil { final class ArchiveUtil {
static final String[] SUPPORTED_EXTENSIONS = {"zip", "rar", "arj", "7z", "7zip", "gzip", "gz", "bzip2", "tar", "tgz",}; // NON-NLS private static final String[] SUPPORTED_EXTENSIONS = {"zip", "rar", "arj", "7z", "7zip", "gzip", "gz", "bzip2", "tar", "tgz",}; // NON-NLS
private static final List<String> ARCHIVE_EXTS = Arrays.asList(".zip", ".rar", ".arj", ".7z", ".7zip", ".gzip", ".gz", ".bzip2", ".tar", ".tgz"); //NON-NLS
@NbBundle.Messages("GeneralFilter.archiveDesc.text=Archive Files (.zip, .rar, .arj, .7z, .7zip, .gzip, .gz, .bzip2, .tar, .tgz)")
private static final String ARCHIVE_DESC = Bundle.GeneralFilter_archiveDesc_text();
private static final GeneralFilter SEVEN_ZIP_FILTER = new GeneralFilter(ARCHIVE_EXTS, ARCHIVE_DESC);
private static final List<FileFilter> ARCHIVE_FILTERS = new ArrayList<>();
static {
ARCHIVE_FILTERS.add(SEVEN_ZIP_FILTER);
}
private ArchiveUtil() { private ArchiveUtil() {
} }
static List<FileFilter> getArchiveFilters() {
return ARCHIVE_FILTERS;
}
static boolean isArchive(Path dataSourcePath) {
String fileName = dataSourcePath.getFileName().toString();
// check whether it's a zip archive file that can be extracted
return isAcceptedByFiler(new File(fileName), ARCHIVE_FILTERS);
}
private static boolean isAcceptedByFiler(File file, List<FileFilter> filters) {
for (FileFilter filter : filters) {
if (filter.accept(file)) {
return true;
}
}
return false;
}
/** /**
* Enum of mime types which support archive extraction * Enum of mime types which support archive extraction
*/ */

View File

@ -18,37 +18,32 @@
*/ */
package org.sleuthkit.autopsy.experimental.autoingest; package org.sleuthkit.autopsy.experimental.autoingest;
import java.io.IOException;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.logging.Level;
import javax.swing.SwingUtilities;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.util.actions.CallableSystemAction;
import org.sleuthkit.autopsy.casemodule.AddImageAction;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.CaseActionException; import org.sleuthkit.autopsy.casemodule.CaseActionException;
import org.sleuthkit.autopsy.casemodule.CaseNewAction; import org.sleuthkit.autopsy.coordinationservice.CoordinationService;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coordinationservice.CoordinationService.CoordinationServiceException;
import org.sleuthkit.autopsy.experimental.configuration.AutoIngestUserPreferences;
/** /**
* Handles locating and opening cases created by auto ingest. * Handles locating and opening cases created by auto ingest.
*/ */
final class AutoIngestCaseManager { final class AutoIngestCaseManager {
private static final Logger LOGGER = Logger.getLogger(AutoIngestCaseManager.class.getName());
private static AutoIngestCaseManager instance; private static AutoIngestCaseManager instance;
private CoordinationService coordinationService;
/** /**
* Gets the auto ingest case manager. * Gets the auto ingest case manager.
* *
* @return The auto ingest case manager singleton. * @return The auto ingest case manager singleton.
*
* @throws AutoIngestCaseManagerException
*/ */
synchronized static AutoIngestCaseManager getInstance() { synchronized static AutoIngestCaseManager getInstance() throws AutoIngestCaseManager.AutoIngestCaseManagerException {
if (null == instance) { if (null == instance) {
instance = new AutoIngestCaseManager(); instance = new AutoIngestCaseManager();
} }
@ -58,38 +53,67 @@ final class AutoIngestCaseManager {
/** /**
* Constructs an object that handles locating and opening cases created by * Constructs an object that handles locating and opening cases created by
* auto ingest. * auto ingest.
*
* @throws AutoIngestCaseManagerException
*/ */
private AutoIngestCaseManager() { private AutoIngestCaseManager() throws AutoIngestCaseManagerException {
try {
/* coordinationService = CoordinationService.getInstance();
* Permanently delete the "Open Recent Cases" item in the "File" menu. } catch (CoordinationServiceException ex) {
* This is quite drastic, as it also affects Autopsy standalone mode on throw new AutoIngestCaseManager.AutoIngestCaseManagerException("Failed to get the coordination service.", ex);
* this machine, but review mode is only for looking at cases created by
* automated ingest.
*/
FileObject root = FileUtil.getConfigRoot();
FileObject openRecentCasesMenu = root.getFileObject("Menu/Case/OpenRecentCase");
if (openRecentCasesMenu != null) {
try {
openRecentCasesMenu.delete();
} catch (IOException ex) {
AutoIngestCaseManager.LOGGER.log(Level.WARNING, "Unable to remove Open Recent Cases file menu item", ex);
}
} }
} }
/* /**
* Gets a list of the cases in the top level case folder used by auto * Gets a list of the cases in the top level case folder used by auto
* ingest. * ingest.
*
* @return List of cases.
*
* @throws AutoIngestCaseManagerException
*/ */
List<AutoIngestCase> getCases() { List<AutoIngestCase> getCases() throws AutoIngestCaseManagerException {
List<AutoIngestCase> cases = new ArrayList<>(); List<AutoIngestCase> cases = new ArrayList<>();
List<Path> caseFolders = PathUtils.findCaseFolders(Paths.get(AutoIngestUserPreferences.getAutoModeResultsFolder())); List<Path> casePathList = getCasePaths();
for (Path caseFolderPath : caseFolders) { for (Path casePath : casePathList) {
cases.add(new AutoIngestCase(caseFolderPath)); cases.add(new AutoIngestCase(casePath));
} }
return cases; return cases;
} }
/**
* Retrieve all of the case nodes and filter for only those that represent
* case paths.
*
* @return List of case paths.
*
* @throws AutoIngestCaseManagerException
*/
private List<Path> getCasePaths() throws AutoIngestCaseManagerException {
try {
List<String> nodeList = coordinationService.getNodeList(CoordinationService.CategoryNode.CASES);
List<Path> casePathList = new ArrayList<Path>(0);
for (String node : nodeList) {
if(node.indexOf('\\') >= 0 || node.indexOf('/') >= 0) {
/*
* This is not a case name lock (name specifies a path).
*/
String nodeUpperCase = node.toUpperCase();
if(!nodeUpperCase.endsWith("_RESOURCES") && !nodeUpperCase.endsWith("AUTO_INGEST_LOG.TXT")) {
/*
* This is not a case resource lock, nor a case auto
* ingest log lock. Collect the path.
*/
casePathList.add(Paths.get(node));
}
}
}
return casePathList;
} catch (CoordinationServiceException ex) {
throw new AutoIngestCaseManager.AutoIngestCaseManagerException("Failed to get node list from coordination service.", ex);
}
}
/** /**
* Opens an auto ingest case case. * Opens an auto ingest case case.
@ -104,4 +128,35 @@ final class AutoIngestCaseManager {
*/ */
Case.openAsCurrentCase(caseMetadataFilePath.toString()); Case.openAsCurrentCase(caseMetadataFilePath.toString());
} }
/**
* Exception type thrown when there is an error completing an auto ingest
* case manager operation.
*/
static final class AutoIngestCaseManagerException extends Exception {
private static final long serialVersionUID = 1L;
/**
* Constructs an instance of the exception type thrown when there is an
* error completing an auto ingest case manager operation.
*
* @param message The exception message.
*/
private AutoIngestCaseManagerException(String message) {
super(message);
}
/**
* Constructs an instance of the exception type thrown when there is an
* error completing an auto ingest case manager operation.
*
* @param message The exception message.
* @param cause A Throwable cause for the error.
*/
private AutoIngestCaseManagerException(String message, Throwable cause) {
super(message, cause);
}
}
} }

View File

@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.experimental.autoingest;
import java.awt.Cursor; import java.awt.Cursor;
import java.awt.Desktop; import java.awt.Desktop;
import java.awt.EventQueue; import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.WindowAdapter; import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent; import java.awt.event.WindowEvent;
import java.io.IOException; import java.io.IOException;
@ -39,16 +40,24 @@ import javax.swing.SwingWorker;
import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionEvent;
import javax.swing.table.DefaultTableModel; import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn; import javax.swing.table.TableColumn;
import org.openide.util.NbBundle;
import org.openide.util.lookup.ServiceProvider;
import org.openide.windows.WindowManager;
import org.sleuthkit.autopsy.casemodule.CaseActionCancelledException; import org.sleuthkit.autopsy.casemodule.CaseActionCancelledException;
import org.sleuthkit.autopsy.casemodule.CaseMetadata; import org.sleuthkit.autopsy.casemodule.CaseMetadata;
import org.sleuthkit.autopsy.casemodule.StartupWindowProvider; import org.sleuthkit.autopsy.casemodule.StartupWindowProvider;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import org.sleuthkit.autopsy.casemodule.AutoIngestCasePanelInterface;
import org.sleuthkit.autopsy.casemodule.CueBannerPanel;
import org.sleuthkit.autopsy.coreutils.NetworkUtils;
import org.sleuthkit.autopsy.experimental.configuration.StartupWindow;
/** /**
* A panel that allows a user to open cases created by auto ingest. * A panel that allows a user to open cases created by auto ingest.
*/ */
public final class AutoIngestCasePanel extends JPanel { @ServiceProvider(service = AutoIngestCasePanelInterface.class)
public final class AutoIngestCasePanel extends JPanel implements AutoIngestCasePanelInterface {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private static final Logger logger = Logger.getLogger(AutoIngestCasePanel.class.getName()); private static final Logger logger = Logger.getLogger(AutoIngestCasePanel.class.getName());
@ -90,6 +99,34 @@ public final class AutoIngestCasePanel extends JPanel {
private final String[] columnNames = {CASE_HEADER, CREATEDTIME_HEADER, COMPLETEDTIME_HEADER, STATUS_ICON_HEADER, OUTPUT_FOLDER_HEADER}; private final String[] columnNames = {CASE_HEADER, CREATEDTIME_HEADER, COMPLETEDTIME_HEADER, STATUS_ICON_HEADER, OUTPUT_FOLDER_HEADER};
private DefaultTableModel caseTableModel; private DefaultTableModel caseTableModel;
private Path currentlySelectedCase = null; private Path currentlySelectedCase = null;
public AutoIngestCasePanel() {
init(null);
}
@Override
public void addWindowStateListener(JDialog parent) {
/*
* Add a window state listener that starts and stops refreshing of the
* cases table.
*/
parent.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
stopCasesTableRefreshes();
}
@Override
public void windowActivated(WindowEvent e) {
startCasesTableRefreshes();
}
@Override
public void windowClosed(WindowEvent e) {
stopCasesTableRefreshes();
}
});
}
/** /**
* Constructs a panel that allows a user to open cases created by automated * Constructs a panel that allows a user to open cases created by automated
@ -98,6 +135,10 @@ public final class AutoIngestCasePanel extends JPanel {
* @param parent The parent dialog for this panel. * @param parent The parent dialog for this panel.
*/ */
public AutoIngestCasePanel(JDialog parent) { public AutoIngestCasePanel(JDialog parent) {
init(parent);
}
public void init(JDialog parent) {
caseTableModel = new DefaultTableModel(columnNames, 0) { caseTableModel = new DefaultTableModel(columnNames, 0) {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@ -226,7 +267,8 @@ public final class AutoIngestCasePanel extends JPanel {
private void refreshCasesTable() { private void refreshCasesTable() {
try { try {
currentlySelectedCase = getSelectedCase(); currentlySelectedCase = getSelectedCase();
List<AutoIngestCase> theModel = AutoIngestCaseManager.getInstance().getCases(); AutoIngestCaseManager manager = AutoIngestCaseManager.getInstance();
List<AutoIngestCase> theModel = manager.getCases();
EventQueue.invokeLater(new CaseTableRefreshTask(theModel)); EventQueue.invokeLater(new CaseTableRefreshTask(theModel));
} catch (Exception ex) { } catch (Exception ex) {
logger.log(Level.SEVERE, "Unexpected exception in refreshCasesTable", ex); //NON-NLS logger.log(Level.SEVERE, "Unexpected exception in refreshCasesTable", ex); //NON-NLS
@ -297,6 +339,7 @@ public final class AutoIngestCasePanel extends JPanel {
AutoIngestCaseManager.getInstance().openCase(caseMetadataFilePath); AutoIngestCaseManager.getInstance().openCase(caseMetadataFilePath);
stopCasesTableRefreshes(); stopCasesTableRefreshes();
StartupWindowProvider.getInstance().close(); StartupWindowProvider.getInstance().close();
CueBannerPanel.closeAutoIngestCasesWindow();
return null; return null;
} }

View File

@ -89,30 +89,34 @@ public final class AutoIngestJob implements Comparable<AutoIngestJob>, Serializa
* *
* @param manifest The manifest for an automated ingest job. * @param manifest The manifest for an automated ingest job.
*/ */
AutoIngestJob(Manifest manifest) { AutoIngestJob(Manifest manifest) throws AutoIngestJobException {
/* try {
* Version 0 fields. /*
*/ * Version 0 fields.
this.manifest = manifest; */
this.nodeName = ""; this.manifest = manifest;
this.caseDirectoryPath = ""; this.nodeName = "";
this.priority = DEFAULT_PRIORITY; this.caseDirectoryPath = "";
this.stage = Stage.PENDING; this.priority = DEFAULT_PRIORITY;
this.stageStartDate = manifest.getDateFileCreated(); this.stage = Stage.PENDING;
this.dataSourceProcessor = null; this.stageStartDate = manifest.getDateFileCreated();
this.ingestJob = null; this.dataSourceProcessor = null;
this.cancelled = false; this.ingestJob = null;
this.completed = false; this.cancelled = false;
this.completedDate = new Date(0); this.completed = false;
this.errorsOccurred = false; this.completedDate = new Date(0);
this.errorsOccurred = false;
/* /*
* Version 1 fields. * Version 1 fields.
*/ */
this.version = CURRENT_VERSION; this.version = CURRENT_VERSION;
this.processingStatus = ProcessingStatus.PENDING; this.processingStatus = ProcessingStatus.PENDING;
this.numberOfCrashes = 0; this.numberOfCrashes = 0;
this.stageDetails = this.getProcessingStageDetails(); this.stageDetails = this.getProcessingStageDetails();
} catch (Exception ex) {
throw new AutoIngestJobException(String.format("Error creating automated ingest job"), ex);
}
} }
/** /**
@ -122,30 +126,34 @@ public final class AutoIngestJob implements Comparable<AutoIngestJob>, Serializa
* @param nodeData The coordination service node data for an automated * @param nodeData The coordination service node data for an automated
* ingest job. * ingest job.
*/ */
AutoIngestJob(AutoIngestJobNodeData nodeData) { AutoIngestJob(AutoIngestJobNodeData nodeData) throws AutoIngestJobException {
/* try {
* Version 0 fields. /*
*/ * Version 0 fields.
this.manifest = new Manifest(nodeData.getManifestFilePath(), nodeData.getManifestFileDate(), nodeData.getCaseName(), nodeData.getDeviceId(), nodeData.getDataSourcePath(), Collections.emptyMap()); */
this.nodeName = nodeData.getProcessingHostName(); this.manifest = new Manifest(nodeData.getManifestFilePath(), nodeData.getManifestFileDate(), nodeData.getCaseName(), nodeData.getDeviceId(), nodeData.getDataSourcePath(), Collections.emptyMap());
this.caseDirectoryPath = nodeData.getCaseDirectoryPath().toString(); this.nodeName = nodeData.getProcessingHostName();
this.priority = nodeData.getPriority(); this.caseDirectoryPath = nodeData.getCaseDirectoryPath().toString();
this.stage = nodeData.getProcessingStage(); this.priority = nodeData.getPriority();
this.stageStartDate = nodeData.getProcessingStageStartDate(); this.stage = nodeData.getProcessingStage();
this.dataSourceProcessor = null; // Transient data not in node data. this.stageStartDate = nodeData.getProcessingStageStartDate();
this.ingestJob = null; // Transient data not in node data. this.dataSourceProcessor = null; // Transient data not in node data.
this.cancelled = false; // Transient data not in node data. this.ingestJob = null; // Transient data not in node data.
this.completed = false; // Transient data not in node data. this.cancelled = false; // Transient data not in node data.
this.completedDate = nodeData.getCompletedDate(); this.completed = false; // Transient data not in node data.
this.errorsOccurred = nodeData.getErrorsOccurred(); this.completedDate = nodeData.getCompletedDate();
this.errorsOccurred = nodeData.getErrorsOccurred();
/* /*
* Version 1 fields. * Version 1 fields.
*/ */
this.version = CURRENT_VERSION; this.version = CURRENT_VERSION;
this.processingStatus = nodeData.getProcessingStatus(); this.processingStatus = nodeData.getProcessingStatus();
this.numberOfCrashes = nodeData.getNumberOfCrashes(); this.numberOfCrashes = nodeData.getNumberOfCrashes();
this.stageDetails = this.getProcessingStageDetails(); this.stageDetails = this.getProcessingStageDetails();
} catch (Exception ex) {
throw new AutoIngestJobException(String.format("Error creating automated ingest job"), ex);
}
} }
/** /**
@ -622,5 +630,33 @@ public final class AutoIngestJob implements Comparable<AutoIngestJob>, Serializa
} }
} }
/**
* Exception thrown when there is a problem creating auto ingest job.
*/
final static class AutoIngestJobException extends Exception {
private static final long serialVersionUID = 1L;
/**
* Constructs an exception to throw when there is a problem creating
* auto ingest job.
*
* @param message The exception message.
*/
private AutoIngestJobException(String message) {
super(message);
}
/**
* Constructs an exception to throw when there is a problem creating
* auto ingest job.
*
* @param message The exception message.
* @param cause The cause of the exception, if it was an exception.
*/
private AutoIngestJobException(String message, Throwable cause) {
super(message, cause);
}
}
} }

View File

@ -37,7 +37,6 @@ import java.time.Duration;
import java.time.Instant; import java.time.Instant;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.EnumSet; import java.util.EnumSet;
@ -59,8 +58,6 @@ import java.util.concurrent.TimeUnit;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.annotation.concurrent.GuardedBy; import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.Immutable;
import javax.annotation.concurrent.ThreadSafe;
import org.openide.util.Lookup; import org.openide.util.Lookup;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.Case.CaseType; import org.sleuthkit.autopsy.casemodule.Case.CaseType;
@ -93,13 +90,13 @@ import org.sleuthkit.autopsy.experimental.configuration.SharedConfiguration;
import org.sleuthkit.autopsy.experimental.configuration.SharedConfiguration.SharedConfigurationException; import org.sleuthkit.autopsy.experimental.configuration.SharedConfiguration.SharedConfigurationException;
import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor; import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor;
import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException; import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException;
import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestJob.AutoIngestJobException;
import org.sleuthkit.autopsy.ingest.IngestJob; import org.sleuthkit.autopsy.ingest.IngestJob;
import org.sleuthkit.autopsy.ingest.IngestJob.CancellationReason; import org.sleuthkit.autopsy.ingest.IngestJob.CancellationReason;
import org.sleuthkit.autopsy.ingest.IngestJobSettings; import org.sleuthkit.autopsy.ingest.IngestJobSettings;
import org.sleuthkit.autopsy.ingest.IngestJobStartResult; import org.sleuthkit.autopsy.ingest.IngestJobStartResult;
import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.ingest.IngestModuleError; import org.sleuthkit.autopsy.ingest.IngestModuleError;
import org.sleuthkit.datamodel.Content;
/** /**
* An auto ingest manager is responsible for processing auto ingest jobs defined * An auto ingest manager is responsible for processing auto ingest jobs defined
@ -759,7 +756,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang
AutoIngestJob deletedJob = new AutoIngestJob(nodeData); AutoIngestJob deletedJob = new AutoIngestJob(nodeData);
deletedJob.setProcessingStatus(AutoIngestJob.ProcessingStatus.DELETED); deletedJob.setProcessingStatus(AutoIngestJob.ProcessingStatus.DELETED);
this.updateCoordinationServiceNode(deletedJob); this.updateCoordinationServiceNode(deletedJob);
} catch (AutoIngestJobNodeData.InvalidDataException ex) { } catch (AutoIngestJobNodeData.InvalidDataException | AutoIngestJobException ex) {
SYS_LOGGER.log(Level.WARNING, String.format("Invalid auto ingest job node data for %s", manifestPath), ex); SYS_LOGGER.log(Level.WARNING, String.format("Invalid auto ingest job node data for %s", manifestPath), ex);
return CaseDeletionResult.PARTIALLY_DELETED; return CaseDeletionResult.PARTIALLY_DELETED;
} catch (InterruptedException | CoordinationServiceException ex) { } catch (InterruptedException | CoordinationServiceException ex) {
@ -1015,92 +1012,103 @@ public final class AutoIngestManager extends Observable implements PropertyChang
* @return TERMINATE if auto ingest is shutting down, CONTINUE if it has * @return TERMINATE if auto ingest is shutting down, CONTINUE if it has
* not. * not.
* *
* @throws IOException if an I/O error occurs, but this implementation
* does not throw.
*/ */
@Override @Override
public FileVisitResult visitFile(Path filePath, BasicFileAttributes attrs) throws IOException { public FileVisitResult visitFile(Path filePath, BasicFileAttributes attrs) {
if (Thread.currentThread().isInterrupted()) { if (Thread.currentThread().isInterrupted()) {
return TERMINATE; return TERMINATE;
} }
Manifest manifest = null; try {
for (ManifestFileParser parser : Lookup.getDefault().lookupAll(ManifestFileParser.class)) { Manifest manifest = null;
if (parser.fileIsManifest(filePath)) { for (ManifestFileParser parser : Lookup.getDefault().lookupAll(ManifestFileParser.class)) {
try { if (parser.fileIsManifest(filePath)) {
manifest = parser.parse(filePath); try {
break; manifest = parser.parse(filePath);
} catch (ManifestFileParserException ex) { break;
SYS_LOGGER.log(Level.SEVERE, String.format("Error attempting to parse %s with parser %s", filePath, parser.getClass().getCanonicalName()), ex); } catch (ManifestFileParserException ex) {
SYS_LOGGER.log(Level.SEVERE, String.format("Error attempting to parse %s with parser %s", filePath, parser.getClass().getCanonicalName()), ex);
}
}
if (Thread.currentThread().isInterrupted()) {
return TERMINATE;
} }
} }
if (Thread.currentThread().isInterrupted()) { if (Thread.currentThread().isInterrupted()) {
return TERMINATE; return TERMINATE;
} }
}
if (Thread.currentThread().isInterrupted()) { if (null != manifest) {
return TERMINATE; /*
}
if (null != manifest) {
/*
* Update the mapping of case names to manifest paths that is * Update the mapping of case names to manifest paths that is
* used for case deletion. * used for case deletion.
*/ */
String caseName = manifest.getCaseName(); String caseName = manifest.getCaseName();
Path manifestPath = manifest.getFilePath(); Path manifestPath = manifest.getFilePath();
if (casesToManifests.containsKey(caseName)) { if (casesToManifests.containsKey(caseName)) {
Set<Path> manifestPaths = casesToManifests.get(caseName); Set<Path> manifestPaths = casesToManifests.get(caseName);
manifestPaths.add(manifestPath); manifestPaths.add(manifestPath);
} else { } else {
Set<Path> manifestPaths = new HashSet<>(); Set<Path> manifestPaths = new HashSet<>();
manifestPaths.add(manifestPath); manifestPaths.add(manifestPath);
casesToManifests.put(caseName, manifestPaths); casesToManifests.put(caseName, manifestPaths);
} }
/* /*
* Add a job to the pending jobs queue, the completed jobs list, * Add a job to the pending jobs queue, the completed jobs list,
* or do crashed job recovery, as required. * or do crashed job recovery, as required.
*/ */
try { try {
byte[] rawData = coordinationService.getNodeData(CoordinationService.CategoryNode.MANIFESTS, manifestPath.toString()); byte[] rawData = coordinationService.getNodeData(CoordinationService.CategoryNode.MANIFESTS, manifestPath.toString());
if (null != rawData && rawData.length > 0) { if (null != rawData && rawData.length > 0) {
try { try {
AutoIngestJobNodeData nodeData = new AutoIngestJobNodeData(rawData); AutoIngestJobNodeData nodeData = new AutoIngestJobNodeData(rawData);
AutoIngestJob.ProcessingStatus processingStatus = nodeData.getProcessingStatus(); AutoIngestJob.ProcessingStatus processingStatus = nodeData.getProcessingStatus();
switch (processingStatus) { switch (processingStatus) {
case PENDING: case PENDING:
addPendingJob(manifest, nodeData); addPendingJob(manifest, nodeData);
break; break;
case PROCESSING: case PROCESSING:
doRecoveryIfCrashed(manifest, nodeData); doRecoveryIfCrashed(manifest, nodeData);
break; break;
case COMPLETED: case COMPLETED:
addCompletedJob(manifest, nodeData); addCompletedJob(manifest, nodeData);
break; break;
case DELETED: case DELETED:
/* /*
* Ignore jobs marked as "deleted." * Ignore jobs marked as "deleted."
*/ */
break; break;
default: default:
SYS_LOGGER.log(Level.SEVERE, "Unknown ManifestNodeData.ProcessingStatus"); SYS_LOGGER.log(Level.SEVERE, "Unknown ManifestNodeData.ProcessingStatus");
break; break;
}
} catch (AutoIngestJobNodeData.InvalidDataException | AutoIngestJobException ex) {
SYS_LOGGER.log(Level.SEVERE, String.format("Invalid auto ingest job node data for %s", manifestPath), ex);
}
} else {
try {
addNewPendingJob(manifest);
} catch (AutoIngestJobException ex) {
SYS_LOGGER.log(Level.SEVERE, String.format("Invalid manifest data for %s", manifestPath), ex);
} }
} catch (AutoIngestJobNodeData.InvalidDataException ex) {
SYS_LOGGER.log(Level.WARNING, String.format("Invalid auto ingest job node data for %s", manifestPath), ex);
} }
} else { } catch (CoordinationServiceException ex) {
addNewPendingJob(manifest); SYS_LOGGER.log(Level.SEVERE, String.format("Error transmitting node data for %s", manifestPath), ex);
return CONTINUE;
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
return TERMINATE;
} }
} catch (CoordinationServiceException ex) {
SYS_LOGGER.log(Level.SEVERE, String.format("Error transmitting node data for %s", manifestPath), ex);
return CONTINUE;
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
return TERMINATE;
} }
} catch (Exception ex) {
// Catch all unhandled and unexpected exceptions. Otherwise one bad file
// can stop the entire input folder scanning. Given that the exception is unexpected,
// I'm hesitant to add logging which requires accessing or de-referencing data.
SYS_LOGGER.log(Level.SEVERE, "Unexpected exception in file visitor", ex);
return CONTINUE;
} }
if (!Thread.currentThread().isInterrupted()) { if (!Thread.currentThread().isInterrupted()) {
@ -1122,7 +1130,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang
* blocked, i.e., if auto ingest is * blocked, i.e., if auto ingest is
* shutting down. * shutting down.
*/ */
private void addPendingJob(Manifest manifest, AutoIngestJobNodeData nodeData) throws InterruptedException { private void addPendingJob(Manifest manifest, AutoIngestJobNodeData nodeData) throws InterruptedException, AutoIngestJobException {
AutoIngestJob job; AutoIngestJob job;
if (nodeData.getVersion() == AutoIngestJobNodeData.getCurrentVersion()) { if (nodeData.getVersion() == AutoIngestJobNodeData.getCurrentVersion()) {
job = new AutoIngestJob(nodeData); job = new AutoIngestJob(nodeData);
@ -1176,7 +1184,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang
* blocked, i.e., if auto ingest is * blocked, i.e., if auto ingest is
* shutting down. * shutting down.
*/ */
private void addNewPendingJob(Manifest manifest) throws InterruptedException { private void addNewPendingJob(Manifest manifest) throws InterruptedException, AutoIngestJobException {
/* /*
* Create the coordination service node data for the job. Note that * Create the coordination service node data for the job. Note that
* getting the lock will create the node for the job (with no data) * getting the lock will create the node for the job (with no data)
@ -1218,7 +1226,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang
* blocked, i.e., if auto ingest is * blocked, i.e., if auto ingest is
* shutting down. * shutting down.
*/ */
private void doRecoveryIfCrashed(Manifest manifest, AutoIngestJobNodeData nodeData) throws InterruptedException { private void doRecoveryIfCrashed(Manifest manifest, AutoIngestJobNodeData nodeData) throws InterruptedException, AutoIngestJobException {
/* /*
* Try to get an exclusive lock on the coordination service node for * Try to get an exclusive lock on the coordination service node for
* the job. If the lock cannot be obtained, another host in the auto * the job. If the lock cannot be obtained, another host in the auto
@ -1314,7 +1322,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang
* @throws CoordinationServiceException * @throws CoordinationServiceException
* @throws InterruptedException * @throws InterruptedException
*/ */
private void addCompletedJob(Manifest manifest, AutoIngestJobNodeData nodeData) throws CoordinationServiceException, InterruptedException { private void addCompletedJob(Manifest manifest, AutoIngestJobNodeData nodeData) throws CoordinationServiceException, InterruptedException, AutoIngestJobException {
Path caseDirectoryPath = PathUtils.findCaseDirectory(rootOutputDirectory, manifest.getCaseName()); Path caseDirectoryPath = PathUtils.findCaseDirectory(rootOutputDirectory, manifest.getCaseName());
if (null != caseDirectoryPath) { if (null != caseDirectoryPath) {
AutoIngestJob job; AutoIngestJob job;
@ -1441,7 +1449,6 @@ public final class AutoIngestManager extends Observable implements PropertyChang
*/ */
private final class JobProcessingTask implements Runnable { private final class JobProcessingTask implements Runnable {
private static final String AUTO_INGEST_MODULE_OUTPUT_DIR = "AutoIngest";
private final Object ingestLock; private final Object ingestLock;
private final Object pauseLock; private final Object pauseLock;
@GuardedBy("pauseLock") @GuardedBy("pauseLock")
@ -2204,7 +2211,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang
return; return;
} }
DataSource dataSource = identifyDataSource(caseForJob); DataSource dataSource = identifyDataSource();
if (null == dataSource) { if (null == dataSource) {
currentJob.setProcessingStage(AutoIngestJob.Stage.COMPLETED, Date.from(Instant.now())); currentJob.setProcessingStage(AutoIngestJob.Stage.COMPLETED, Date.from(Instant.now()));
return; return;
@ -2257,7 +2264,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang
* interrupted while blocked, i.e., * interrupted while blocked, i.e.,
* if auto ingest is shutting down. * if auto ingest is shutting down.
*/ */
private DataSource identifyDataSource(Case caseForJob) throws AutoIngestAlertFileException, AutoIngestJobLoggerException, InterruptedException { private DataSource identifyDataSource() throws AutoIngestAlertFileException, AutoIngestJobLoggerException, InterruptedException {
Manifest manifest = currentJob.getManifest(); Manifest manifest = currentJob.getManifest();
Path manifestPath = manifest.getFilePath(); Path manifestPath = manifest.getFilePath();
SYS_LOGGER.log(Level.INFO, "Identifying data source for {0} ", manifestPath); SYS_LOGGER.log(Level.INFO, "Identifying data source for {0} ", manifestPath);
@ -2276,7 +2283,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang
String deviceId = manifest.getDeviceId(); String deviceId = manifest.getDeviceId();
return new DataSource(deviceId, dataSourcePath); return new DataSource(deviceId, dataSourcePath);
} }
/** /**
* Passes the data source for the current job through a data source * Passes the data source for the current job through a data source
* processor that adds it to the case database. * processor that adds it to the case database.
@ -2299,28 +2306,21 @@ public final class AutoIngestManager extends Observable implements PropertyChang
SYS_LOGGER.log(Level.INFO, "Adding data source for {0} ", manifestPath); SYS_LOGGER.log(Level.INFO, "Adding data source for {0} ", manifestPath);
currentJob.setProcessingStage(AutoIngestJob.Stage.ADDING_DATA_SOURCE, Date.from(Instant.now())); currentJob.setProcessingStage(AutoIngestJob.Stage.ADDING_DATA_SOURCE, Date.from(Instant.now()));
UUID taskId = UUID.randomUUID(); UUID taskId = UUID.randomUUID();
DataSourceProcessorCallback callBack = new AddDataSourceCallback(caseForJob, dataSource, taskId); DataSourceProcessorCallback callBack = new AddDataSourceCallback(caseForJob, dataSource, taskId, ingestLock);
DataSourceProcessorProgressMonitor progressMonitor = new DoNothingDSPProgressMonitor(); DataSourceProcessorProgressMonitor progressMonitor = new DoNothingDSPProgressMonitor();
Path caseDirectoryPath = currentJob.getCaseDirectoryPath(); Path caseDirectoryPath = currentJob.getCaseDirectoryPath();
AutoIngestJobLogger jobLogger = new AutoIngestJobLogger(manifestPath, manifest.getDataSourceFileName(), caseDirectoryPath); AutoIngestJobLogger jobLogger = new AutoIngestJobLogger(manifestPath, manifest.getDataSourceFileName(), caseDirectoryPath);
try { try {
caseForJob.notifyAddingDataSource(taskId); caseForJob.notifyAddingDataSource(taskId);
// lookup all AutomatedIngestDataSourceProcessors Map<AutoIngestDataSourceProcessor, Integer> validDataSourceProcessorsMap;
Collection<? extends AutoIngestDataSourceProcessor> processorCandidates = Lookup.getDefault().lookupAll(AutoIngestDataSourceProcessor.class); try {
// lookup all AutomatedIngestDataSourceProcessors and poll which ones are able to process the current data source
Map<AutoIngestDataSourceProcessor, Integer> validDataSourceProcessorsMap = new HashMap<>(); validDataSourceProcessorsMap = DataSourceProcessorUtility.getDataSourceProcessor(dataSource.getPath());
for (AutoIngestDataSourceProcessor processor : processorCandidates) { } catch (AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException ex) {
try { SYS_LOGGER.log(Level.SEVERE, "Exception while determining best data source processor for {0}", dataSource.getPath());
int confidence = processor.canProcess(dataSource.getPath()); // rethrow the exception. It will get caught & handled upstream and will result in AIM auto-pause.
if (confidence > 0) { throw ex;
validDataSourceProcessorsMap.put(processor, confidence);
}
} catch (AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException ex) {
SYS_LOGGER.log(Level.SEVERE, "Exception while determining whether data source processor {0} can process {1}", new Object[]{processor.getDataSourceType(), dataSource.getPath()});
// rethrow the exception. It will get caught & handled upstream and will result in AIM auto-pause.
throw ex;
}
} }
// did we find a data source processor that can process the data source // did we find a data source processor that can process the data source
@ -2577,80 +2577,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang
jobLogger.logFileExportError(); jobLogger.logFileExportError();
} }
} }
/**
* A "callback" that collects the results of running a data source
* processor on a data source and unblocks the job processing thread
* when the data source processor finishes running in its own thread.
*/
@Immutable
class AddDataSourceCallback extends DataSourceProcessorCallback {
private final Case caseForJob;
private final DataSource dataSourceInfo;
private final UUID taskId;
/**
* Constructs a "callback" that collects the results of running a
* data source processor on a data source and unblocks the job
* processing thread when the data source processor finishes running
* in its own thread.
*
* @param caseForJob The case for the current job.
* @param dataSourceInfo The data source
* @param taskId The task id to associate with ingest job
* events.
*/
AddDataSourceCallback(Case caseForJob, DataSource dataSourceInfo, UUID taskId) {
this.caseForJob = caseForJob;
this.dataSourceInfo = dataSourceInfo;
this.taskId = taskId;
}
/**
* Called by the data source processor when it finishes running in
* its own thread.
*
* @param result The result code for the processing of
* the data source.
* @param errorMessages Any error messages generated during the
* processing of the data source.
* @param dataSourceContent The content produced by processing the
* data source.
*/
@Override
public void done(DataSourceProcessorCallback.DataSourceProcessorResult result, List<String> errorMessages, List<Content> dataSourceContent) {
if (!dataSourceContent.isEmpty()) {
caseForJob.notifyDataSourceAdded(dataSourceContent.get(0), taskId);
} else {
caseForJob.notifyFailedAddingDataSource(taskId);
}
dataSourceInfo.setDataSourceProcessorOutput(result, errorMessages, dataSourceContent);
dataSourceContent.addAll(dataSourceContent);
synchronized (ingestLock) {
ingestLock.notify();
}
}
/**
* Called by the data source processor when it finishes running in
* its own thread, if that thread is the AWT (Abstract Window
* Toolkit) event dispatch thread (EDT).
*
* @param result The result code for the processing of
* the data source.
* @param errorMessages Any error messages generated during the
* processing of the data source.
* @param dataSourceContent The content produced by processing the
* data source.
*/
@Override
public void doneEDT(DataSourceProcessorCallback.DataSourceProcessorResult result, List<String> errorMessages, List<Content> dataSources) {
done(result, errorMessages, dataSources);
}
}
/** /**
* A data source processor progress monitor does nothing. There is * A data source processor progress monitor does nothing. There is
* currently no mechanism for showing or recording data source processor * currently no mechanism for showing or recording data source processor
@ -2990,49 +2917,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang
PARTIALLY_DELETED, PARTIALLY_DELETED,
FULLY_DELETED FULLY_DELETED
} }
@ThreadSafe
private static final class DataSource {
private final String deviceId;
private final Path path;
private DataSourceProcessorResult resultCode;
private List<String> errorMessages;
private List<Content> content;
DataSource(String deviceId, Path path) {
this.deviceId = deviceId;
this.path = path;
}
String getDeviceId() {
return deviceId;
}
Path getPath() {
return this.path;
}
synchronized void setDataSourceProcessorOutput(DataSourceProcessorResult result, List<String> errorMessages, List<Content> content) {
this.resultCode = result;
this.errorMessages = new ArrayList<>(errorMessages);
this.content = new ArrayList<>(content);
}
synchronized DataSourceProcessorResult getResultDataSourceProcessorResultCode() {
return resultCode;
}
synchronized List<String> getDataSourceProcessorErrorMessages() {
return new ArrayList<>(errorMessages);
}
synchronized List<Content> getContent() {
return new ArrayList<>(content);
}
}
static final class AutoIngestManagerException extends Exception { static final class AutoIngestManagerException extends Exception {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;

View File

@ -265,7 +265,7 @@ public final class AutoIngestMonitor extends Observable implements PropertyChang
} }
} catch (InterruptedException ex) { } catch (InterruptedException ex) {
LOGGER.log(Level.SEVERE, String.format("Unexpected interrupt while retrieving coordination service node data for '%s'", node), ex); LOGGER.log(Level.SEVERE, String.format("Unexpected interrupt while retrieving coordination service node data for '%s'", node), ex);
} catch (AutoIngestJobNodeData.InvalidDataException ex) { } catch (AutoIngestJobNodeData.InvalidDataException | AutoIngestJob.AutoIngestJobException ex) {
LOGGER.log(Level.SEVERE, String.format("Unable to use node data for '%s'", node), ex); LOGGER.log(Level.SEVERE, String.format("Unable to use node data for '%s'", node), ex);
} }
} }

View File

@ -247,3 +247,7 @@ AutoIngestDashboard.prioritizeJobButton.toolTipText=Move the selected job to the
AutoIngestDashboard.prioritizeJobButton.text=Prioritize &Job AutoIngestDashboard.prioritizeJobButton.text=Prioritize &Job
AutoIngestDashboard.prioritizeCaseButton.toolTipText=Move all images associated with a case to top of Pending queue. AutoIngestDashboard.prioritizeCaseButton.toolTipText=Move all images associated with a case to top of Pending queue.
AutoIngestDashboard.prioritizeCaseButton.text=Prioritize &Case AutoIngestDashboard.prioritizeCaseButton.text=Prioritize &Case
ArchiveFilePanel.pathLabel.text=Browse for an archive file:
ArchiveFilePanel.browseButton.text=Browse
ArchiveFilePanel.pathTextField.text=
ArchiveFilePanel.errorLabel.text=Error Label

View File

@ -0,0 +1,68 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2017 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.experimental.autoingest;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.concurrent.ThreadSafe;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback.DataSourceProcessorResult;
import org.sleuthkit.datamodel.Content;
@ThreadSafe
class DataSource {
private final String deviceId;
private final Path path;
private DataSourceProcessorResult resultCode;
private List<String> errorMessages;
private List<Content> content;
DataSource(String deviceId, Path path) {
this.deviceId = deviceId;
this.path = path;
}
String getDeviceId() {
return deviceId;
}
Path getPath() {
return this.path;
}
synchronized void setDataSourceProcessorOutput(DataSourceProcessorResult result, List<String> errorMessages, List<Content> content) {
this.resultCode = result;
this.errorMessages = new ArrayList<>(errorMessages);
this.content = new ArrayList<>(content);
}
synchronized DataSourceProcessorResult getResultDataSourceProcessorResultCode() {
return resultCode;
}
synchronized List<String> getDataSourceProcessorErrorMessages() {
return new ArrayList<>(errorMessages);
}
synchronized List<Content> getContent() {
return new ArrayList<>(content);
}
}

View File

@ -0,0 +1,63 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2017 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.experimental.autoingest;
import java.nio.file.Path;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import org.openide.util.Lookup;
import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor;
import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException;
/**
* A utility class to find Data Source Processors
*/
class DataSourceProcessorUtility {
private DataSourceProcessorUtility() {
}
/**
* A utility method to find all Data Source Processors (DSP) that are able
* to process the input data source. Only the DSPs that implement
* AutoIngestDataSourceProcessor interface are used.
*
* @param dataSourcePath Full path to the data source
* @return Hash map of all DSPs that can process the data source along with
* their confidence score
* @throws
* org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException
*/
static Map<AutoIngestDataSourceProcessor, Integer> getDataSourceProcessor(Path dataSourcePath) throws AutoIngestDataSourceProcessorException {
// lookup all AutomatedIngestDataSourceProcessors
Collection<? extends AutoIngestDataSourceProcessor> processorCandidates = Lookup.getDefault().lookupAll(AutoIngestDataSourceProcessor.class);
Map<AutoIngestDataSourceProcessor, Integer> validDataSourceProcessorsMap = new HashMap<>();
for (AutoIngestDataSourceProcessor processor : processorCandidates) {
int confidence = processor.canProcess(dataSourcePath);
if (confidence > 0) {
validDataSourceProcessorsMap.put(processor, confidence);
}
}
return validDataSourceProcessorsMap;
}
}

View File

@ -126,11 +126,7 @@
</Group> </Group>
<Group type="102" attributes="0"> <Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0"> <Component id="jLabelSelectMode" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="jLabelSelectMode" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="restartRequiredNodeLabel" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="jRadioButtonReview" alignment="0" min="-2" max="-2" attributes="0"/> <Component id="jRadioButtonReview" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="jRadioButtonAutomated" alignment="0" min="-2" max="-2" attributes="0"/> <Component id="jRadioButtonAutomated" alignment="0" min="-2" max="-2" attributes="0"/>
</Group> </Group>
@ -159,10 +155,7 @@
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0"> <Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0"> <Component id="jLabelSelectMode" min="-2" max="-2" attributes="0"/>
<Component id="jLabelSelectMode" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="restartRequiredNodeLabel" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace type="unrelated" max="-2" attributes="0"/> <EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="jRadioButtonAutomated" min="-2" max="-2" attributes="0"/> <Component id="jRadioButtonAutomated" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
@ -203,16 +196,6 @@
</Property> </Property>
</Properties> </Properties>
</Component> </Component>
<Component class="javax.swing.JLabel" name="restartRequiredNodeLabel">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/experimental/images/warning16.png"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/experimental/configuration/Bundle.properties" key="AutoIngestSettingsPanel.restartRequiredNodeLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JRadioButton" name="jRadioButtonAutomated"> <Component class="javax.swing.JRadioButton" name="jRadioButtonAutomated">
<Properties> <Properties>
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor"> <Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">

View File

@ -210,35 +210,16 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel {
boolean needsRestart = false; boolean needsRestart = false;
UserPreferences.SelectedMode storedMode = UserPreferences.getMode(); UserPreferences.SelectedMode storedMode = UserPreferences.getMode();
if (AutoIngestUserPreferences.getJoinAutoModeCluster() != cbJoinAutoIngestCluster.isSelected()) {
needsRestart = true;
}
AutoIngestUserPreferences.setJoinAutoModeCluster(cbJoinAutoIngestCluster.isSelected()); AutoIngestUserPreferences.setJoinAutoModeCluster(cbJoinAutoIngestCluster.isSelected());
if (!cbJoinAutoIngestCluster.isSelected()) { if (!cbJoinAutoIngestCluster.isSelected()) {
if(storedMode == UserPreferences.SelectedMode.AUTOINGEST) {
needsRestart = true;
}
UserPreferences.setMode(UserPreferences.SelectedMode.STANDALONE); UserPreferences.setMode(UserPreferences.SelectedMode.STANDALONE);
//before return popup the message
if (needsRestart) {
SwingUtilities.invokeLater(() -> {
JOptionPane.showMessageDialog(null,
NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.MustRestart"),
NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.restartRequiredLabel.text"),
JOptionPane.WARNING_MESSAGE);
});
}
return;
} }
else if (jRadioButtonAutomated.isSelected()) {
if (jRadioButtonAutomated.isSelected()) { if (storedMode == UserPreferences.SelectedMode.REVIEW) {
if (storedMode != UserPreferences.SelectedMode.AUTOINGEST) {
needsRestart = true;
}
String thePath = AutoIngestUserPreferences.getAutoModeImageFolder();
if (thePath != null && 0 != inputPathTextField.getText().compareTo(thePath)) {
needsRestart = true;
}
thePath = AutoIngestUserPreferences.getAutoModeResultsFolder();
if (thePath != null && 0 != outputPathTextField.getText().compareTo(thePath)) {
needsRestart = true; needsRestart = true;
} }
@ -254,11 +235,7 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel {
AutoIngestUserPreferences.setSharedConfigMaster(masterNodeCheckBox.isSelected()); AutoIngestUserPreferences.setSharedConfigMaster(masterNodeCheckBox.isSelected());
} }
} else if (jRadioButtonReview.isSelected()) { } else if (jRadioButtonReview.isSelected()) {
if (storedMode != UserPreferences.SelectedMode.REVIEW) { if (storedMode == UserPreferences.SelectedMode.AUTOINGEST) {
needsRestart = true;
}
String thePath = AutoIngestUserPreferences.getAutoModeResultsFolder();
if (thePath != null && 0 != outputPathTextField.getText().compareTo(thePath)) {
needsRestart = true; needsRestart = true;
} }
@ -661,7 +638,6 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel {
nodePanel = new javax.swing.JPanel(); nodePanel = new javax.swing.JPanel();
jPanelNodeType = new javax.swing.JPanel(); jPanelNodeType = new javax.swing.JPanel();
jLabelSelectMode = new javax.swing.JLabel(); jLabelSelectMode = new javax.swing.JLabel();
restartRequiredNodeLabel = new javax.swing.JLabel();
jRadioButtonAutomated = new javax.swing.JRadioButton(); jRadioButtonAutomated = new javax.swing.JRadioButton();
jRadioButtonReview = new javax.swing.JRadioButton(); jRadioButtonReview = new javax.swing.JRadioButton();
jLabelSelectInputFolder = new javax.swing.JLabel(); jLabelSelectInputFolder = new javax.swing.JLabel();
@ -703,9 +679,6 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel {
org.openide.awt.Mnemonics.setLocalizedText(jLabelSelectMode, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jLabelSelectMode.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(jLabelSelectMode, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jLabelSelectMode.text")); // NOI18N
restartRequiredNodeLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/experimental/images/warning16.png"))); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(restartRequiredNodeLabel, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.restartRequiredNodeLabel.text")); // NOI18N
modeRadioButtons.add(jRadioButtonAutomated); modeRadioButtons.add(jRadioButtonAutomated);
jRadioButtonAutomated.setSelected(true); jRadioButtonAutomated.setSelected(true);
org.openide.awt.Mnemonics.setLocalizedText(jRadioButtonAutomated, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jRadioButtonAutomated.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(jRadioButtonAutomated, org.openide.util.NbBundle.getMessage(AutoIngestSettingsPanel.class, "AutoIngestSettingsPanel.jRadioButtonAutomated.text")); // NOI18N
@ -777,10 +750,7 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel {
.addComponent(browseOutputFolderButton, javax.swing.GroupLayout.Alignment.TRAILING))) .addComponent(browseOutputFolderButton, javax.swing.GroupLayout.Alignment.TRAILING)))
.addGroup(jPanelNodeTypeLayout.createSequentialGroup() .addGroup(jPanelNodeTypeLayout.createSequentialGroup()
.addGroup(jPanelNodeTypeLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanelNodeTypeLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanelNodeTypeLayout.createSequentialGroup() .addComponent(jLabelSelectMode)
.addComponent(jLabelSelectMode)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(restartRequiredNodeLabel))
.addComponent(jRadioButtonReview) .addComponent(jRadioButtonReview)
.addComponent(jRadioButtonAutomated)) .addComponent(jRadioButtonAutomated))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
@ -802,9 +772,7 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel {
.addGroup(jPanelNodeTypeLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanelNodeTypeLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanelNodeTypeLayout.createSequentialGroup() .addGroup(jPanelNodeTypeLayout.createSequentialGroup()
.addContainerGap() .addContainerGap()
.addGroup(jPanelNodeTypeLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(jLabelSelectMode)
.addComponent(jLabelSelectMode)
.addComponent(restartRequiredNodeLabel))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(jRadioButtonAutomated) .addComponent(jRadioButtonAutomated)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
@ -1407,7 +1375,6 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel {
jRadioButtonAutomated.setEnabled(enabled); jRadioButtonAutomated.setEnabled(enabled);
jRadioButtonReview.setEnabled(enabled); jRadioButtonReview.setEnabled(enabled);
outputPathTextField.setEnabled(enabled); outputPathTextField.setEnabled(enabled);
restartRequiredNodeLabel.setEnabled(enabled);
} }
// Variables declaration - do not modify//GEN-BEGIN:variables // Variables declaration - do not modify//GEN-BEGIN:variables
@ -1442,7 +1409,6 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel {
private javax.swing.JScrollPane nodeScrollPane; private javax.swing.JScrollPane nodeScrollPane;
private javax.swing.JTextField outputPathTextField; private javax.swing.JTextField outputPathTextField;
private javax.swing.JProgressBar pbTaskInProgress; private javax.swing.JProgressBar pbTaskInProgress;
private javax.swing.JLabel restartRequiredNodeLabel;
private javax.swing.JCheckBox sharedConfigCheckbox; private javax.swing.JCheckBox sharedConfigCheckbox;
private javax.swing.JTextField sharedSettingsErrorTextField; private javax.swing.JTextField sharedSettingsErrorTextField;
private javax.swing.JTextField sharedSettingsTextField; private javax.swing.JTextField sharedSettingsTextField;

View File

@ -59,7 +59,7 @@ public final class AutoIngestUserPreferences {
} }
/** /**
* Get "Join Automated Ingest Cluster" setting from persistent storage. * Get "Join auto ingest cluster" setting from persistent storage.
* *
* @return SelectedMode Selected setting. * @return SelectedMode Selected setting.
*/ */
@ -71,7 +71,7 @@ public final class AutoIngestUserPreferences {
} }
/** /**
* Set "Join Automated Ingest Cluster" setting to persistent storage. * Set "Join auto ingest cluster" setting to persistent storage.
* *
* @param join boolean value of whether to join auto ingest cluster or not * @param join boolean value of whether to join auto ingest cluster or not
*/ */

View File

@ -25,7 +25,7 @@ AutoIngestSettingsPanel.AdvancedAutoIngestSettingsPanel.Title=Advanced Settings
AutoIngestSettingsPanel.browseGlobalSettingsButton.text=Browse AutoIngestSettingsPanel.browseGlobalSettingsButton.text=Browse
AutoIngestSettingsPanel.browseSharedSettingsButton.text=Browse AutoIngestSettingsPanel.browseSharedSettingsButton.text=Browse
AutoIngestSettingsPanel.CannotAccess=Cannot access AutoIngestSettingsPanel.CannotAccess=Cannot access
AutoIngestSettingsPanel.cbJoinAutoIngestCluster.text=Join Automated Ingest Cluster AutoIngestSettingsPanel.cbJoinAutoIngestCluster.text=Join auto ingest cluster
AutoIngestSettingsPanel.CheckPermissions=Check permissions. AutoIngestSettingsPanel.CheckPermissions=Check permissions.
AutoIngestSettingsPanel.configButtonErrorTextField.text=configButtonErrorTextField AutoIngestSettingsPanel.configButtonErrorTextField.text=configButtonErrorTextField
AutoIngestSettingsPanel.downloadButton.text=Download Config AutoIngestSettingsPanel.downloadButton.text=Download Config
@ -89,7 +89,6 @@ OptionsDialog.jLabel1.text=jLabel1
StartupWindow.AutoIngestMode=Automated Ingest Node StartupWindow.AutoIngestMode=Automated Ingest Node
StartupWindow.CaseImportMode=Single User Case Import StartupWindow.CaseImportMode=Single User Case Import
StartupWindow.CopyAndImportMode=Utilities StartupWindow.CopyAndImportMode=Utilities
StartupWindow.ReviewMode=Cases
StartupWindow.title.text=Welcome StartupWindow.title.text=Welcome
AdvancedAutoIngestSettingsPanel.lbInputScanIntervalMinutes.text=minutes AdvancedAutoIngestSettingsPanel.lbInputScanIntervalMinutes.text=minutes
AdvancedAutoIngestSettingsPanel.lbTimeoutHours.text=hour(s) AdvancedAutoIngestSettingsPanel.lbTimeoutHours.text=hour(s)
@ -133,10 +132,9 @@ AutoIngestSettingsPanel.inputPathTextField.toolTipText=Input folder for automate
AutoIngestSettingsPanel.inputPathTextField.text= AutoIngestSettingsPanel.inputPathTextField.text=
AutoIngestSettingsPanel.jLabelSelectInputFolder.text=Select shared images folder: AutoIngestSettingsPanel.jLabelSelectInputFolder.text=Select shared images folder:
AutoIngestSettingsPanel.jRadioButtonReview.toolTipText=Review cases created in automated processing mode AutoIngestSettingsPanel.jRadioButtonReview.toolTipText=Review cases created in automated processing mode
AutoIngestSettingsPanel.jRadioButtonReview.text=Examiner Node AutoIngestSettingsPanel.jRadioButtonReview.text=Examiner node
AutoIngestSettingsPanel.jRadioButtonAutomated.toolTipText=Automatically detect new data sources and create cases. AutoIngestSettingsPanel.jRadioButtonAutomated.toolTipText=Automatically detect new data sources and create cases.
AutoIngestSettingsPanel.jRadioButtonAutomated.text=Auto Ingest Node AutoIngestSettingsPanel.jRadioButtonAutomated.text=Auto ingest node (application restart required)
AutoIngestSettingsPanel.restartRequiredNodeLabel.text=Application restart required
AutoIngestSettingsPanel.jLabelSelectMode.text=Select mode: AutoIngestSettingsPanel.jLabelSelectMode.text=Select mode:
AutoIngestSettingsPanel.jPanelIngestSettings.border.title=Automated Ingest Settings AutoIngestSettingsPanel.jPanelIngestSettings.border.title=Automated Ingest Settings
AutoIngestSettingsPanel.bnLogging.text=Node Status Logging AutoIngestSettingsPanel.bnLogging.text=Node Status Logging

View File

@ -18,7 +18,6 @@
*/ */
package org.sleuthkit.autopsy.experimental.configuration; package org.sleuthkit.autopsy.experimental.configuration;
import java.awt.Cursor;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Toolkit; import java.awt.Toolkit;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
@ -36,7 +35,6 @@ import org.sleuthkit.autopsy.casemodule.StartupWindowInterface;
import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.coreutils.NetworkUtils; import org.sleuthkit.autopsy.coreutils.NetworkUtils;
import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestControlPanel; import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestControlPanel;
import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestCasePanel;
/** /**
* The default implementation of the Autopsy startup window * The default implementation of the Autopsy startup window
@ -48,7 +46,6 @@ public final class StartupWindow extends JDialog implements StartupWindowInterfa
private static Dimension DIMENSIONS = new Dimension(750, 400); private static Dimension DIMENSIONS = new Dimension(750, 400);
private static CueBannerPanel welcomeWindow; private static CueBannerPanel welcomeWindow;
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private AutoIngestCasePanel caseManagementPanel = null;
private static final String LOCAL_HOST_NAME = NetworkUtils.getLocalHostName(); private static final String LOCAL_HOST_NAME = NetworkUtils.getLocalHostName();
public StartupWindow() { public StartupWindow() {
@ -78,12 +75,6 @@ public final class StartupWindow extends JDialog implements StartupWindowInterfa
@Override @Override
public void open() { public void open() {
if (caseManagementPanel != null) {
caseManagementPanel.updateView();
caseManagementPanel.setCursor(Cursor.getDefaultCursor());
}
if (welcomeWindow != null) { if (welcomeWindow != null) {
welcomeWindow.refresh(); welcomeWindow.refresh();
} }
@ -104,38 +95,27 @@ public final class StartupWindow extends JDialog implements StartupWindowInterfa
* user. * user.
*/ */
private void addPanelForMode() { private void addPanelForMode() {
UserPreferences.SelectedMode mode = UserPreferences.getMode(); if(UserPreferences.getMode() == UserPreferences.SelectedMode.AUTOINGEST) {
this.setTitle(NbBundle.getMessage(StartupWindow.class, "StartupWindow.AutoIngestMode") + " (" + LOCAL_HOST_NAME + ")");
switch (mode) { setIconImage(ImageUtilities.loadImage("org/sleuthkit/autopsy/experimental/images/frame.gif", false)); //NON-NLS
case AUTOINGEST: this.addWindowListener(new WindowAdapter() {
this.setTitle(NbBundle.getMessage(StartupWindow.class, "StartupWindow.AutoIngestMode") + " (" + LOCAL_HOST_NAME + ")"); @Override
setIconImage(ImageUtilities.loadImage("org/sleuthkit/autopsy/experimental/images/frame.gif", false)); //NON-NLS public void windowClosing(WindowEvent e) {
this.addWindowListener(new WindowAdapter() { AutoIngestControlPanel.getInstance().shutdown();
@Override }
public void windowClosing(WindowEvent e) { });
AutoIngestControlPanel.getInstance().shutdown(); setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
} add(AutoIngestControlPanel.getInstance());
}); } else {
setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); welcomeWindow = new CueBannerPanel();
add(AutoIngestControlPanel.getInstance()); // add the command to close the window to the button on the Volume Detail Panel
break; welcomeWindow.setCloseButtonActionListener(new ActionListener() {
case REVIEW: @Override
this.setTitle(NbBundle.getMessage(StartupWindow.class, "StartupWindow.ReviewMode") + " (" + LOCAL_HOST_NAME + ")"); public void actionPerformed(ActionEvent e) {
caseManagementPanel = new AutoIngestCasePanel(this); close();
setIconImage(ImageUtilities.loadImage("org/sleuthkit/autopsy/experimental/images/frame.gif", false)); //NON-NLS }
add(caseManagementPanel); });
break; add(welcomeWindow);
default:
welcomeWindow = new CueBannerPanel();
// add the command to close the window to the button on the Volume Detail Panel
welcomeWindow.setCloseButtonActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
close();
}
});
add(welcomeWindow);
break;
} }
} }
} }

View File

@ -138,12 +138,14 @@ final class GlobalListSettingsPanel extends javax.swing.JPanel implements Option
@Override @Override
public void addPropertyChangeListener(PropertyChangeListener l) { public void addPropertyChangeListener(PropertyChangeListener l) {
super.addPropertyChangeListener(l);
listsManagementPanel.addPropertyChangeListener(l); listsManagementPanel.addPropertyChangeListener(l);
editListPanel.addPropertyChangeListener(l); editListPanel.addPropertyChangeListener(l);
} }
@Override @Override
public void removePropertyChangeListener(PropertyChangeListener l) { public void removePropertyChangeListener(PropertyChangeListener l) {
super.removePropertyChangeListener(l);
listsManagementPanel.removePropertyChangeListener(l); listsManagementPanel.removePropertyChangeListener(l);
editListPanel.removePropertyChangeListener(l); editListPanel.removePropertyChangeListener(l);
} }

View File

@ -104,13 +104,13 @@ class HighlightedText implements IndexedText {
/** /**
* This constructor is used when keyword hits are accessed from the ad-hoc * This constructor is used when keyword hits are accessed from the ad-hoc
* search results. In that case we have the entire QueryResults object and * search results. In that case we have the entire QueryResults object and
* need to arrange the paging. need to arrange the paging.
* *
* @param objectId The objectID of the content whose text will be * @param objectId The objectID of the content whose text will be
* highlighted. * highlighted.
* @param QueryResults The QueryResults for the ad-hoc search from whose * @param QueryResults The QueryResults for the ad-hoc search from whose
* results a selection was made leading to this results a selection was made leading to this
* HighlightedText. HighlightedText.
*/ */
HighlightedText(long objectId, QueryResults hits) { HighlightedText(long objectId, QueryResults hits) {
this.objectId = objectId; this.objectId = objectId;

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2011-2016 Basis Technology Corp. * Copyright 2011-2017 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -28,11 +28,12 @@ import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSettingsPanel;
*/ */
final class KeywordSearchGlobalSettingsPanel extends IngestModuleGlobalSettingsPanel implements OptionsPanel { final class KeywordSearchGlobalSettingsPanel extends IngestModuleGlobalSettingsPanel implements OptionsPanel {
private static final long serialVersionUID = 1L;
private GlobalListSettingsPanel listsPanel; private GlobalListSettingsPanel listsPanel;
private KeywordSearchGlobalLanguageSettingsPanel languagesPanel; private KeywordSearchGlobalLanguageSettingsPanel languagesPanel;
private KeywordSearchGlobalSearchSettingsPanel generalPanel; private KeywordSearchGlobalSearchSettingsPanel generalPanel;
public KeywordSearchGlobalSettingsPanel() { KeywordSearchGlobalSettingsPanel() {
initComponents(); initComponents();
customizeComponents(); customizeComponents();
} }
@ -53,6 +54,7 @@ final class KeywordSearchGlobalSettingsPanel extends IngestModuleGlobalSettingsP
@Override @Override
public void addPropertyChangeListener(PropertyChangeListener l) { public void addPropertyChangeListener(PropertyChangeListener l) {
super.addPropertyChangeListener(l);
listsPanel.addPropertyChangeListener(l); listsPanel.addPropertyChangeListener(l);
languagesPanel.addPropertyChangeListener(l); languagesPanel.addPropertyChangeListener(l);
generalPanel.addPropertyChangeListener(l); generalPanel.addPropertyChangeListener(l);
@ -60,6 +62,7 @@ final class KeywordSearchGlobalSettingsPanel extends IngestModuleGlobalSettingsP
@Override @Override
public void removePropertyChangeListener(PropertyChangeListener l) { public void removePropertyChangeListener(PropertyChangeListener l) {
super.removePropertyChangeListener(l);
listsPanel.removePropertyChangeListener(l); listsPanel.removePropertyChangeListener(l);
languagesPanel.removePropertyChangeListener(l); languagesPanel.removePropertyChangeListener(l);
generalPanel.removePropertyChangeListener(l); generalPanel.removePropertyChangeListener(l);

View File

@ -101,20 +101,20 @@ interface KeywordSearchQuery {
String getEscapedQueryString(); String getEscapedQueryString();
/** /**
* Converts the keyword hits for a given search term into artifacts. * Posts a keyword hit artifact to the blackboard for a given keyword hit.
* *
* @param content The Content object associated with the hit. * @param content The text source object for the hit.
* @param foundKeyword The keyword that was found by the search, this may be * @param foundKeyword The keyword that was found by the search, this may be
* different than the Keyword that was searched if, for * different than the Keyword that was searched if, for
* example, it was a RegexQuery. * example, it was a RegexQuery.
* @param hit The keyword hit. * @param hit The keyword hit.
* @param snippet The document snippet that contains the hit. * @param snippet A snippet from the text that contains the hit.
* @param listName The name of the keyword list that contained the * @param listName The name of the keyword list that contained the
* keyword for which the hit was found. * keyword for which the hit was found.
* *
* *
* @return The newly created artifact or Null if there was a problem * @return The newly created artifact or null if there was a problem
* creating it. * creating it.
*/ */
BlackboardArtifact writeSingleFileHitsToBlackBoard(Content content, Keyword foundKeyword, KeywordHit hit, String snippet, String listName); BlackboardArtifact postKeywordHitToBlackboard(Content content, Keyword foundKeyword, KeywordHit hit, String snippet, String listName);
} }

View File

@ -331,7 +331,7 @@ class KeywordSearchResultFactory extends ChildFactory<KeyValueQueryContent> {
final String queryDisp = queryStr.length() > QUERY_DISPLAY_LEN ? queryStr.substring(0, QUERY_DISPLAY_LEN - 1) + " ..." : queryStr; final String queryDisp = queryStr.length() > QUERY_DISPLAY_LEN ? queryStr.substring(0, QUERY_DISPLAY_LEN - 1) + " ..." : queryStr;
try { try {
progress = ProgressHandle.createHandle(NbBundle.getMessage(this.getClass(), "KeywordSearchResultFactory.progress.saving", queryDisp), () -> BlackboardResultWriter.this.cancel(true)); progress = ProgressHandle.createHandle(NbBundle.getMessage(this.getClass(), "KeywordSearchResultFactory.progress.saving", queryDisp), () -> BlackboardResultWriter.this.cancel(true));
hits.writeAllHitsToBlackBoard(progress, null, this, false); hits.process(progress, null, this, false);
} finally { } finally {
finalizeWorker(); finalizeWorker();
} }

View File

@ -52,8 +52,8 @@ class LuceneQuery implements KeywordSearchQuery {
private static final Logger logger = Logger.getLogger(LuceneQuery.class.getName()); private static final Logger logger = Logger.getLogger(LuceneQuery.class.getName());
private String keywordStringEscaped; private String keywordStringEscaped;
private boolean isEscaped; private boolean isEscaped;
private final Keyword originalKeyword ; private final Keyword originalKeyword;
private final KeywordList keywordList ; private final KeywordList keywordList;
private final List<KeywordQueryFilter> filters = new ArrayList<>(); private final List<KeywordQueryFilter> filters = new ArrayList<>();
private String field = null; private String field = null;
private static final int MAX_RESULTS_PER_CURSOR_MARK = 512; private static final int MAX_RESULTS_PER_CURSOR_MARK = 512;
@ -70,7 +70,7 @@ class LuceneQuery implements KeywordSearchQuery {
LuceneQuery(KeywordList keywordList, Keyword keyword) { LuceneQuery(KeywordList keywordList, Keyword keyword) {
this.keywordList = keywordList; this.keywordList = keywordList;
this.originalKeyword = keyword; this.originalKeyword = keyword;
this.keywordStringEscaped = this.originalKeyword.getSearchTerm(); this.keywordStringEscaped = this.originalKeyword.getSearchTerm();
} }
@Override @Override
@ -191,8 +191,24 @@ class LuceneQuery implements KeywordSearchQuery {
return StringUtils.isNotBlank(originalKeyword.getSearchTerm()); return StringUtils.isNotBlank(originalKeyword.getSearchTerm());
} }
/**
* Posts a keyword hit artifact to the blackboard for a given keyword hit.
*
* @param content The text source object for the hit.
* @param foundKeyword The keyword that was found by the search, this may be
* different than the Keyword that was searched if, for
* example, it was a RegexQuery.
* @param hit The keyword hit.
* @param snippet A snippet from the text that contains the hit.
* @param listName The name of the keyword list that contained the
* keyword for which the hit was found.
*
*
* @return The newly created artifact or null if there was a problem
* creating it.
*/
@Override @Override
public BlackboardArtifact writeSingleFileHitsToBlackBoard(Content content, Keyword foundKeyword, KeywordHit hit, String snippet, String listName) { public BlackboardArtifact postKeywordHitToBlackboard(Content content, Keyword foundKeyword, KeywordHit hit, String snippet, String listName) {
final String MODULE_NAME = KeywordSearchModuleFactory.getModuleName(); final String MODULE_NAME = KeywordSearchModuleFactory.getModuleName();
Collection<BlackboardAttribute> attributes = new ArrayList<>(); Collection<BlackboardAttribute> attributes = new ArrayList<>();
@ -225,11 +241,9 @@ class LuceneQuery implements KeywordSearchQuery {
} }
} }
hit.getArtifactID().ifPresent(artifactID hit.getArtifactID().ifPresent(artifactID
-> attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT, MODULE_NAME, artifactID)) -> attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT, MODULE_NAME, artifactID))
); );
try { try {
bba.addAttributes(attributes); //write out to bb bba.addAttributes(attributes); //write out to bb
@ -398,10 +412,10 @@ class LuceneQuery implements KeywordSearchQuery {
return EscapeUtil.unEscapeHtml(contentHighlights.get(0)).trim(); return EscapeUtil.unEscapeHtml(contentHighlights.get(0)).trim();
} }
} catch (NoOpenCoreException ex) { } catch (NoOpenCoreException ex) {
logger.log(Level.SEVERE, "Error executing Lucene Solr Query: " + query +". Solr doc id " + solrObjectId + ", chunkID " + chunkID , ex); //NON-NLS logger.log(Level.SEVERE, "Error executing Lucene Solr Query: " + query + ". Solr doc id " + solrObjectId + ", chunkID " + chunkID, ex); //NON-NLS
throw ex; throw ex;
} catch (KeywordSearchModuleException ex) { } catch (KeywordSearchModuleException ex) {
logger.log(Level.SEVERE, "Error executing Lucene Solr Query: " + query +". Solr doc id " + solrObjectId + ", chunkID " + chunkID , ex); //NON-NLS logger.log(Level.SEVERE, "Error executing Lucene Solr Query: " + query + ". Solr doc id " + solrObjectId + ", chunkID " + chunkID, ex); //NON-NLS
return ""; return "";
} }
} }

View File

@ -45,195 +45,274 @@ import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
/** /**
* Stores the results from running a Solr query (which could contain multiple * Stores and processes the results of a keyword search query. Processing
* keywords). * includes posting keyword hit artifacts to the blackboard, sending messages
* * about the search hits to the ingest inbox, and publishing an event to notify
* subscribers of the blackboard posts.
*/ */
class QueryResults { class QueryResults {
private static final Logger logger = Logger.getLogger(QueryResults.class.getName()); private static final Logger logger = Logger.getLogger(QueryResults.class.getName());
private static final String MODULE_NAME = KeywordSearchModuleFactory.getModuleName(); private static final String MODULE_NAME = KeywordSearchModuleFactory.getModuleName();
/** private final KeywordSearchQuery query;
* The query that generated the results.
*/
private final KeywordSearchQuery keywordSearchQuery;
/**
* A map of keywords to keyword hits.
*/
private final Map<Keyword, List<KeywordHit>> results = new HashMap<>(); private final Map<Keyword, List<KeywordHit>> results = new HashMap<>();
/**
* Constructs a object that stores and processes the results of a keyword
* search query. Processing includes posting keyword hit artifacts to the
* blackboard, sending messages about the search hits to the ingest inbox,
* and publishing an event to notify subscribers of the blackboard posts.
*
* The KeywordSearchQuery is used to do the blackboard posts.
*
* @param query The query.
*/
QueryResults(KeywordSearchQuery query) { QueryResults(KeywordSearchQuery query) {
this.keywordSearchQuery = query; this.query = query;
} }
/**
* Gets the keyword search query that generated the results stored in this
* object.
*
* @return The query.
*/
KeywordSearchQuery getQuery() {
return query;
}
/**
* Adds the keyword hits for a keyword to the hits that are stored in this
* object. All calls to this method MUST be completed before calling the
* process method.
*
* @param keyword The keyword,
* @param hits The hits.
*/
void addResult(Keyword keyword, List<KeywordHit> hits) { void addResult(Keyword keyword, List<KeywordHit> hits) {
results.put(keyword, hits); results.put(keyword, hits);
} }
KeywordSearchQuery getQuery() { /**
return keywordSearchQuery; * Gets the keyword hits stored in this object for a given keyword.
} *
* @param keyword The keyword.
*
* @return The keyword hits.
*/
List<KeywordHit> getResults(Keyword keyword) { List<KeywordHit> getResults(Keyword keyword) {
return results.get(keyword); return results.get(keyword);
} }
/**
* Gets the set of unique keywords for which keyword hits have been stored
* in this object.
*
* @return
*/
Set<Keyword> getKeywords() { Set<Keyword> getKeywords() {
return results.keySet(); return results.keySet();
} }
/** /**
* Writes the keyword hits encapsulated in this query result to the * Processes the keyword hits stored in this object by osting keyword hit
* blackboard. Makes one artifact per keyword per searched object (file or * artifacts to the blackboard, sending messages about the search hits to
* artifact), i.e., if a keyword is found several times in the object, only * the ingest inbox, and publishing an event to notify subscribers of the
* one artifact is created. * blackboard posts.
* *
* @param progress Can be null. * Makes one artifact per keyword per searched text source object (file or
* @param subProgress Can be null. * artifact), i.e., if a keyword is found several times in the text
* @param worker The Swing worker that is writing the hits, needed to * extracted from the source object, only one artifact is created.
* support cancellation. *
* @param notifyInbox Whether or not write a message to the ingest messages * This method ASSUMES that the processing is being done using a SwingWorker
* inbox. * that should be checked for task cancellation.
*
* All calls to the addResult method MUST be completed before calling this
* method.
*
* @param progress A progress indicator that reports the number of
* keywords processed. Can be null.
* @param subProgress A progress contributor that reports the keyword
* currently being processed. Can be null.
* @param worker The SwingWorker that is being used to do the
* processing, will be checked for task cancellation
* before processing each keyword.
* @param notifyInbox Whether or not to write a message to the ingest
* messages inbox if there is a keyword hit in the text
* exrtacted from the text source object.
* *
* @return The artifacts that were created.
*/ */
Collection<BlackboardArtifact> writeAllHitsToBlackBoard(ProgressHandle progress, ProgressContributor subProgress, SwingWorker<?, ?> worker, boolean notifyInbox) { void process(ProgressHandle progress, ProgressContributor subProgress, SwingWorker<?, ?> worker, boolean notifyInbox) {
final Collection<BlackboardArtifact> newArtifacts = new ArrayList<>(); /*
if (progress != null) { * Initialize the progress indicator to the number of keywords that will
* be processed.
*/
if (null != progress) {
progress.start(getKeywords().size()); progress.start(getKeywords().size());
} }
int unitProgress = 0;
/*
* Process the keyword hits for each keyword.
*/
int keywordsProcessed = 0;
final Collection<BlackboardArtifact> hitArtifacts = new ArrayList<>();
for (final Keyword keyword : getKeywords()) { for (final Keyword keyword : getKeywords()) {
/*
* Cancellation check.
*/
if (worker.isCancelled()) { if (worker.isCancelled()) {
logger.log(Level.INFO, "Cancel detected, bailing before new keyword processed: {0}", keyword.getSearchTerm()); //NON-NLS logger.log(Level.INFO, "Processing cancelled, exiting before processing search term {0}", keyword.getSearchTerm()); //NON-NLS
break; break;
} }
// Update progress object(s), if any /*
* Update the progress indicator and the show the current keyword
* via the progress contributor.
*/
if (progress != null) { if (progress != null) {
progress.progress(keyword.toString(), unitProgress); progress.progress(keyword.toString(), keywordsProcessed);
} }
if (subProgress != null) { if (subProgress != null) {
String hitDisplayStr = keyword.getSearchTerm(); String hitDisplayStr = keyword.getSearchTerm();
if (hitDisplayStr.length() > 50) { if (hitDisplayStr.length() > 50) {
hitDisplayStr = hitDisplayStr.substring(0, 49) + "..."; hitDisplayStr = hitDisplayStr.substring(0, 49) + "...";
} }
subProgress.progress(keywordSearchQuery.getKeywordList().getName() + ": " + hitDisplayStr, unitProgress); subProgress.progress(query.getKeywordList().getName() + ": " + hitDisplayStr, keywordsProcessed);
} }
for (KeywordHit hit : getOneHitPerObject(keyword)) { /*
String termString = keyword.getSearchTerm(); * Reduce the hits for this keyword to one hit per text source
* object so that only one hit artifact is generated per text source
* object, no matter how many times the keyword was actually found.
*/
for (KeywordHit hit : getOneHitPerTextSourceObject(keyword)) {
/*
* Get a snippet (preview) for the hit. Regex queries always
* have snippets made from the content_str pulled back from Solr
* for executing the search. Other types of queries may or may
* not have snippets yet.
*/
String snippet = hit.getSnippet(); String snippet = hit.getSnippet();
if (StringUtils.isBlank(snippet)) { if (StringUtils.isBlank(snippet)) {
final String snippetQuery = KeywordSearchUtil.escapeLuceneQuery(termString); final String snippetQuery = KeywordSearchUtil.escapeLuceneQuery(keyword.getSearchTerm());
try { try {
/* snippet = LuceneQuery.querySnippet(snippetQuery, hit.getSolrObjectId(), hit.getChunkId(), !query.isLiteral(), true);
* this doesn't work for regex queries... But that is
* okay because regex queries always have snippets made
* from the content_str field we pull back from Solr
*/
snippet = LuceneQuery.querySnippet(snippetQuery, hit.getSolrObjectId(), hit.getChunkId(), !keywordSearchQuery.isLiteral(), true);
} catch (NoOpenCoreException e) { } catch (NoOpenCoreException e) {
logger.log(Level.WARNING, "Error querying snippet: " + snippetQuery, e); //NON-NLS logger.log(Level.SEVERE, "Solr core closed while executing snippet query " + snippetQuery, e); //NON-NLS
//no reason to continue break; // Stop processing.
break;
} catch (Exception e) { } catch (Exception e) {
logger.log(Level.WARNING, "Error querying snippet: " + snippetQuery, e); //NON-NLS logger.log(Level.SEVERE, "Error executing snippet query " + snippetQuery, e); //NON-NLS
continue; continue; // Try processing the next hit.
} }
} }
/*
* Get the content (file or artifact) that is the text source
* for the hit.
*/
Content content = null; Content content = null;
try { try {
SleuthkitCase tskCase = Case.getCurrentCase().getSleuthkitCase(); SleuthkitCase tskCase = Case.getCurrentCase().getSleuthkitCase();
content = tskCase.getContentById(hit.getContentID()); content = tskCase.getContentById(hit.getContentID());
} catch (TskCoreException | IllegalStateException tskCoreException) { } catch (TskCoreException | IllegalStateException tskCoreException) {
logger.log(Level.SEVERE, "Error adding artifact for keyword hit to blackboard", tskCoreException); //NON-NLS logger.log(Level.SEVERE, "Failed to get text source object for ", tskCoreException); //NON-NLS
return null;
} }
BlackboardArtifact writeResult = keywordSearchQuery.writeSingleFileHitsToBlackBoard(content, keyword, hit, snippet, keywordSearchQuery.getKeywordList().getName());
if (writeResult != null) { /*
newArtifacts.add(writeResult); * Post an artifact for the hit to the blackboard.
*/
BlackboardArtifact artifact = query.postKeywordHitToBlackboard(content, keyword, hit, snippet, query.getKeywordList().getName());
if (null == artifact) {
logger.log(Level.SEVERE, "Error posting keyword hit artifact for keyword {0} in {1} to the blackboard", new Object[]{keyword.toString(), content}); //NON-NLS
}
/*
* Send an ingest inbox message for the hit.
*/
if (null != artifact) {
hitArtifacts.add(artifact);
if (notifyInbox) { if (notifyInbox) {
try { try {
writeSingleFileInboxMessage(writeResult, content); writeSingleFileInboxMessage(artifact, content);
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
logger.log(Level.WARNING, "Error posting message to Ingest Inbox", ex); //NON-NLS logger.log(Level.SEVERE, "Error sending message to ingest messages inbox", ex); //NON-NLS
} }
} }
} else {
logger.log(Level.WARNING, "BB artifact for keyword hit not written, file: {0}, hit: {1}", new Object[]{content, keyword.toString()}); //NON-NLS
} }
} }
++unitProgress;
++keywordsProcessed;
} }
// Update artifact browser /*
if (!newArtifacts.isEmpty()) { * Publish an event to notify subscribers of the blackboard posts. The
newArtifacts.stream() * artifacts are grouped by type, since they may contain both
//group artifacts by type * TSK_KEYWORD_HIT artifacts and TSK_ACCOUNT artifacts (for credit card
* account number hits).
*/
if (!hitArtifacts.isEmpty()) {
hitArtifacts.stream()
// Group artifacts by type
.collect(Collectors.groupingBy(BlackboardArtifact::getArtifactTypeID)) .collect(Collectors.groupingBy(BlackboardArtifact::getArtifactTypeID))
//for each type send an event // For each type send an event
.forEach((typeID, artifacts) .forEach((typeID, artifacts)
-> IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent(MODULE_NAME, BlackboardArtifact.ARTIFACT_TYPE.fromID(typeID), artifacts))); -> IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent(MODULE_NAME, BlackboardArtifact.ARTIFACT_TYPE.fromID(typeID), artifacts)));
} }
return newArtifacts;
} }
/** /**
* Gets the first hit of the keyword. * Reduce the hits for a given keyword to one hit per text source object so
* that only one hit artifact is generated per text source object, no matter
* how many times the keyword was actually found.
* *
* @param keyword * @param keyword The keyword.
* *
* @return Collection<KeywordHit> containing KeywordHits with lowest * @return Collection<KeywordHit> The reduced set of keyword hits.
* SolrObjectID-ChunkID pairs.
*/ */
private Collection<KeywordHit> getOneHitPerObject(Keyword keyword) { private Collection<KeywordHit> getOneHitPerTextSourceObject(Keyword keyword) {
HashMap<Long, KeywordHit> hits = new HashMap<>(); /*
* For each Solr document (chunk) for a text source object, return only
// create a list of KeywordHits. KeywordHits with lowest chunkID is added the the list. * a single keyword hit from the first chunk of text (the one with the
for (KeywordHit hit : getResults(keyword)) { * lowest chunk id).
*/
HashMap< Long, KeywordHit> hits = new HashMap<>();
getResults(keyword).forEach((hit) -> {
if (!hits.containsKey(hit.getSolrObjectId())) { if (!hits.containsKey(hit.getSolrObjectId())) {
hits.put(hit.getSolrObjectId(), hit); hits.put(hit.getSolrObjectId(), hit);
} else if (hit.getChunkId() < hits.get(hit.getSolrObjectId()).getChunkId()) { } else if (hit.getChunkId() < hits.get(hit.getSolrObjectId()).getChunkId()) {
hits.put(hit.getSolrObjectId(), hit); hits.put(hit.getSolrObjectId(), hit);
} }
} });
return hits.values(); return hits.values();
} }
/** /**
* Generate and post an ingest inbox message for the given keyword in the * Send an ingest inbox message indicating that there was a keyword hit in
* given content. * the given text source object.
* *
* @param artifact The keyword hit artifact. * @param artifact The keyword hit artifact for the hit.
* @param hitContent The content that the hit is in. * @param hitContent The text source object.
* *
* @throws TskCoreException If there is a problem generating or posting the * @throws TskCoreException If there is a problem generating or send the
* inbox message. * inbox message.
*/ */
private void writeSingleFileInboxMessage(BlackboardArtifact artifact, Content hitContent) throws TskCoreException { private void writeSingleFileInboxMessage(BlackboardArtifact artifact, Content hitContent) throws TskCoreException {
StringBuilder subjectSb = new StringBuilder(); StringBuilder subjectSb = new StringBuilder(1024);
StringBuilder detailsSb = new StringBuilder(); if (!query.isLiteral()) {
if (!keywordSearchQuery.isLiteral()) {
subjectSb.append(NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.regExpHitLbl")); subjectSb.append(NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.regExpHitLbl"));
} else { } else {
subjectSb.append(NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.kwHitLbl")); subjectSb.append(NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.kwHitLbl"));
} }
StringBuilder detailsSb = new StringBuilder(1024);
String uniqueKey = null; String uniqueKey = null;
BlackboardAttribute attr = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD)); BlackboardAttribute attr = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD));
if (attr != null) { if (attr != null) {
final String keyword = attr.getValueString(); final String keyword = attr.getValueString();
subjectSb.append(keyword); subjectSb.append(keyword);
uniqueKey = keyword.toLowerCase(); uniqueKey = keyword.toLowerCase();
//details
detailsSb.append("<table border='0' cellpadding='4' width='280'>"); //NON-NLS detailsSb.append("<table border='0' cellpadding='4' width='280'>"); //NON-NLS
//hit
detailsSb.append("<tr>"); //NON-NLS detailsSb.append("<tr>"); //NON-NLS
detailsSb.append(NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.kwHitThLbl")); detailsSb.append(NbBundle.getMessage(this.getClass(), "KeywordSearchIngestModule.kwHitThLbl"));
detailsSb.append("<td>").append(EscapeUtil.escapeHtml(keyword)).append("</td>"); //NON-NLS detailsSb.append("<td>").append(EscapeUtil.escapeHtml(keyword)).append("</td>"); //NON-NLS
@ -270,7 +349,7 @@ class QueryResults {
} }
//regex //regex
if (!keywordSearchQuery.isLiteral()) { if (!query.isLiteral()) {
attr = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP)); attr = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP));
if (attr != null) { if (attr != null) {
detailsSb.append("<tr>"); //NON-NLS detailsSb.append("<tr>"); //NON-NLS
@ -279,7 +358,6 @@ class QueryResults {
detailsSb.append("</tr>"); //NON-NLS detailsSb.append("</tr>"); //NON-NLS
} }
} }
detailsSb.append("</table>"); //NON-NLS detailsSb.append("</table>"); //NON-NLS
IngestServices.getInstance().postMessage(IngestMessage.createDataMessage(MODULE_NAME, subjectSb.toString(), detailsSb.toString(), uniqueKey, artifact)); IngestServices.getInstance().postMessage(IngestMessage.createDataMessage(MODULE_NAME, subjectSb.toString(), detailsSb.toString(), uniqueKey, artifact));

View File

@ -403,8 +403,24 @@ final class RegexQuery implements KeywordSearchQuery {
return escapedQuery; return escapedQuery;
} }
/**
* Posts a keyword hit artifact to the blackboard for a given keyword hit.
*
* @param content The text source object for the hit.
* @param foundKeyword The keyword that was found by the search, this may be
* different than the Keyword that was searched if, for
* example, it was a RegexQuery.
* @param hit The keyword hit.
* @param snippet A snippet from the text that contains the hit.
* @param listName The name of the keyword list that contained the
* keyword for which the hit was found.
*
*
* @return The newly created artifact or null if there was a problem
* creating it.
*/
@Override @Override
public BlackboardArtifact writeSingleFileHitsToBlackBoard(Content content, Keyword foundKeyword, KeywordHit hit, String snippet, String listName) { public BlackboardArtifact postKeywordHitToBlackboard(Content content, Keyword foundKeyword, KeywordHit hit, String snippet, String listName) {
final String MODULE_NAME = KeywordSearchModuleFactory.getModuleName(); final String MODULE_NAME = KeywordSearchModuleFactory.getModuleName();
if (content == null) { if (content == null) {
@ -413,96 +429,30 @@ final class RegexQuery implements KeywordSearchQuery {
} }
/* /*
* Create either a "plain vanilla" keyword hit artifact with keyword and * Credit Card number hits are handled differently
* regex attributes, or a credit card account artifact with attributes */
* parsed from from the snippet for the hit and looked up based on the if (originalKeyword.getArtifactAttributeType() == ATTRIBUTE_TYPE.TSK_CARD_NUMBER) {
* parsed bank identifcation number. createCCNAccount(content, foundKeyword, hit, snippet, listName);
return null;
}
/*
* Create a "plain vanilla" keyword hit artifact with keyword and
* regex attributes
*/ */
BlackboardArtifact newArtifact; BlackboardArtifact newArtifact;
Collection<BlackboardAttribute> attributes = new ArrayList<>(); Collection<BlackboardAttribute> attributes = new ArrayList<>();
if (originalKeyword.getArtifactAttributeType() != ATTRIBUTE_TYPE.TSK_CARD_NUMBER) {
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD, MODULE_NAME, foundKeyword.getSearchTerm())); attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD, MODULE_NAME, foundKeyword.getSearchTerm()));
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP, MODULE_NAME, getQueryString())); attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP, MODULE_NAME, getQueryString()));
try {
newArtifact = content.newArtifact(ARTIFACT_TYPE.TSK_KEYWORD_HIT); try {
} catch (TskCoreException ex) { newArtifact = content.newArtifact(ARTIFACT_TYPE.TSK_KEYWORD_HIT);
LOGGER.log(Level.SEVERE, "Error adding artifact for keyword hit to blackboard", ex); //NON-NLS } catch (TskCoreException ex) {
return null; LOGGER.log(Level.SEVERE, "Error adding artifact for keyword hit to blackboard", ex); //NON-NLS
} return null;
} else {
/*
* Parse the credit card account attributes from the snippet for the
* hit.
*/
Map<BlackboardAttribute.Type, BlackboardAttribute> parsedTrackAttributeMap = new HashMap<>();
Matcher matcher = TermsComponentQuery.CREDIT_CARD_TRACK1_PATTERN.matcher(hit.getSnippet());
if (matcher.find()) {
parseTrack1Data(parsedTrackAttributeMap, matcher);
}
matcher = CREDIT_CARD_TRACK2_PATTERN.matcher(hit.getSnippet());
if (matcher.find()) {
parseTrack2Data(parsedTrackAttributeMap, matcher);
}
final BlackboardAttribute ccnAttribute = parsedTrackAttributeMap.get(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_CARD_NUMBER));
if (ccnAttribute == null || StringUtils.isBlank(ccnAttribute.getValueString())) {
if (hit.isArtifactHit()) {
LOGGER.log(Level.SEVERE, String.format("Failed to parse credit card account number for artifact keyword hit: term = %s, snippet = '%s', artifact id = %d", foundKeyword.getSearchTerm(), hit.getSnippet(), hit.getArtifactID().get())); //NON-NLS
} else {
LOGGER.log(Level.SEVERE, String.format("Failed to parse credit card account number for content keyword hit: term = %s, snippet = '%s', object id = %d", foundKeyword.getSearchTerm(), hit.getSnippet(), hit.getContentID())); //NON-NLS
}
return null;
}
attributes.addAll(parsedTrackAttributeMap.values());
/*
* Look up the bank name, scheme, etc. attributes for the bank
* indentification number (BIN).
*/
final int bin = Integer.parseInt(ccnAttribute.getValueString().substring(0, 8));
CreditCards.BankIdentificationNumber binInfo = CreditCards.getBINInfo(bin);
if (binInfo != null) {
binInfo.getScheme().ifPresent(scheme
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_CARD_SCHEME, MODULE_NAME, scheme)));
binInfo.getCardType().ifPresent(cardType
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_CARD_TYPE, MODULE_NAME, cardType)));
binInfo.getBrand().ifPresent(brand
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_BRAND_NAME, MODULE_NAME, brand)));
binInfo.getBankName().ifPresent(bankName
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_BANK_NAME, MODULE_NAME, bankName)));
binInfo.getBankPhoneNumber().ifPresent(phoneNumber
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER, MODULE_NAME, phoneNumber)));
binInfo.getBankURL().ifPresent(url
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL, MODULE_NAME, url)));
binInfo.getCountry().ifPresent(country
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COUNTRY, MODULE_NAME, country)));
binInfo.getBankCity().ifPresent(city
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_CITY, MODULE_NAME, city)));
}
/*
* If the hit is from unused or unallocated space, record the Solr
* document id to support showing just the chunk that contained the
* hit.
*/
if (content instanceof AbstractFile) {
AbstractFile file = (AbstractFile) content;
if (file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS
|| file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) {
attributes.add(new BlackboardAttribute(KEYWORD_SEARCH_DOCUMENT_ID, MODULE_NAME, hit.getSolrDocumentId()));
}
}
/*
* Create an account instance.
*/
try {
AccountInstance ccAccountInstance = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().createAccountInstance(Account.Type.CREDIT_CARD, ccnAttribute.getValueString() , MODULE_NAME, content);
newArtifact = Case.getCurrentCase().getSleuthkitCase().getBlackboardArtifact(ccAccountInstance.getArtifactId());
} catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, "Error adding artifact for account to blackboard", ex); //NON-NLS
return null;
}
} }
if (StringUtils.isNotBlank(listName)) { if (StringUtils.isNotBlank(listName)) {
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_SET_NAME, MODULE_NAME, listName)); attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_SET_NAME, MODULE_NAME, listName));
@ -526,6 +476,107 @@ final class RegexQuery implements KeywordSearchQuery {
} }
} }
private void createCCNAccount(Content content, Keyword foundKeyword, KeywordHit hit, String snippet, String listName) {
final String MODULE_NAME = KeywordSearchModuleFactory.getModuleName();
if (originalKeyword.getArtifactAttributeType() != ATTRIBUTE_TYPE.TSK_CARD_NUMBER) {
LOGGER.log(Level.SEVERE, "Keyword hit is not a credit card number"); //NON-NLS
return;
}
/*
* Create a credit card account with attributes
* parsed from the snippet for the hit and looked up based on the
* parsed bank identifcation number.
*/
Collection<BlackboardAttribute> attributes = new ArrayList<>();
Map<BlackboardAttribute.Type, BlackboardAttribute> parsedTrackAttributeMap = new HashMap<>();
Matcher matcher = TermsComponentQuery.CREDIT_CARD_TRACK1_PATTERN.matcher(hit.getSnippet());
if (matcher.find()) {
parseTrack1Data(parsedTrackAttributeMap, matcher);
}
matcher = CREDIT_CARD_TRACK2_PATTERN.matcher(hit.getSnippet());
if (matcher.find()) {
parseTrack2Data(parsedTrackAttributeMap, matcher);
}
final BlackboardAttribute ccnAttribute = parsedTrackAttributeMap.get(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_CARD_NUMBER));
if (ccnAttribute == null || StringUtils.isBlank(ccnAttribute.getValueString())) {
if (hit.isArtifactHit()) {
LOGGER.log(Level.SEVERE, String.format("Failed to parse credit card account number for artifact keyword hit: term = %s, snippet = '%s', artifact id = %d", foundKeyword.getSearchTerm(), hit.getSnippet(), hit.getArtifactID().get())); //NON-NLS
} else {
LOGGER.log(Level.SEVERE, String.format("Failed to parse credit card account number for content keyword hit: term = %s, snippet = '%s', object id = %d", foundKeyword.getSearchTerm(), hit.getSnippet(), hit.getContentID())); //NON-NLS
}
return;
}
attributes.addAll(parsedTrackAttributeMap.values());
/*
* Look up the bank name, scheme, etc. attributes for the bank
* indentification number (BIN).
*/
final int bin = Integer.parseInt(ccnAttribute.getValueString().substring(0, 8));
CreditCards.BankIdentificationNumber binInfo = CreditCards.getBINInfo(bin);
if (binInfo != null) {
binInfo.getScheme().ifPresent(scheme
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_CARD_SCHEME, MODULE_NAME, scheme)));
binInfo.getCardType().ifPresent(cardType
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_CARD_TYPE, MODULE_NAME, cardType)));
binInfo.getBrand().ifPresent(brand
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_BRAND_NAME, MODULE_NAME, brand)));
binInfo.getBankName().ifPresent(bankName
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_BANK_NAME, MODULE_NAME, bankName)));
binInfo.getBankPhoneNumber().ifPresent(phoneNumber
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER, MODULE_NAME, phoneNumber)));
binInfo.getBankURL().ifPresent(url
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL, MODULE_NAME, url)));
binInfo.getCountry().ifPresent(country
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COUNTRY, MODULE_NAME, country)));
binInfo.getBankCity().ifPresent(city
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_CITY, MODULE_NAME, city)));
}
/*
* If the hit is from unused or unallocated space, record the Solr
* document id to support showing just the chunk that contained the
* hit.
*/
if (content instanceof AbstractFile) {
AbstractFile file = (AbstractFile) content;
if (file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS
|| file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) {
attributes.add(new BlackboardAttribute(KEYWORD_SEARCH_DOCUMENT_ID, MODULE_NAME, hit.getSolrDocumentId()));
}
}
if (StringUtils.isNotBlank(listName)) {
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_SET_NAME, MODULE_NAME, listName));
}
if (snippet != null) {
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD_PREVIEW, MODULE_NAME, snippet));
}
hit.getArtifactID().ifPresent(artifactID
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT, MODULE_NAME, artifactID))
);
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_TYPE, MODULE_NAME, KeywordSearch.QueryType.REGEX.ordinal()));
/*
* Create an account instance.
*/
try {
AccountInstance ccAccountInstance = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().createAccountInstance(Account.Type.CREDIT_CARD, ccnAttribute.getValueString() , MODULE_NAME, content);
ccAccountInstance.addAttributes(attributes);
} catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, "Error creating CCN account instance", ex); //NON-NLS
}
}
/** /**
* Parses the track 2 data from the snippet for a credit card account number * Parses the track 2 data from the snippet for a credit card account number
* hit and turns them into artifact attributes. * hit and turns them into artifact attributes.

View File

@ -492,7 +492,7 @@ public final class SearchRunner {
subProgresses[keywordsSearched].progress(keywordList.getName() + ": " + queryDisplayStr, unitProgress); subProgresses[keywordsSearched].progress(keywordList.getName() + ": " + queryDisplayStr, unitProgress);
// Create blackboard artifacts // Create blackboard artifacts
newResults.writeAllHitsToBlackBoard(null, subProgresses[keywordsSearched], this, keywordList.getIngestMessages()); newResults.process(null, subProgresses[keywordsSearched], this, keywordList.getIngestMessages());
} //if has results } //if has results

View File

@ -81,8 +81,8 @@ final class TermsComponentQuery implements KeywordSearchQuery {
* digit is 2 through 6 * digit is 2 through 6
* *
*/ */
static final Pattern CREDIT_CARD_NUM_PATTERN = static final Pattern CREDIT_CARD_NUM_PATTERN
Pattern.compile("(?<ccn>[2-6]([ -]?[0-9]){11,18})"); = Pattern.compile("(?<ccn>[2-6]([ -]?[0-9]){11,18})");
static final Pattern CREDIT_CARD_TRACK1_PATTERN = Pattern.compile( static final Pattern CREDIT_CARD_TRACK1_PATTERN = Pattern.compile(
/* /*
* Track 1 is alphanumeric. * Track 1 is alphanumeric.
@ -126,7 +126,6 @@ final class TermsComponentQuery implements KeywordSearchQuery {
+ "?)?)?)?)?)?"); //close nested optional groups //NON-NLS + "?)?)?)?)?)?"); //close nested optional groups //NON-NLS
static final BlackboardAttribute.Type KEYWORD_SEARCH_DOCUMENT_ID = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_DOCUMENT_ID); static final BlackboardAttribute.Type KEYWORD_SEARCH_DOCUMENT_ID = new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_DOCUMENT_ID);
/** /**
* Constructs an object that implements a regex query that will be performed * Constructs an object that implements a regex query that will be performed
* as a two step operation. In the first step, the Solr terms component is * as a two step operation. In the first step, the Solr terms component is
@ -327,101 +326,51 @@ final class TermsComponentQuery implements KeywordSearchQuery {
return results; return results;
} }
/**
* Posts a keyword hit artifact to the blackboard for a given keyword hit.
*
* @param content The text source object for the hit.
* @param foundKeyword The keyword that was found by the search, this may be
* different than the Keyword that was searched if, for
* example, it was a RegexQuery.
* @param hit The keyword hit.
* @param snippet A snippet from the text that contains the hit.
* @param listName The name of the keyword list that contained the
* keyword for which the hit was found.
*
*
* @return The newly created artifact or null if there was a problem
* creating it.
*/
@Override @Override
public BlackboardArtifact writeSingleFileHitsToBlackBoard(Content content, Keyword foundKeyword, KeywordHit hit, String snippet, String listName) { public BlackboardArtifact postKeywordHitToBlackboard(Content content, Keyword foundKeyword, KeywordHit hit, String snippet, String listName) {
/* /*
* Create either a "plain vanilla" keyword hit artifact with keyword and * CCN hits are handled specially
* regex attributes, or a credit card account artifact with attributes */
* parsed from from the snippet for the hit and looked up based on the if (originalKeyword.getArtifactAttributeType() == ATTRIBUTE_TYPE.TSK_CARD_NUMBER) {
* parsed bank identifcation number. createCCNAccount(content, hit, snippet, listName);
return null;
}
/*
* Create a "plain vanilla" keyword hit artifact with keyword and
* regex attributes,
*/ */
BlackboardArtifact newArtifact; BlackboardArtifact newArtifact;
Collection<BlackboardAttribute> attributes = new ArrayList<>(); Collection<BlackboardAttribute> attributes = new ArrayList<>();
if (originalKeyword.getArtifactAttributeType() != ATTRIBUTE_TYPE.TSK_CARD_NUMBER) {
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD, MODULE_NAME, foundKeyword.getSearchTerm())); attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD, MODULE_NAME, foundKeyword.getSearchTerm()));
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP, MODULE_NAME, originalKeyword.getSearchTerm())); attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP, MODULE_NAME, originalKeyword.getSearchTerm()));
try { try {
newArtifact = content.newArtifact(ARTIFACT_TYPE.TSK_KEYWORD_HIT); newArtifact = content.newArtifact(ARTIFACT_TYPE.TSK_KEYWORD_HIT);
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, "Error adding artifact for keyword hit to blackboard", ex); //NON-NLS LOGGER.log(Level.SEVERE, "Error adding artifact for keyword hit to blackboard", ex); //NON-NLS
return null; return null;
}
} else {
/*
* Parse the credit card account attributes from the snippet for the
* hit.
*/
Map<BlackboardAttribute.Type, BlackboardAttribute> parsedTrackAttributeMap = new HashMap<>();
Matcher matcher = CREDIT_CARD_TRACK1_PATTERN.matcher(hit.getSnippet());
if (matcher.find()) {
parseTrack1Data(parsedTrackAttributeMap, matcher);
}
matcher = CREDIT_CARD_TRACK2_PATTERN.matcher(hit.getSnippet());
if (matcher.find()) {
parseTrack2Data(parsedTrackAttributeMap, matcher);
}
final BlackboardAttribute ccnAttribute = parsedTrackAttributeMap.get(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_CARD_NUMBER));
if (ccnAttribute == null || StringUtils.isBlank(ccnAttribute.getValueString())) {
if (hit.isArtifactHit()) {
LOGGER.log(Level.SEVERE, String.format("Failed to parse credit card account number for artifact keyword hit: term = %s, snippet = '%s', artifact id = %d", searchTerm, hit.getSnippet(), hit.getArtifactID().get())); //NON-NLS
} else {
LOGGER.log(Level.SEVERE, String.format("Failed to parse credit card account number for content keyword hit: term = %s, snippet = '%s', object id = %d", searchTerm, hit.getSnippet(), hit.getContentID())); //NON-NLS
}
return null;
}
attributes.addAll(parsedTrackAttributeMap.values());
/*
* Look up the bank name, scheme, etc. attributes for the bank
* indentification number (BIN).
*/
final int bin = Integer.parseInt(ccnAttribute.getValueString().substring(0, 8));
CreditCards.BankIdentificationNumber binInfo = CreditCards.getBINInfo(bin);
if (binInfo != null) {
binInfo.getScheme().ifPresent(scheme
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_CARD_SCHEME, MODULE_NAME, scheme)));
binInfo.getCardType().ifPresent(cardType
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_CARD_TYPE, MODULE_NAME, cardType)));
binInfo.getBrand().ifPresent(brand
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_BRAND_NAME, MODULE_NAME, brand)));
binInfo.getBankName().ifPresent(bankName
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_BANK_NAME, MODULE_NAME, bankName)));
binInfo.getBankPhoneNumber().ifPresent(phoneNumber
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER, MODULE_NAME, phoneNumber)));
binInfo.getBankURL().ifPresent(url
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL, MODULE_NAME, url)));
binInfo.getCountry().ifPresent(country
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COUNTRY, MODULE_NAME, country)));
binInfo.getBankCity().ifPresent(city
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_CITY, MODULE_NAME, city)));
}
/*
* If the hit is from unused or unallocated space, record the Solr
* document id to support showing just the chunk that contained the
* hit.
*/
if (content instanceof AbstractFile) {
AbstractFile file = (AbstractFile) content;
if (file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS
|| file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) {
attributes.add(new BlackboardAttribute(KEYWORD_SEARCH_DOCUMENT_ID, MODULE_NAME, hit.getSolrDocumentId()));
}
}
/*
* Create an account artifact.
*/
try {
AccountInstance ccAccountInstance = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().createAccountInstance(Account.Type.CREDIT_CARD, ccnAttribute.getValueString() , MODULE_NAME, content);
newArtifact = Case.getCurrentCase().getSleuthkitCase().getBlackboardArtifact(ccAccountInstance.getArtifactId());
} catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, "Error adding artifact for account to blackboard", ex); //NON-NLS
return null;
}
} }
if (StringUtils.isNotBlank(listName)) { if (StringUtils.isNotBlank(listName)) {
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_SET_NAME, MODULE_NAME, listName)); attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_SET_NAME, MODULE_NAME, listName));
@ -446,6 +395,104 @@ final class TermsComponentQuery implements KeywordSearchQuery {
} }
} }
private void createCCNAccount(Content content, KeywordHit hit, String snippet, String listName) {
if (originalKeyword.getArtifactAttributeType() != ATTRIBUTE_TYPE.TSK_CARD_NUMBER) {
LOGGER.log(Level.SEVERE, "Keyword hit is not a credit card number"); //NON-NLS
return;
}
/*
* Create a credit card account with attributes
* parsed from from the snippet for the hit and looked up based on the
* parsed bank identifcation number.
*/
Collection<BlackboardAttribute> attributes = new ArrayList<>();
Map<BlackboardAttribute.Type, BlackboardAttribute> parsedTrackAttributeMap = new HashMap<>();
Matcher matcher = CREDIT_CARD_TRACK1_PATTERN.matcher(hit.getSnippet());
if (matcher.find()) {
parseTrack1Data(parsedTrackAttributeMap, matcher);
}
matcher = CREDIT_CARD_TRACK2_PATTERN.matcher(hit.getSnippet());
if (matcher.find()) {
parseTrack2Data(parsedTrackAttributeMap, matcher);
}
final BlackboardAttribute ccnAttribute = parsedTrackAttributeMap.get(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_CARD_NUMBER));
if (ccnAttribute == null || StringUtils.isBlank(ccnAttribute.getValueString())) {
if (hit.isArtifactHit()) {
LOGGER.log(Level.SEVERE, String.format("Failed to parse credit card account number for artifact keyword hit: term = %s, snippet = '%s', artifact id = %d", searchTerm, hit.getSnippet(), hit.getArtifactID().get())); //NON-NLS
} else {
LOGGER.log(Level.SEVERE, String.format("Failed to parse credit card account number for content keyword hit: term = %s, snippet = '%s', object id = %d", searchTerm, hit.getSnippet(), hit.getContentID())); //NON-NLS
}
return;
}
attributes.addAll(parsedTrackAttributeMap.values());
/*
* Look up the bank name, scheme, etc. attributes for the bank
* indentification number (BIN).
*/
final int bin = Integer.parseInt(ccnAttribute.getValueString().substring(0, 8));
CreditCards.BankIdentificationNumber binInfo = CreditCards.getBINInfo(bin);
if (binInfo != null) {
binInfo.getScheme().ifPresent(scheme
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_CARD_SCHEME, MODULE_NAME, scheme)));
binInfo.getCardType().ifPresent(cardType
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_CARD_TYPE, MODULE_NAME, cardType)));
binInfo.getBrand().ifPresent(brand
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_BRAND_NAME, MODULE_NAME, brand)));
binInfo.getBankName().ifPresent(bankName
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_BANK_NAME, MODULE_NAME, bankName)));
binInfo.getBankPhoneNumber().ifPresent(phoneNumber
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER, MODULE_NAME, phoneNumber)));
binInfo.getBankURL().ifPresent(url
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL, MODULE_NAME, url)));
binInfo.getCountry().ifPresent(country
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COUNTRY, MODULE_NAME, country)));
binInfo.getBankCity().ifPresent(city
-> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_CITY, MODULE_NAME, city)));
}
/*
* If the hit is from unused or unallocated space, record the Solr
* document id to support showing just the chunk that contained the
* hit.
*/
if (content instanceof AbstractFile) {
AbstractFile file = (AbstractFile) content;
if (file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS
|| file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) {
attributes.add(new BlackboardAttribute(KEYWORD_SEARCH_DOCUMENT_ID, MODULE_NAME, hit.getSolrDocumentId()));
}
}
if (StringUtils.isNotBlank(listName)) {
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_SET_NAME, MODULE_NAME, listName));
}
if (snippet != null) {
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD_PREVIEW, MODULE_NAME, snippet));
}
hit.getArtifactID().ifPresent(
artifactID -> attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT, MODULE_NAME, artifactID))
);
// TermsComponentQuery is now being used exclusively for substring searches.
attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_TYPE, MODULE_NAME, KeywordSearch.QueryType.SUBSTRING.ordinal()));
/*
* Create an account.
*/
try {
AccountInstance ccAccountInstance = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().createAccountInstance(Account.Type.CREDIT_CARD, ccnAttribute.getValueString() , MODULE_NAME, content);
ccAccountInstance.addAttributes(attributes);
//newArtifact = Case.getCurrentCase().getSleuthkitCase().getBlackboardArtifact(ccAccountInstance.getArtifactId());
} catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, "Error creating CCN account instance", ex); //NON-NLS
}
}
/** /**
* Parses the track 2 data from the snippet for a credit card account number * Parses the track 2 data from the snippet for a credit card account number
* hit and turns them into artifact attributes. * hit and turns them into artifact attributes.

View File

@ -36,6 +36,7 @@ import java.util.logging.Logger;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
import javax.swing.JDialog; import javax.swing.JDialog;
import javax.swing.text.JTextComponent; import javax.swing.text.JTextComponent;
import javax.swing.tree.TreePath;
import org.netbeans.jellytools.MainWindowOperator; import org.netbeans.jellytools.MainWindowOperator;
import org.netbeans.jellytools.NbDialogOperator; import org.netbeans.jellytools.NbDialogOperator;
import org.netbeans.jellytools.WizardOperator; import org.netbeans.jellytools.WizardOperator;
@ -53,6 +54,8 @@ import org.netbeans.jemmy.operators.JTabbedPaneOperator;
import org.netbeans.jemmy.operators.JTableOperator; import org.netbeans.jemmy.operators.JTableOperator;
import org.netbeans.jemmy.operators.JTextFieldOperator; import org.netbeans.jemmy.operators.JTextFieldOperator;
import org.netbeans.jemmy.operators.JToggleButtonOperator; import org.netbeans.jemmy.operators.JToggleButtonOperator;
import org.netbeans.jemmy.operators.JTreeOperator;
import org.netbeans.jemmy.operators.JTreeOperator.NoSuchPathException;
import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.core.UserPreferencesException; import org.sleuthkit.autopsy.core.UserPreferencesException;
import org.sleuthkit.autopsy.events.MessageServiceConnectionInfo; import org.sleuthkit.autopsy.events.MessageServiceConnectionInfo;
@ -290,6 +293,16 @@ public class AutopsyTestCases {
} }
public void testExpandDataSourcesTree() {
logger.info("Data Sources Node");
MainWindowOperator mwo = MainWindowOperator.getDefault();
JTreeOperator jto = new JTreeOperator(mwo, "Data Sources");
String [] nodeNames = {"Data Sources"};
TreePath tp = jto.findPath(nodeNames);
expandNodes(jto, tp);
screenshot("Data Sources Tree");
}
public void testGenerateReportToolbar() { public void testGenerateReportToolbar() {
logger.info("Generate Report Toolbars"); logger.info("Generate Report Toolbars");
MainWindowOperator mwo = MainWindowOperator.getDefault(); MainWindowOperator mwo = MainWindowOperator.getDefault();
@ -380,4 +393,15 @@ public class AutopsyTestCases {
logger.log(Level.SEVERE, "Error saving messaging service connection info", ex); //NON-NLS logger.log(Level.SEVERE, "Error saving messaging service connection info", ex); //NON-NLS
} }
} }
private void expandNodes (JTreeOperator jto, TreePath tp) {
try {
jto.expandPath(tp);
for (TreePath t : jto.getChildPaths(tp)) {
expandNodes(jto, t);
}
} catch (NoSuchPathException ne) {
logger.log(Level.SEVERE, "Error expanding tree path", ne);
}
}
} }

View File

@ -69,6 +69,7 @@ public class RegressionTest extends TestCase {
"testConfigureSearch", "testConfigureSearch",
"testAddSourceWizard1", "testAddSourceWizard1",
"testIngest", "testIngest",
"testExpandDataSourcesTree", //After do ingest, before generate report, we expand Data Sources node
"testGenerateReportToolbar", "testGenerateReportToolbar",
"testGenerateReportButton"); "testGenerateReportButton");
} }
@ -83,6 +84,7 @@ public class RegressionTest extends TestCase {
"testConfigureSearch", "testConfigureSearch",
"testAddSourceWizard1", "testAddSourceWizard1",
"testIngest", "testIngest",
"testExpandDataSourcesTree",
"testGenerateReportToolbar", "testGenerateReportToolbar",
"testGenerateReportButton"); "testGenerateReportButton");
} }
@ -147,6 +149,9 @@ public class RegressionTest extends TestCase {
autopsyTests.testIngest(); autopsyTests.testIngest();
} }
public void testExpandDataSourcesTree() {
autopsyTests.testExpandDataSourcesTree();
}
public void testGenerateReportToolbar() { public void testGenerateReportToolbar() {
autopsyTests.testGenerateReportToolbar(); autopsyTests.testGenerateReportToolbar();
} }

View File

@ -6,8 +6,8 @@ app.name=${branding.token}
### if left unset, version will default to today's date ### if left unset, version will default to today's date
app.version=4.5.0 app.version=4.5.0
### build.type must be one of: DEVELOPMENT, RELEASE ### build.type must be one of: DEVELOPMENT, RELEASE
build.type=RELEASE #build.type=RELEASE
#build.type=DEVELOPMENT build.type=DEVELOPMENT
project.org.netbeans.progress=org-netbeans-api-progress project.org.netbeans.progress=org-netbeans-api-progress
project.org.sleuthkit.autopsy.experimental=Experimental project.org.sleuthkit.autopsy.experimental=Experimental