Merge branch 'develop' of https://github.com/sleuthkit/autopsy into 1205-download-source

This commit is contained in:
Raman 2019-03-04 11:04:20 -05:00
commit 90177a7fb6
17 changed files with 1075 additions and 418 deletions

View File

@ -6,3 +6,4 @@ DataContentViewerOtherCases.showCommonalityMenuItem.text=Show Frequency
DataContentViewerOtherCases.earliestCaseDate.text=Earliest Case Date
DataContentViewerOtherCases.earliestCaseLabel.toolTipText=
DataContentViewerOtherCases.earliestCaseLabel.text=Central Repository Starting Date:
DataContentViewerOtherCases.foundInLabel.text=

View File

@ -73,7 +73,7 @@
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="otherCasesPanel" pref="58" max="32767" attributes="0"/>
<Component id="otherCasesPanel" pref="53" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
</Layout>
@ -96,10 +96,10 @@
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="483" max="32767" attributes="0"/>
<EmptySpace min="0" pref="61" max="32767" attributes="0"/>
<Group type="103" rootIndex="1" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="tableContainerPanel" pref="58" max="32767" attributes="0"/>
<Component id="tableContainerPanel" pref="53" max="32767" attributes="0"/>
<EmptySpace min="-2" pref="0" max="-2" attributes="0"/>
</Group>
</Group>
@ -117,31 +117,28 @@
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<Component id="tableStatusPanel" pref="1282" max="32767" attributes="0"/>
<EmptySpace min="-2" pref="218" max="-2" attributes="0"/>
</Group>
<Component id="tableScrollPane" alignment="0" max="32767" attributes="0"/>
<Component id="tableScrollPane" alignment="0" pref="1508" max="32767" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Component id="earliestCaseLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="earliestCaseDate" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
<EmptySpace min="-2" pref="66" max="-2" attributes="0"/>
<Component id="foundInLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="1157" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<Component id="tableScrollPane" pref="27" max="32767" attributes="0"/>
<EmptySpace min="-2" pref="2" max="-2" attributes="0"/>
<Component id="tableScrollPane" pref="71" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="earliestCaseLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="earliestCaseDate" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="foundInLabel" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
<Component id="tableStatusPanel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="6" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@ -198,26 +195,13 @@
</Property>
</Properties>
</Component>
<Container class="javax.swing.JPanel" name="tableStatusPanel">
<Component class="javax.swing.JLabel" name="foundInLabel">
<Properties>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[1500, 16]"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/contentviewer/Bundle.properties" key="DataContentViewerOtherCases.foundInLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="16" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
</Layout>
</Container>
</Component>
</SubComponents>
</Container>
</SubComponents>

View File

@ -1,7 +1,7 @@
/*
* Central Repository
*
* Copyright 2015-2018 Basis Technology Corp.
* Copyright 2015-2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -33,10 +33,12 @@ import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.logging.Level;
import org.sleuthkit.autopsy.coreutils.Logger;
import javax.swing.JFileChooser;
@ -46,9 +48,13 @@ import static javax.swing.JOptionPane.DEFAULT_OPTION;
import static javax.swing.JOptionPane.PLAIN_MESSAGE;
import static javax.swing.JOptionPane.ERROR_MESSAGE;
import javax.swing.JPanel;
import javax.swing.RowSorter;
import javax.swing.SortOrder;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;
import org.joda.time.DateTimeZone;
import org.joda.time.LocalDateTime;
import org.openide.nodes.Node;
@ -138,7 +144,20 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
// Set background of every nth row as light grey.
TableCellRenderer renderer = new DataContentViewerOtherCasesTableCellRenderer();
otherCasesTable.setDefaultRenderer(Object.class, renderer);
// Configure column sorting.
TableRowSorter<TableModel> sorter = new TableRowSorter<>(otherCasesTable.getModel());
otherCasesTable.setRowSorter(sorter);
List<RowSorter.SortKey> sortKeys = new ArrayList<>();
int caseNameColumnIndex = DataContentViewerOtherCasesTableModel.TableColumns.CASE_NAME.ordinal();
sortKeys.add(new RowSorter.SortKey(caseNameColumnIndex, SortOrder.ASCENDING));
int dataSourceColumnIndex = DataContentViewerOtherCasesTableModel.TableColumns.DATA_SOURCE.ordinal();
sortKeys.add(new RowSorter.SortKey(dataSourceColumnIndex, SortOrder.ASCENDING));
sorter.setSortKeys(sortKeys);
sorter.sort();
}
@Messages({"DataContentViewerOtherCases.correlatedArtifacts.isEmpty=There are no files or artifacts to correlate.",
@ -306,6 +325,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
tableModel.clearTable();
correlationAttributes.clear();
earliestCaseDate.setText(Bundle.DataContentViewerOtherCases_earliestCaseNotAvailable());
foundInLabel.setText("");
}
@Override
@ -337,6 +357,40 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
public int isPreferred(Node node) {
return 1;
}
/**
* Set the number of unique cases and data sources.
*/
@Messages({
"DataContentViewerOtherCases.foundIn.text=Found %d instances in %d cases and %d data sources."
})
private void setOccurrenceCounts() {
DataContentViewerOtherCasesTableModel model = (DataContentViewerOtherCasesTableModel) otherCasesTable.getModel();
int caseColumnIndex = DataContentViewerOtherCasesTableModel.TableColumns.CASE_NAME.ordinal();
int deviceColumnIndex = DataContentViewerOtherCasesTableModel.TableColumns.DEVICE.ordinal();
/*
* We need a unique set of data sources. We rely on device ID for this.
* To mitigate edge cases where a device ID could be duplicated in the
* same case (e.g. "report.xml"), we put the device ID and case name in
* a key-value pair.
*
* Note: Relying on the case name isn't a fool-proof way of determining
* a case to be unique. We should improve this in the future.
*/
Set<String> cases = new HashSet<>();
Map<String, String> devices = new HashMap();
for (int i=0; i < model.getRowCount(); i++) {
String caseName = (String) model.getValueAt(i, caseColumnIndex);
String deviceId = (String) model.getValueAt(i, deviceColumnIndex);
cases.add(caseName);
devices.put(deviceId, caseName);
}
foundInLabel.setText(String.format(Bundle.DataContentViewerOtherCases_foundIn_text(), model.getRowCount(), cases.size(), devices.size()));
}
/**
* Get the associated BlackboardArtifact from a node, if it exists.
@ -720,7 +774,9 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
} else {
setColumnWidths();
}
setEarliestCaseDate();
setOccurrenceCounts();
}
/**
@ -772,7 +828,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
otherCasesTable = new javax.swing.JTable();
earliestCaseLabel = new javax.swing.JLabel();
earliestCaseDate = new javax.swing.JLabel();
tableStatusPanel = new javax.swing.JPanel();
foundInLabel = new javax.swing.JLabel();
rightClickPopupMenu.addPopupMenuListener(new javax.swing.event.PopupMenuListener() {
public void popupMenuCanceled(javax.swing.event.PopupMenuEvent evt) {
@ -818,44 +874,31 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
org.openide.awt.Mnemonics.setLocalizedText(earliestCaseDate, org.openide.util.NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.earliestCaseDate.text")); // NOI18N
tableStatusPanel.setPreferredSize(new java.awt.Dimension(1500, 16));
javax.swing.GroupLayout tableStatusPanelLayout = new javax.swing.GroupLayout(tableStatusPanel);
tableStatusPanel.setLayout(tableStatusPanelLayout);
tableStatusPanelLayout.setHorizontalGroup(
tableStatusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 0, Short.MAX_VALUE)
);
tableStatusPanelLayout.setVerticalGroup(
tableStatusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 16, Short.MAX_VALUE)
);
org.openide.awt.Mnemonics.setLocalizedText(foundInLabel, org.openide.util.NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.foundInLabel.text")); // NOI18N
javax.swing.GroupLayout tableContainerPanelLayout = new javax.swing.GroupLayout(tableContainerPanel);
tableContainerPanel.setLayout(tableContainerPanelLayout);
tableContainerPanelLayout.setHorizontalGroup(
tableContainerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, tableContainerPanelLayout.createSequentialGroup()
.addComponent(tableStatusPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 1282, Short.MAX_VALUE)
.addGap(218, 218, 218))
.addComponent(tableScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(tableScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 1508, Short.MAX_VALUE)
.addGroup(tableContainerPanelLayout.createSequentialGroup()
.addComponent(earliestCaseLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(earliestCaseDate)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addGap(66, 66, 66)
.addComponent(foundInLabel)
.addGap(0, 1157, Short.MAX_VALUE))
);
tableContainerPanelLayout.setVerticalGroup(
tableContainerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, tableContainerPanelLayout.createSequentialGroup()
.addComponent(tableScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 27, Short.MAX_VALUE)
.addGap(2, 2, 2)
.addComponent(tableScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 71, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(tableContainerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(earliestCaseLabel)
.addComponent(earliestCaseDate))
.addGap(0, 0, 0)
.addComponent(tableStatusPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(0, 0, 0))
.addComponent(earliestCaseDate)
.addComponent(foundInLabel))
.addGap(6, 6, 6))
);
javax.swing.GroupLayout otherCasesPanelLayout = new javax.swing.GroupLayout(otherCasesPanel);
@ -868,10 +911,10 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
);
otherCasesPanelLayout.setVerticalGroup(
otherCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 483, Short.MAX_VALUE)
.addGap(0, 61, Short.MAX_VALUE)
.addGroup(otherCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(otherCasesPanelLayout.createSequentialGroup()
.addComponent(tableContainerPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 59, Short.MAX_VALUE)
.addComponent(tableContainerPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 53, Short.MAX_VALUE)
.addGap(0, 0, 0)))
);
@ -883,7 +926,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(otherCasesPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 59, Short.MAX_VALUE)
.addComponent(otherCasesPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 53, Short.MAX_VALUE)
);
}// </editor-fold>//GEN-END:initComponents
@ -907,6 +950,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
private javax.swing.JLabel earliestCaseDate;
private javax.swing.JLabel earliestCaseLabel;
private javax.swing.JMenuItem exportToCSVMenuItem;
private javax.swing.JLabel foundInLabel;
private javax.swing.JPanel otherCasesPanel;
private javax.swing.JTable otherCasesTable;
private javax.swing.JPopupMenu rightClickPopupMenu;
@ -915,7 +959,6 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
private javax.swing.JMenuItem showCommonalityMenuItem;
private javax.swing.JPanel tableContainerPanel;
private javax.swing.JScrollPane tableScrollPane;
private javax.swing.JPanel tableStatusPanel;
// End of variables declaration//GEN-END:variables
/**

View File

@ -83,3 +83,4 @@ MediaViewImagePanel.zoomResetButton.text=Reset
MediaViewImagePanel.zoomTextField.text=
MediaViewImagePanel.rotationTextField.text=
MediaViewImagePanel.rotateLeftButton.toolTipText=
HtmlPanel.showImagesToggleButton.text=Show Images

View File

@ -11,6 +11,7 @@
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,1,-112"/>
</AuxValues>
<LayoutCode>
<CodeStatement>

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2018 Basis Technology Corp.
* Copyright 2018-2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -49,7 +49,8 @@ public class FileViewer extends javax.swing.JPanel implements DataContentViewer
private final FileTypeViewer[] KNOWN_VIEWERS = new FileTypeViewer[]{
new SQLiteViewer(),
new PListViewer(),
new MediaFileViewer()
new MediaFileViewer(),
new HtmlViewer()
};
private FileTypeViewer lastViewer;

View File

@ -0,0 +1,65 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<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">
<Component id="htmlScrollPane" pref="300" max="32767" attributes="0"/>
<Group type="102" attributes="0">
<Component id="showImagesToggleButton" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="showImagesToggleButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="htmlScrollPane" pref="71" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JScrollPane" name="htmlScrollPane">
<Properties>
<Property name="verticalScrollBarPolicy" type="int" value="22"/>
</Properties>
<AuxValues>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JTextPane" name="htmlbodyTextPane">
<Properties>
<Property name="editable" type="boolean" value="false"/>
</Properties>
</Component>
</SubComponents>
</Container>
<Component class="javax.swing.JToggleButton" name="showImagesToggleButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="HtmlPanel.showImagesToggleButton.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="showImagesToggleButtonActionPerformed"/>
</Events>
</Component>
</SubComponents>
</Form>

View File

@ -0,0 +1,165 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019 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.contentviewers;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.openide.util.NbBundle.Messages;
/**
* A file content viewer for HTML files.
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
final class HtmlPanel extends javax.swing.JPanel {
private static final long serialVersionUID = 1L;
private String htmlText;
/**
* Creates new form HtmlViewerPanel
*/
HtmlPanel() {
initComponents();
Utilities.configureTextPaneAsHtml(htmlbodyTextPane);
}
/**
* Set the text pane's HTML text and refresh the view to display it.
*
* @param htmlText The HTML text to be applied to the text pane.
*/
void setHtmlText(String htmlText) {
this.htmlText = htmlText;
refresh();
}
/**
* Clear the HTML in the text pane and disable the show/hide button.
*/
void reset() {
htmlbodyTextPane.setText("");
showImagesToggleButton.setEnabled(false);
}
/**
* Guarantee the HTML text has 'html' and 'body' tags.
*
* @param htmlText The HTML text
*
* @return The HTML text with the 'html' and 'body' tags applied.
*/
private String wrapInHtmlBody(String htmlText) {
return "<html><body>" + htmlText + "</body></html>";
}
/**
* Cleans out input HTML string
*
* @param htmlInString The HTML string to cleanse
*
* @return The cleansed HTML String
*/
private String cleanseHTML(String htmlInString) {
Document doc = Jsoup.parse(htmlInString);
// Update all 'img' tags.
doc.select("img[src]").forEach(img -> img.attr("src", ""));
return doc.html();
}
/**
* Refresh the panel to reflect the current show/hide images setting.
*/
@Messages({
"HtmlPanel_showImagesToggleButton_show=Show Images",
"HtmlPanel_showImagesToggleButton_hide=Hide Images"
})
private void refresh() {
if (false == htmlText.isEmpty()) {
if (showImagesToggleButton.isSelected()) {
showImagesToggleButton.setText(Bundle.HtmlPanel_showImagesToggleButton_hide());
this.htmlbodyTextPane.setText(wrapInHtmlBody(htmlText));
} else {
showImagesToggleButton.setText(Bundle.HtmlPanel_showImagesToggleButton_show());
this.htmlbodyTextPane.setText(wrapInHtmlBody(cleanseHTML(htmlText)));
}
htmlbodyTextPane.setCaretPosition(0);
showImagesToggleButton.setEnabled(true);
}
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
htmlScrollPane = new javax.swing.JScrollPane();
htmlbodyTextPane = new javax.swing.JTextPane();
showImagesToggleButton = new javax.swing.JToggleButton();
htmlScrollPane.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
htmlbodyTextPane.setEditable(false);
htmlScrollPane.setViewportView(htmlbodyTextPane);
org.openide.awt.Mnemonics.setLocalizedText(showImagesToggleButton, org.openide.util.NbBundle.getMessage(HtmlPanel.class, "HtmlPanel.showImagesToggleButton.text")); // NOI18N
showImagesToggleButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
showImagesToggleButtonActionPerformed(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(htmlScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE)
.addGroup(layout.createSequentialGroup()
.addComponent(showImagesToggleButton)
.addGap(0, 0, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(showImagesToggleButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(htmlScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 71, Short.MAX_VALUE))
);
}// </editor-fold>//GEN-END:initComponents
private void showImagesToggleButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showImagesToggleButtonActionPerformed
refresh();
}//GEN-LAST:event_showImagesToggleButtonActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JScrollPane htmlScrollPane;
private javax.swing.JTextPane htmlbodyTextPane;
private javax.swing.JToggleButton showImagesToggleButton;
// End of variables declaration//GEN-END:variables
}

View File

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<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" alignment="0" attributes="0">
<EmptySpace min="-2" max="-2" attributes="0"/>
<Component id="htmlPanel" max="32767" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" max="-2" attributes="0"/>
<Component id="htmlPanel" max="32767" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="org.sleuthkit.autopsy.contentviewers.HtmlPanel" name="htmlPanel">
</Component>
</SubComponents>
</Form>

View File

@ -0,0 +1,128 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019 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.contentviewers;
import java.awt.Component;
import java.awt.Cursor;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import org.openide.windows.WindowManager;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.TskCoreException;
/**
* A file content viewer for HTML files.
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
final class HtmlViewer extends javax.swing.JPanel implements FileTypeViewer {
private static final long serialVersionUID = 1L;
private static final Logger logger = Logger.getLogger(HtmlViewer.class.getName());
private static final String[] SUPPORTED_MIMETYPES = new String[]{
"text/html",
"application/xhtml+xml"
};
/**
* Creates new form HtmlViewerPanel
*/
HtmlViewer() {
initComponents();
}
/**
* Retrieve the HTML text content from the supplied file.
*
* @param abstractFile The file to read.
*
* @return The text content of the file.
*/
private String getHtmlText(AbstractFile abstractFile) {
try {
int fileSize = (int) abstractFile.getSize();
byte[] buffer = new byte[fileSize];
abstractFile.read(buffer, 0, fileSize);
return new String(buffer);
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, String.format("Unable to read from file '%s' (id=%d).",
abstractFile.getName(), abstractFile.getId()), ex);
}
return null;
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
htmlPanel = new org.sleuthkit.autopsy.contentviewers.HtmlPanel();
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(htmlPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(htmlPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addContainerGap())
);
}// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables
private org.sleuthkit.autopsy.contentviewers.HtmlPanel htmlPanel;
// End of variables declaration//GEN-END:variables
@Override
public List<String> getSupportedMIMETypes() {
return Arrays.asList(SUPPORTED_MIMETYPES);
}
@Override
public void setFile(AbstractFile file) {
WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
htmlPanel.setHtmlText(getHtmlText(file));
WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
@Override
public Component getComponent() {
return this;
}
@Override
public void resetComponent() {
htmlPanel.reset();
}
}

View File

@ -126,7 +126,6 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
scene.getStylesheets().add(MediaViewImagePanel.class.getResource("MediaViewImagePanel.css").toExternalForm()); //NOI18N
fxPanel.setScene(scene);
//bind size of image to that of scene, while keeping proportions
fxImageView.setSmooth(true);
fxImageView.setCache(true);
@ -142,11 +141,13 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
}
/**
* clear the displayed image
* Clear the displayed image
*/
public void reset() {
Platform.runLater(() -> {
fxImageView.setViewport(new Rectangle2D(0, 0, 0, 0));
fxImageView.setImage(null);
scrollPane.setContent(null);
scrollPane.setContent(fxImageView);
});

View File

@ -274,50 +274,17 @@
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="htmlScrollPane" alignment="0" max="32767" attributes="0"/>
<Group type="102" alignment="1" attributes="0">
<EmptySpace pref="533" max="32767" attributes="0"/>
<Component id="showImagesToggleButton" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="3" max="-2" attributes="0"/>
</Group>
<Component id="htmlPanel" alignment="0" pref="647" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="showImagesToggleButton" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Component id="htmlScrollPane" pref="333" max="32767" attributes="0"/>
<EmptySpace min="-2" pref="0" max="-2" attributes="0"/>
</Group>
<Component id="htmlPanel" alignment="0" pref="362" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JScrollPane" name="htmlScrollPane">
<Properties>
<Property name="verticalScrollBarPolicy" type="int" value="22"/>
</Properties>
<AuxValues>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JTextPane" name="htmlbodyTextPane">
<Properties>
<Property name="editable" type="boolean" value="false"/>
</Properties>
</Component>
</SubComponents>
</Container>
<Component class="javax.swing.JToggleButton" name="showImagesToggleButton">
<Properties>
<Property name="text" type="java.lang.String" value="Show Images"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="showImagesToggleButtonActionPerformed"/>
</Events>
<Component class="org.sleuthkit.autopsy.contentviewers.HtmlPanel" name="htmlPanel">
</Component>
</SubComponents>
</Container>

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2017-2018 Basis Technology Corp.
* Copyright 2017-2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -106,9 +106,12 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont
attachmentsScrollPane.setViewportView(drp);
msgbodyTabbedPane.setEnabledAt(ATTM_TAB_INDEX, true);
textAreas = Arrays.asList(headersTextArea, textbodyTextArea, htmlbodyTextPane, rtfbodyTextPane);
/*
* HTML tab uses the HtmlPanel instead of an internal text pane, so we
* use 'null' for that index.
*/
textAreas = Arrays.asList(headersTextArea, textbodyTextArea, null, rtfbodyTextPane);
Utilities.configureTextPaneAsHtml(htmlbodyTextPane);
Utilities.configureTextPaneAsRtf(rtfbodyTextPane);
resetComponent();
@ -150,9 +153,7 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont
textbodyScrollPane = new javax.swing.JScrollPane();
textbodyTextArea = new javax.swing.JTextArea();
htmlPane = new javax.swing.JPanel();
htmlScrollPane = new javax.swing.JScrollPane();
htmlbodyTextPane = new javax.swing.JTextPane();
showImagesToggleButton = new javax.swing.JToggleButton();
htmlPanel = new org.sleuthkit.autopsy.contentviewers.HtmlPanel();
rtfbodyScrollPane = new javax.swing.JScrollPane();
rtfbodyTextPane = new javax.swing.JTextPane();
attachmentsPanel = new javax.swing.JPanel();
@ -265,35 +266,15 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont
msgbodyTabbedPane.addTab(org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.textbodyScrollPane.TabConstraints.tabTitle"), textbodyScrollPane); // NOI18N
htmlScrollPane.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
htmlbodyTextPane.setEditable(false);
htmlScrollPane.setViewportView(htmlbodyTextPane);
org.openide.awt.Mnemonics.setLocalizedText(showImagesToggleButton, "Show Images");
showImagesToggleButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
showImagesToggleButtonActionPerformed(evt);
}
});
javax.swing.GroupLayout htmlPaneLayout = new javax.swing.GroupLayout(htmlPane);
htmlPane.setLayout(htmlPaneLayout);
htmlPaneLayout.setHorizontalGroup(
htmlPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(htmlScrollPane)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, htmlPaneLayout.createSequentialGroup()
.addContainerGap(533, Short.MAX_VALUE)
.addComponent(showImagesToggleButton)
.addGap(3, 3, 3))
.addComponent(htmlPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 647, Short.MAX_VALUE)
);
htmlPaneLayout.setVerticalGroup(
htmlPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(htmlPaneLayout.createSequentialGroup()
.addComponent(showImagesToggleButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(htmlScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 333, Short.MAX_VALUE)
.addGap(0, 0, 0))
.addComponent(htmlPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 362, Short.MAX_VALUE)
);
msgbodyTabbedPane.addTab(org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.htmlPane.TabConstraints.tabTitle"), htmlPane); // NOI18N
@ -358,26 +339,6 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont
);
}// </editor-fold>//GEN-END:initComponents
@NbBundle.Messages({
"MessageContentViewer.showImagesToggleButton.hide.text=Hide Images",
"MessageContentViewer.showImagesToggleButton.text=Show Images"})
private void showImagesToggleButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showImagesToggleButtonActionPerformed
try {
String htmlText = getAttributeValueSafe(artifact, TSK_EMAIL_CONTENT_HTML);
if (false == htmlText.isEmpty()) {
if (showImagesToggleButton.isSelected()) {
showImagesToggleButton.setText(Bundle.MessageContentViewer_showImagesToggleButton_hide_text());
this.htmlbodyTextPane.setText(wrapInHtmlBody(htmlText));
} else {
showImagesToggleButton.setText(Bundle.MessageContentViewer_showImagesToggleButton_text());
this.htmlbodyTextPane.setText(wrapInHtmlBody(cleanseHTML(htmlText)));
}
}
} catch (TskCoreException ex) {
LOGGER.log(Level.WARNING, "Failed to get attributes for email message.", ex); //NON-NLS
}
}//GEN-LAST:event_showImagesToggleButtonActionPerformed
private void viewInNewWindowButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_viewInNewWindowButtonActionPerformed
new NewWindowViewAction("View in new window", drpExplorerManager.getSelectedNodes()[0]).actionPerformed(evt);
}//GEN-LAST:event_viewInNewWindowButtonActionPerformed
@ -396,12 +357,10 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont
private javax.swing.JScrollPane headersScrollPane;
private javax.swing.JTextArea headersTextArea;
private javax.swing.JPanel htmlPane;
private javax.swing.JScrollPane htmlScrollPane;
private javax.swing.JTextPane htmlbodyTextPane;
private org.sleuthkit.autopsy.contentviewers.HtmlPanel htmlPanel;
private javax.swing.JTabbedPane msgbodyTabbedPane;
private javax.swing.JScrollPane rtfbodyScrollPane;
private javax.swing.JTextPane rtfbodyTextPane;
private javax.swing.JToggleButton showImagesToggleButton;
private javax.swing.JLabel subjectLabel;
private javax.swing.JLabel subjectText;
private javax.swing.JScrollPane textbodyScrollPane;
@ -505,9 +464,8 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont
headersTextArea.setText("");
rtfbodyTextPane.setText("");
htmlbodyTextPane.setText("");
htmlPanel.reset();
textbodyTextArea.setText("");
showImagesToggleButton.setEnabled(false);
msgbodyTabbedPane.setEnabled(false);
}
@ -567,12 +525,15 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont
String attributeText = getAttributeValueSafe(artifact, type);
if (index == HTML_TAB_INDEX && StringUtils.isNotBlank(attributeText)) {
//special case for HTML, we need to 'cleanse' it
attributeText = wrapInHtmlBody(cleanseHTML(attributeText));
htmlPanel.setHtmlText(attributeText);
} else {
JTextComponent textComponent = textAreas.get(index);
if (textComponent != null) {
textComponent.setText(attributeText);
textComponent.setCaretPosition(0); //make sure we start at the top
}
}
JTextComponent textComponent = textAreas.get(index);
textComponent.setText(attributeText);
textComponent.setCaretPosition(0); //make sure we start at the top
final boolean hasText = attributeText.length() > 0;
msgbodyTabbedPane.setEnabledAt(index, hasText);
@ -613,10 +574,6 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont
directionText.setEnabled(false);
ccLabel.setEnabled(true);
showImagesToggleButton.setEnabled(true);
showImagesToggleButton.setText("Show Images");
showImagesToggleButton.setSelected(false);
try {
this.fromText.setText(getAttributeValueSafe(artifact, TSK_EMAIL_FROM));
this.fromText.setToolTipText(getAttributeValueSafe(artifact, TSK_EMAIL_FROM));

View File

@ -302,8 +302,9 @@ class MSOfficeEmbeddedContentExtractor {
}
List<ExtractedFile> listOfExtractedImages = new ArrayList<>();
byte[] data = null;
int pictureNumber = 0; //added to ensure uniqueness in cases where suggestFullFileName returns duplicates
for (Picture picture : listOfAllPictures) {
String fileName = picture.suggestFullFileName();
String fileName = UNKNOWN_IMAGE_NAME_PREFIX +pictureNumber +"."+ picture.suggestFileExtension();
try {
data = picture.getContent();
} catch (Exception ex) {
@ -312,6 +313,7 @@ class MSOfficeEmbeddedContentExtractor {
writeExtractedImage(Paths.get(outputFolderPath, fileName).toString(), data);
// TODO Extract more info from the Picture viz ctime, crtime, atime, mtime
listOfExtractedImages.add(new ExtractedFile(fileName, getFileRelativePath(fileName), picture.getSize()));
pictureNumber++;
}
return listOfExtractedImages;

View File

@ -38,6 +38,9 @@ import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import org.sleuthkit.autopsy.datamodel.ContentUtils;
import org.sleuthkit.autopsy.datamodel.utils.FileTypeUtils.FileTypeCategory;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardArtifactTag;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.ContentTag;
import org.sleuthkit.datamodel.FileSystem;
@ -47,6 +50,7 @@ import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.SleuthkitCase.CaseDbTransaction;
import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskDataException;
import org.sleuthkit.datamodel.TskData;
import org.sleuthkit.datamodel.Volume;
import org.sleuthkit.datamodel.VolumeSystem;
@ -66,7 +70,7 @@ public class CreatePortableCaseModule implements GeneralReportModule {
FileTypeCategory.EXECUTABLE, FileTypeCategory.IMAGE, FileTypeCategory.VIDEO);
private Case currentCase = null;
private SleuthkitCase skCase = null;
private SleuthkitCase portableSkCase = null;
private File caseFolder = null;
private File copiedFilesFolder = null;
@ -78,6 +82,15 @@ public class CreatePortableCaseModule implements GeneralReportModule {
// Maps old TagName to new TagName
private final Map<TagName, TagName> oldTagNameToNewTagName = new HashMap<>();
// Map of old artifact type ID to new artifact type ID. There will only be changes if custom artifact types are present.
private final Map<Integer, Integer> oldArtTypeIdToNewArtTypeId = new HashMap<>();
// Map of old attribute type ID to new attribute type ID. There will only be changes if custom attr types are present.
private final Map<Integer, BlackboardAttribute.Type> oldAttrTypeIdToNewAttrType = new HashMap<>();
// Map of old artifact ID to new artifact
private final Map<Long, BlackboardArtifact> oldArtifactIdToNewArtifact = new HashMap<>();
public CreatePortableCaseModule() {
// Nothing to do here
@ -132,6 +145,8 @@ public class CreatePortableCaseModule implements GeneralReportModule {
"CreatePortableCaseModule.generateReport.copyingTags=Copying tags...",
"# {0} - tag name",
"CreatePortableCaseModule.generateReport.copyingFiles=Copying files tagged as {0}...",
"# {0} - tag name",
"CreatePortableCaseModule.generateReport.copyingArtifacts=Copying artifacts tagged as {0}...",
"# {0} - output folder",
"CreatePortableCaseModule.generateReport.outputDirDoesNotExist=Output folder {0} does not exist",
"# {0} - output folder",
@ -139,7 +154,10 @@ public class CreatePortableCaseModule implements GeneralReportModule {
"CreatePortableCaseModule.generateReport.noTagsSelected=No tags selected for export.",
"CreatePortableCaseModule.generateReport.caseClosed=Current case has been closed",
"CreatePortableCaseModule.generateReport.errorCopyingTags=Error copying tags",
"CreatePortableCaseModule.generateReport.errorCopyingFiles=Error copying tagged files"
"CreatePortableCaseModule.generateReport.errorCopyingFiles=Error copying tagged files",
"CreatePortableCaseModule.generateReport.errorCopyingArtifacts=Error copying tagged artifacts",
"# {0} - attribute type name",
"CreatePortableCaseModule.generateReport.errorLookingUpAttrType=Error looking up attribute type {0}",
})
@Override
public void generateReport(String reportPath, ReportProgressPanel progressPanel) {
@ -182,10 +200,10 @@ public class CreatePortableCaseModule implements GeneralReportModule {
// Create the case.
// skCase and caseFolder will be set here.
// portableSkCase and caseFolder will be set here.
progressPanel.updateStatusLabel(Bundle.CreatePortableCaseModule_generateReport_creatingCase());
createCase(outputDir, progressPanel);
if (skCase == null) {
if (portableSkCase == null) {
// The error has already been handled
return;
}
@ -200,7 +218,7 @@ public class CreatePortableCaseModule implements GeneralReportModule {
progressPanel.updateStatusLabel(Bundle.CreatePortableCaseModule_generateReport_copyingTags());
try {
for(TagName tagName:tagNames) {
TagName newTagName = skCase.addOrUpdateTagName(tagName.getDisplayName(), tagName.getDescription(), tagName.getColor(), tagName.getKnownStatus());
TagName newTagName = portableSkCase.addOrUpdateTagName(tagName.getDisplayName(), tagName.getDescription(), tagName.getColor(), tagName.getKnownStatus());
oldTagNameToNewTagName.put(tagName, newTagName);
}
} catch (TskCoreException ex) {
@ -222,6 +240,35 @@ public class CreatePortableCaseModule implements GeneralReportModule {
handleError("Error copying tagged files", Bundle.CreatePortableCaseModule_generateReport_errorCopyingFiles(), ex, progressPanel);
return;
}
// Set up tracking to support any custom artifact or attribute types
for (BlackboardArtifact.ARTIFACT_TYPE type:BlackboardArtifact.ARTIFACT_TYPE.values()) {
oldArtTypeIdToNewArtTypeId.put(type.getTypeID(), type.getTypeID());
}
for (BlackboardAttribute.ATTRIBUTE_TYPE type:BlackboardAttribute.ATTRIBUTE_TYPE.values()) {
try {
oldAttrTypeIdToNewAttrType.put(type.getTypeID(), portableSkCase.getAttributeType(type.getLabel()));
} catch (TskCoreException ex) {
handleError("Error looking up attribute name " + type.getLabel(),
Bundle.CreatePortableCaseModule_generateReport_errorLookingUpAttrType(type.getLabel()),
ex, progressPanel);
}
}
// Copy the tagged artifacts and associated files
try {
for(TagName tagName:tagNames) {
// Check for cancellation
if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) {
return;
}
progressPanel.updateStatusLabel(Bundle.CreatePortableCaseModule_generateReport_copyingArtifacts(tagName.getDisplayName()));
addArtifactsToPortableCase(tagName, progressPanel);
}
} catch (TskCoreException ex) {
handleError("Error copying tagged artifacts", Bundle.CreatePortableCaseModule_generateReport_errorCopyingArtifacts(), ex, progressPanel);
return;
}
// Close the case connections and clear out the maps
cleanup();
@ -232,7 +279,7 @@ public class CreatePortableCaseModule implements GeneralReportModule {
/**
* Create the case directory and case database.
* skCase will be set if this completes without error.
* portableSkCase will be set if this completes without error.
*
* @param outputDir The parent for the case folder
* @param progressPanel
@ -258,7 +305,7 @@ public class CreatePortableCaseModule implements GeneralReportModule {
// Create the case
try {
skCase = currentCase.createPortableCase(caseName, caseFolder);
portableSkCase = currentCase.createPortableCase(caseName, caseFolder);
} catch (TskCoreException ex) {
handleError("Error creating case " + caseName + " in folder " + caseFolder.toString(),
Bundle.CreatePortableCaseModule_createCase_errorCreatingCase(), ex, progressPanel);
@ -294,14 +341,11 @@ public class CreatePortableCaseModule implements GeneralReportModule {
/**
* Add all files with a given tag to the portable case.
*
* @param oldTagName
* @param progressPanel
* @param oldTagName The TagName object from the current case
* @param progressPanel The progress panel
*
* @throws TskCoreException
*/
@NbBundle.Messages({
"# {0} - File name",
"CreatePortableCaseModule.addFilesToPortableCase.copyingFile=Copying file {0}",
})
private void addFilesToPortableCase(TagName oldTagName, ReportProgressPanel progressPanel) throws TskCoreException {
// Get all the tags in the current case
@ -317,29 +361,201 @@ public class CreatePortableCaseModule implements GeneralReportModule {
Content content = tag.getContent();
if (content instanceof AbstractFile) {
AbstractFile file = (AbstractFile) content;
String filePath = file.getParentPath() + file.getName();
progressPanel.updateStatusLabel(Bundle.CreatePortableCaseModule_addFilesToPortableCase_copyingFile(filePath));
long newFileId;
CaseDbTransaction trans = skCase.beginTransaction();
try {
newFileId = copyContent(file, trans);
trans.commit();
} catch (TskCoreException ex) {
trans.rollback();
throw(ex);
}
long newFileId = copyContentToPortableCase(content, progressPanel);
// Tag the file
if (! oldTagNameToNewTagName.containsKey(tag.getName())) {
throw new TskCoreException("TagName map is missing entry for ID " + tag.getName().getId() + " with display name " + tag.getName().getDisplayName());
}
skCase.addContentTag(newIdToContent.get(newFileId), oldTagNameToNewTagName.get(tag.getName()), tag.getComment(), tag.getBeginByteOffset(), tag.getEndByteOffset());
portableSkCase.addContentTag(newIdToContent.get(newFileId), oldTagNameToNewTagName.get(tag.getName()), tag.getComment(), tag.getBeginByteOffset(), tag.getEndByteOffset());
}
}
}
/**
* Add all artifacts with a given tag to the portable case.
*
* @param oldTagName The TagName object from the current case
* @param progressPanel The progress panel
*
* @throws TskCoreException
*/
private void addArtifactsToPortableCase(TagName oldTagName, ReportProgressPanel progressPanel) throws TskCoreException {
List<BlackboardArtifactTag> tags = currentCase.getServices().getTagsManager().getBlackboardArtifactTagsByTagName(oldTagName);
// Copy the artifacts into the portable case along with their content and tag
for (BlackboardArtifactTag tag : tags) {
// Check for cancellation
if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) {
return;
}
// Copy the source content
Content content = tag.getContent();
long newContentId = copyContentToPortableCase(content, progressPanel);
// Copy the artifact
BlackboardArtifact newArtifact = copyArtifact(newContentId, tag.getArtifact());
// Tag the artfiact
if (! oldTagNameToNewTagName.containsKey(tag.getName())) {
throw new TskCoreException("TagName map is missing entry for ID " + tag.getName().getId() + " with display name " + tag.getName().getDisplayName());
}
portableSkCase.addBlackboardArtifactTag(newArtifact, oldTagNameToNewTagName.get(tag.getName()), tag.getComment());
}
}
/**
* Copy an artifact into the new case. Will also copy any associated artifacts
*
* @param newContentId The content ID (in the portable case) of the source content
* @param artifactToCopy The artifact to copy
*
* @return The new artifact in the portable case
*
* @throws TskCoreException
*/
private BlackboardArtifact copyArtifact(long newContentId, BlackboardArtifact artifactToCopy) throws TskCoreException {
if (oldArtifactIdToNewArtifact.containsKey(artifactToCopy.getArtifactID())) {
return oldArtifactIdToNewArtifact.get(artifactToCopy.getArtifactID());
}
// First create the associated artifact (if present)
BlackboardAttribute oldAssociatedAttribute = artifactToCopy.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT));
List<BlackboardAttribute> newAttrs = new ArrayList<>();
if (oldAssociatedAttribute != null) {
BlackboardArtifact oldAssociatedArtifact = currentCase.getSleuthkitCase().getBlackboardArtifact(oldAssociatedAttribute.getValueLong());
BlackboardArtifact newAssociatedArtifact = copyArtifact(newContentId, oldAssociatedArtifact);
newAttrs.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT,
String.join(",", oldAssociatedAttribute.getSources()), newAssociatedArtifact.getArtifactID()));
}
// Create the new artifact
int newArtifactTypeId = getNewArtifactTypeId(artifactToCopy);
BlackboardArtifact newArtifact = portableSkCase.newBlackboardArtifact(newArtifactTypeId, newContentId);
List<BlackboardAttribute> oldAttrs = artifactToCopy.getAttributes();
// Copy over each attribute, making sure the type is in the new case.
for (BlackboardAttribute oldAttr:oldAttrs) {
// The associated artifact has already been handled
if (oldAttr.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT.getTypeID()) {
continue;
}
BlackboardAttribute.Type newAttributeType = getNewAttributeType(oldAttr);
switch (oldAttr.getValueType()) {
case BYTE:
newAttrs.add(new BlackboardAttribute(newAttributeType, String.join(",", oldAttr.getSources()),
oldAttr.getValueBytes()));
break;
case DOUBLE:
newAttrs.add(new BlackboardAttribute(newAttributeType, String.join(",", oldAttr.getSources()),
oldAttr.getValueDouble()));
break;
case INTEGER:
newAttrs.add(new BlackboardAttribute(newAttributeType, String.join(",", oldAttr.getSources()),
oldAttr.getValueInt()));
break;
case DATETIME:
case LONG:
newAttrs.add(new BlackboardAttribute(newAttributeType, String.join(",", oldAttr.getSources()),
oldAttr.getValueLong()));
break;
case STRING:
newAttrs.add(new BlackboardAttribute(newAttributeType, String.join(",", oldAttr.getSources()),
oldAttr.getValueString()));
break;
default:
throw new TskCoreException("Unexpected attribute value type found: " + oldAttr.getValueType().getLabel());
}
}
newArtifact.addAttributes(newAttrs);
oldArtifactIdToNewArtifact.put(artifactToCopy.getArtifactID(), newArtifact);
return newArtifact;
}
/**
* Get the artifact type ID in the portable case and create new artifact type if needed.
* For built-in artifacts this will be the same as the original.
*
* @param oldArtifactTypeId The artifact type ID in the current case
*
* @return The corresponding artifact type ID in the portable case
*/
private int getNewArtifactTypeId(BlackboardArtifact oldArtifact) throws TskCoreException {
if (oldArtTypeIdToNewArtTypeId.containsKey(oldArtifact.getArtifactTypeID())) {
return oldArtTypeIdToNewArtTypeId.get(oldArtifact.getArtifactTypeID());
}
BlackboardArtifact.Type oldCustomType = currentCase.getSleuthkitCase().getArtifactType(oldArtifact.getArtifactTypeName());
try {
BlackboardArtifact.Type newCustomType = portableSkCase.addBlackboardArtifactType(oldCustomType.getTypeName(), oldCustomType.getDisplayName());
oldArtTypeIdToNewArtTypeId.put(oldArtifact.getArtifactTypeID(), newCustomType.getTypeID());
return newCustomType.getTypeID();
} catch (TskDataException ex) {
throw new TskCoreException("Error creating new artifact type " + oldCustomType.getTypeName(), ex);
}
}
/**
* Get the attribute type ID in the portable case and create new attribute type if needed.
* For built-in attributes this will be the same as the original.
*
* @param oldAttributeTypeId The attribute type ID in the current case
*
* @return The corresponding attribute type in the portable case
*/
private BlackboardAttribute.Type getNewAttributeType(BlackboardAttribute oldAttribute) throws TskCoreException {
BlackboardAttribute.Type oldAttrType = oldAttribute.getAttributeType();
if (oldAttrTypeIdToNewAttrType.containsKey(oldAttrType.getTypeID())) {
return oldAttrTypeIdToNewAttrType.get(oldAttrType.getTypeID());
}
try {
BlackboardAttribute.Type newCustomType = portableSkCase.addArtifactAttributeType(oldAttrType.getTypeName(),
oldAttrType.getValueType(), oldAttrType.getDisplayName());
oldAttrTypeIdToNewAttrType.put(oldAttribute.getAttributeType().getTypeID(), newCustomType);
return newCustomType;
} catch (TskDataException ex) {
throw new TskCoreException("Error creating new attribute type " + oldAttrType.getTypeName(), ex);
}
}
/**
* Top level method to copy a content object to the portable case.
*
* @param content The content object to copy
* @param progressPanel The progress panel
*
* @return The object ID of the copied content in the portable case
*
* @throws TskCoreException
*/
@NbBundle.Messages({
"# {0} - File name",
"CreatePortableCaseModule.copyContentToPortableCase.copyingFile=Copying file {0}",
})
private long copyContentToPortableCase(Content content, ReportProgressPanel progressPanel) throws TskCoreException {
progressPanel.updateStatusLabel(Bundle.CreatePortableCaseModule_copyContentToPortableCase_copyingFile(content.getUniquePath()));
long newFileId;
CaseDbTransaction trans = portableSkCase.beginTransaction();
try {
newFileId = copyContent(content, trans);
trans.commit();
return newFileId;
} catch (TskCoreException ex) {
trans.rollback();
throw(ex);
}
}
/**
* Returns the object ID for the given content object in the portable case.
*
@ -368,18 +584,18 @@ public class CreatePortableCaseModule implements GeneralReportModule {
Content newContent;
if (content instanceof Image) {
Image image = (Image)content;
newContent = skCase.addImage(image.getType(), image.getSsize(), image.getSize(), image.getName(),
newContent = portableSkCase.addImage(image.getType(), image.getSsize(), image.getSize(), image.getName(),
new ArrayList<>(), image.getTimeZone(), image.getMd5(), image.getSha1(), image.getSha256(), image.getDeviceId(), trans);
} else if (content instanceof VolumeSystem) {
VolumeSystem vs = (VolumeSystem)content;
newContent = skCase.addVolumeSystem(parentId, vs.getType(), vs.getOffset(), vs.getBlockSize(), trans);
newContent = portableSkCase.addVolumeSystem(parentId, vs.getType(), vs.getOffset(), vs.getBlockSize(), trans);
} else if (content instanceof Volume) {
Volume vs = (Volume)content;
newContent = skCase.addVolume(parentId, vs.getAddr(), vs.getStart(), vs.getLength(),
newContent = portableSkCase.addVolume(parentId, vs.getAddr(), vs.getStart(), vs.getLength(),
vs.getDescription(), vs.getFlags(), trans);
} else if (content instanceof FileSystem) {
FileSystem fs = (FileSystem)content;
newContent = skCase.addFileSystem(parentId, fs.getImageOffset(), fs.getFsType(), fs.getBlock_size(),
newContent = portableSkCase.addFileSystem(parentId, fs.getImageOffset(), fs.getFsType(), fs.getBlock_size(),
fs.getBlock_count(), fs.getRoot_inum(), fs.getFirst_inum(), fs.getLastInum(),
fs.getName(), trans);
} else if (content instanceof AbstractFile) {
@ -387,10 +603,10 @@ public class CreatePortableCaseModule implements GeneralReportModule {
if (abstractFile instanceof LocalFilesDataSource) {
LocalFilesDataSource localFilesDS = (LocalFilesDataSource)abstractFile;
newContent = skCase.addLocalFilesDataSource(localFilesDS.getDeviceId(), localFilesDS.getName(), localFilesDS.getTimeZone(), trans);
newContent = portableSkCase.addLocalFilesDataSource(localFilesDS.getDeviceId(), localFilesDS.getName(), localFilesDS.getTimeZone(), trans);
} else {
if (abstractFile.isDir()) {
newContent = skCase.addLocalDirectory(parentId, abstractFile.getName(), trans);
newContent = portableSkCase.addLocalDirectory(parentId, abstractFile.getName(), trans);
} else {
try {
// Copy the file
@ -410,7 +626,7 @@ public class CreatePortableCaseModule implements GeneralReportModule {
// Construct the relative path to the copied file
String relativePath = FILE_FOLDER_NAME + File.separator + exportSubFolder + File.separator + fileName;
newContent = skCase.addLocalFile(abstractFile.getName(), relativePath, abstractFile.getSize(),
newContent = portableSkCase.addLocalFile(abstractFile.getName(), relativePath, abstractFile.getSize(),
abstractFile.getCtime(), abstractFile.getCrtime(), abstractFile.getAtime(), abstractFile.getMtime(),
abstractFile.getMd5Hash(), abstractFile.getKnown(), abstractFile.getMIMEType(),
true, TskData.EncodingType.NONE,
@ -459,9 +675,9 @@ public class CreatePortableCaseModule implements GeneralReportModule {
newIdToContent.clear();
oldTagNameToNewTagName.clear();
currentCase = null;
if (skCase != null) {
if (portableSkCase != null) {
// We want to close the database connections here but it is currently not possible. JIRA-4736
skCase = null;
portableSkCase = null;
}
caseFolder = null;
copiedFilesFolder = null;

View File

@ -201,10 +201,21 @@ class AddArchiveTask implements Runnable {
success = true;
newDataSources.addAll(internalDataSource.getContent());
// Update the names for all new data sources to be the root archive plus the name of the data source
// update data source info
for (Content c:internalDataSource.getContent()) {
if (c instanceof DataSource) {
DataSource ds = (DataSource) c;
// Read existing aquisition details and update them
String details = "Extracted from archive: " + archivePath.toString();
String existingDetails = ds.getAcquisitionDetails();
if (existingDetails != null && !existingDetails.isEmpty()) {
ds.setAcquisitionDetails(existingDetails + System.getProperty("line.separator") + details);
} else {
ds.setAcquisitionDetails(details);
}
// Update the names for all new data sources to be the root archive plus the name of the data source
String newName = Paths.get(archivePath).getFileName() + "/" + ds.getName();
ds.setDisplayName(newName);
currentCase.notifyDataSourceNameChanged(c, newName);
@ -253,8 +264,17 @@ class AddArchiveTask implements Runnable {
archiveDspLock.wait();
// at this point we got the content object(s) from the current DSP
// at this point we got the content object(s) from the current DSP.
newDataSources.addAll(internalDataSource.getContent());
for (Content c : internalDataSource.getContent()) {
if (c instanceof DataSource) {
DataSource ds = (DataSource) c;
// This is a new data source so just write the aquisition details
String details = "Extracted from archive: " + archivePath.toString();
ds.setAcquisitionDetails(details);
}
}
}
}
} catch (Exception ex) {

View File

@ -42,6 +42,7 @@ import org.netbeans.jellytools.NbDialogOperator;
import org.netbeans.jellytools.WizardOperator;
import org.netbeans.jemmy.JemmyProperties;
import org.netbeans.jemmy.Timeout;
import org.netbeans.jemmy.TimeoutExpiredException;
import org.netbeans.jemmy.Timeouts;
import org.netbeans.jemmy.operators.JButtonOperator;
import org.netbeans.jemmy.operators.JCheckBoxOperator;
@ -67,7 +68,7 @@ public class AutopsyTestCases {
private static final Logger logger = Logger.getLogger(AutopsyTestCases.class.getName());
private long start;
/**
* Escapes the slashes in a file or directory path.
*
@ -96,274 +97,338 @@ public class AutopsyTestCases {
}
public void testNewCaseWizardOpen(String title) {
logger.info("New Case");
resetTimeouts("WindowWaiter.WaitWindowTimeout", 240000);
NbDialogOperator nbdo = new NbDialogOperator(title);
JButtonOperator jbo = new JButtonOperator(nbdo, 0); // the "New Case" button
jbo.pushNoBlock();
try {
logger.info("New Case");
setTimeout("WindowWaiter.WaitWindowTimeout", 240000);
NbDialogOperator nbdo = new NbDialogOperator(title);
JButtonOperator jbo = new JButtonOperator(nbdo, 0); // the "New Case" button
jbo.pushNoBlock();
} catch (TimeoutExpiredException ex) {
screenshot("TimeoutScreenshot");
logger.log(Level.SEVERE, "AutopsyTestCases.testNewCaseWizard encountered timed out", ex);
}
}
public void testNewCaseWizard() {
logger.info("New Case Wizard");
WizardOperator wo = new WizardOperator("New Case Information");
JTextFieldOperator jtfo0 = new JTextFieldOperator(wo, 1);
jtfo0.typeText("AutopsyTestCase"); // Name the case "AutopsyTestCase"
JTextFieldOperator jtfo1 = new JTextFieldOperator(wo, 2);
jtfo1.typeText(getEscapedPath(System.getProperty("out_path")));
wo.btNext().clickMouse();
JTextFieldOperator jtfo2 = new JTextFieldOperator(wo, 0);
jtfo2.typeText("000"); // Set the case number
JTextFieldOperator jtfo3 = new JTextFieldOperator(wo, 1);
jtfo3.typeText("Examiner 1"); // Set the case examiner
start = System.currentTimeMillis();
wo.btFinish().clickMouse();
try {
logger.info("New Case Wizard");
WizardOperator wo = new WizardOperator("New Case Information");
JTextFieldOperator jtfo0 = new JTextFieldOperator(wo, 1);
jtfo0.typeText("AutopsyTestCase"); // Name the case "AutopsyTestCase"
JTextFieldOperator jtfo1 = new JTextFieldOperator(wo, 2);
jtfo1.typeText(getEscapedPath(System.getProperty("out_path")));
wo.btNext().clickMouse();
JTextFieldOperator jtfo2 = new JTextFieldOperator(wo, 0);
jtfo2.typeText("000"); // Set the case number
JTextFieldOperator jtfo3 = new JTextFieldOperator(wo, 1);
jtfo3.typeText("Examiner 1"); // Set the case examiner
start = System.currentTimeMillis();
wo.btFinish().clickMouse();
} catch (TimeoutExpiredException ex) {
screenshot("TimeoutScreenshot");
logger.log(Level.SEVERE, "AutopsyTestCases.testNewCaseWizard encountered timed out", ex);
}
}
public void testStartAddImageFileDataSource() {
/*
* This time out is to give time for creating case database and opening solr index
*/
new Timeout("pausing", 120000).sleep();
logger.info("Starting Add Image process");
resetTimeouts("WindowWaiter.WaitWindowTimeOut", 240000);
WizardOperator wo = new WizardOperator("Add Data Source");
while(!wo.btNext().isEnabled()){
new Timeout("pausing", 1000).sleep(); // give it a second till the Add Data Source dialog enabled
try {
/*
* This time out is to give time for creating case database and
* opening solr index
*/
new Timeout("pausing", 120000).sleep();
logger.info("Starting Add Image process");
setTimeout("WindowWaiter.WaitWindowTimeOut", 240000);
WizardOperator wo = new WizardOperator("Add Data Source");
while (!wo.btNext().isEnabled()) {
new Timeout("pausing", 1000).sleep(); // give it a second till the Add Data Source dialog enabled
}
//select the toggle button for Disk Image or VM File it will be the first button created and proceed to next panel
JToggleButtonOperator jtbo = new JToggleButtonOperator(wo, 0);
jtbo.clickMouse();
wo.btNext().clickMouse();
JTextFieldOperator jtfo0 = new JTextFieldOperator(wo, 0);
String img_path = getEscapedPath(System.getProperty("img_path"));
String imageDir = img_path;
((JTextComponent) jtfo0.getSource()).setText(imageDir);
JComboBoxOperator comboBoxOperator = new JComboBoxOperator(wo, 0);
comboBoxOperator.setSelectedItem("(GMT-5:00) America/New_York");
wo.btNext().clickMouse();
} catch (TimeoutExpiredException ex) {
screenshot("TimeoutScreenshot");
logger.log(Level.SEVERE, "AutopsyTestCases.testNewCaseWizard encountered timed out", ex);
}
//select the toggle button for Disk Image or VM File it will be the first button created and proceed to next panel
JToggleButtonOperator jtbo = new JToggleButtonOperator(wo, 0);
jtbo.clickMouse();
wo.btNext().clickMouse();
JTextFieldOperator jtfo0 = new JTextFieldOperator(wo, 0);
String img_path = getEscapedPath(System.getProperty("img_path"));
String imageDir = img_path;
((JTextComponent) jtfo0.getSource()).setText(imageDir);
JComboBoxOperator comboBoxOperator = new JComboBoxOperator(wo, 0);
comboBoxOperator.setSelectedItem("(GMT-5:00) America/New_York");
wo.btNext().clickMouse();
}
public void testStartAddLogicalFilesDataSource() {
/*
* This time out is to give time for creating case database and opening solr index
*/
new Timeout("pausing", 120000).sleep();
logger.info("Starting Add Logical Files process");
WizardOperator wo = new WizardOperator("Add Data Source");
wo.setTimeouts(resetTimeouts("WindowWaiter.WaitWindowTimeOut", 240000));
while(!wo.btNext().isEnabled()){
new Timeout("pausing", 1000).sleep(); // give it a second till the Add Data Source dialog enabled
try {
/*
* This time out is to give time for creating case database and
* opening solr index
*/
new Timeout("pausing", 120000).sleep();
logger.info("Starting Add Logical Files process");
WizardOperator wo = new WizardOperator("Add Data Source");
wo.setTimeouts(setTimeout("WindowWaiter.WaitWindowTimeOut", 240000));
while (!wo.btNext().isEnabled()) {
new Timeout("pausing", 1000).sleep(); // give it a second till the Add Data Source dialog enabled
}
//select the toggle button for Logical Files it will be the third button created and proceed to next panel
JToggleButtonOperator jtbo = new JToggleButtonOperator(wo, 2);
jtbo.clickMouse();
wo.btNext().clickMouse();
JButtonOperator addButtonOperator = new JButtonOperator(wo, "Add");
addButtonOperator.pushNoBlock();
JFileChooserOperator fileChooserOperator = new JFileChooserOperator();
fileChooserOperator.setCurrentDirectory(new File(getEscapedPath(System.getProperty("img_path"))));
// set the current directory one level above the directory containing logicalFileSet folder.
fileChooserOperator.goUpLevel();
fileChooserOperator.chooseFile(new File(getEscapedPath(System.getProperty("img_path"))).getName());
wo.btNext().clickMouse();
} catch (TimeoutExpiredException ex) {
screenshot("TimeoutScreenshot");
logger.log(Level.SEVERE, "AutopsyTestCases.testNewCaseWizard encountered timed out", ex);
}
//select the toggle button for Logical Files it will be the third button created and proceed to next panel
JToggleButtonOperator jtbo = new JToggleButtonOperator(wo, 2);
jtbo.clickMouse();
wo.btNext().clickMouse();
JButtonOperator addButtonOperator = new JButtonOperator(wo, "Add");
addButtonOperator.pushNoBlock();
JFileChooserOperator fileChooserOperator = new JFileChooserOperator();
fileChooserOperator.setCurrentDirectory(new File(getEscapedPath(System.getProperty("img_path"))));
// set the current directory one level above the directory containing logicalFileSet folder.
fileChooserOperator.goUpLevel();
fileChooserOperator.chooseFile(new File(getEscapedPath(System.getProperty("img_path"))).getName());
wo.btNext().clickMouse();
}
public void testAddSourceWizard1() {
WizardOperator wo = new WizardOperator("Add Data Source");
while (!wo.btFinish().isEnabled()) {
new Timeout("pausing", 1000).sleep(); // give it a second (or five) to process
try {
WizardOperator wo = new WizardOperator("Add Data Source");
while (!wo.btFinish().isEnabled()) {
new Timeout("pausing", 1000).sleep(); // give it a second (or five) to process
}
logger.log(Level.INFO, "Add image took {0}ms", (System.currentTimeMillis() - start));
wo.btFinish().clickMouse();
} catch (TimeoutExpiredException ex) {
screenshot("TimeoutScreenshot");
logger.log(Level.SEVERE, "AutopsyTestCases.testNewCaseWizard encountered timed out", ex);
}
logger.log(Level.INFO, "Add image took {0}ms", (System.currentTimeMillis() - start));
wo.btFinish().clickMouse();
}
public void testConfigureIngest1() {
/*
* This timeout is to allow the setup for the ingest job settings panel
* to complete.
*/
new Timeout("pausing", 10000).sleep();
try {
/*
* This timeout is to allow the setup for the ingest job settings
* panel to complete.
*/
new Timeout("pausing", 10000).sleep();
logger.info("Looking for hash lookup module in ingest job settings panel");
WizardOperator wo = new WizardOperator("Add Data Source");
while(!wo.btNext().isEnabled()){
new Timeout("pausing", 1000).sleep(); // give it a second till the Add Data Source dialog enabled
logger.info("Looking for hash lookup module in ingest job settings panel");
WizardOperator wo = new WizardOperator("Add Data Source");
while (!wo.btNext().isEnabled()) {
new Timeout("pausing", 1000).sleep(); // give it a second till the Add Data Source dialog enabled
}
JTableOperator jto = new JTableOperator(wo, 0);
int row = jto.findCellRow("Hash Lookup", 2, 0);
jto.clickOnCell(row, 1);
logger.info("Selected hash lookup module in ingest job settings panel");
JButtonOperator jbo1 = new JButtonOperator(wo, "Global Settings");
jbo1.pushNoBlock();
logger.info("Pushed Global Settings button for hash lookup module in ingest job settings panel");
} catch (TimeoutExpiredException ex) {
screenshot("TimeoutScreenshot");
logger.log(Level.SEVERE, "AutopsyTestCases.testNewCaseWizard encountered timed out", ex);
}
JTableOperator jto = new JTableOperator(wo, 0);
int row = jto.findCellRow("Hash Lookup", 2, 0);
jto.clickOnCell(row, 1);
logger.info("Selected hash lookup module in ingest job settings panel");
JButtonOperator jbo1 = new JButtonOperator(wo, "Global Settings");
jbo1.pushNoBlock();
logger.info("Pushed Global Settings button for hash lookup module in ingest job settings panel");
}
public void testConfigureHash() {
logger.info("Hash Configure");
JDialog hashMainDialog = JDialogOperator.waitJDialog("Global Hash Lookup Settings", false, false);
JDialogOperator hashMainDialogOperator = new JDialogOperator(hashMainDialog);
List<String> databases = new ArrayList<>();
databases.add(getEscapedPath(System.getProperty("nsrl_path")));
databases.add(getEscapedPath(System.getProperty("known_bad_path")));
databases.stream().map((database) -> {
JButtonOperator importButtonOperator = new JButtonOperator(hashMainDialogOperator, "Import");
importButtonOperator.pushNoBlock();
JDialog addDatabaseDialog = JDialogOperator.waitJDialog("Import Hash Set", false, false);
JDialogOperator addDatabaseDialogOperator = new JDialogOperator(addDatabaseDialog);
JButtonOperator browseButtonOperator = new JButtonOperator(addDatabaseDialogOperator, "Open...", 0);
browseButtonOperator.pushNoBlock();
JFileChooserOperator fileChooserOperator = new JFileChooserOperator();
fileChooserOperator.chooseFile(database);
JButtonOperator okButtonOperator = new JButtonOperator(addDatabaseDialogOperator, "OK", 0);
return okButtonOperator;
}).map((okButtonOperator) -> {
okButtonOperator.pushNoBlock();
return okButtonOperator;
}).forEach((_item) -> {
try {
logger.info("Hash Configure");
JDialog hashMainDialog = JDialogOperator.waitJDialog("Global Hash Lookup Settings", false, false);
JDialogOperator hashMainDialogOperator = new JDialogOperator(hashMainDialog);
List<String> databases = new ArrayList<>();
databases.add(getEscapedPath(System.getProperty("nsrl_path")));
databases.add(getEscapedPath(System.getProperty("known_bad_path")));
databases.stream().map((database) -> {
JButtonOperator importButtonOperator = new JButtonOperator(hashMainDialogOperator, "Import");
importButtonOperator.pushNoBlock();
JDialog addDatabaseDialog = JDialogOperator.waitJDialog("Import Hash Set", false, false);
JDialogOperator addDatabaseDialogOperator = new JDialogOperator(addDatabaseDialog);
JButtonOperator browseButtonOperator = new JButtonOperator(addDatabaseDialogOperator, "Open...", 0);
browseButtonOperator.pushNoBlock();
JFileChooserOperator fileChooserOperator = new JFileChooserOperator();
fileChooserOperator.chooseFile(database);
JButtonOperator okButtonOperator = new JButtonOperator(addDatabaseDialogOperator, "OK", 0);
return okButtonOperator;
}).map((okButtonOperator) -> {
okButtonOperator.pushNoBlock();
return okButtonOperator;
}).forEach((_item) -> {
new Timeout("pausing", 1000).sleep(); // give it a second (or five) to process
});
// Used if the database has no index
//JDialog jd3 = JDialogOperator.waitJDialog("No Index Exists", false, false);
//JDialogOperator jdo3 = new JDialogOperator(jd3);
//JButtonOperator jbo3 = new JButtonOperator(jdo3, "Yes", 0);
new Timeout("pausing", 1000).sleep(); // give it a second (or five) to process
});
// Used if the database has no index
//JDialog jd3 = JDialogOperator.waitJDialog("No Index Exists", false, false);
//JDialogOperator jdo3 = new JDialogOperator(jd3);
//JButtonOperator jbo3 = new JButtonOperator(jdo3, "Yes", 0);
new Timeout("pausing", 1000).sleep(); // give it a second (or five) to process
//jbo3.pushNoBlock();
JButtonOperator jbo4 = new JButtonOperator(hashMainDialogOperator, "OK", 0);
jbo4.pushNoBlock();
//jbo3.pushNoBlock();
JButtonOperator jbo4 = new JButtonOperator(hashMainDialogOperator, "OK", 0);
jbo4.pushNoBlock();
} catch (TimeoutExpiredException ex) {
screenshot("TimeoutScreenshot");
logger.log(Level.SEVERE, "AutopsyTestCases.testNewCaseWizard encountered timed out", ex);
}
}
public void testConfigureIngest2() {
logger.info("Looking for keyword search module in ingest job settings panel");
WizardOperator wo = new WizardOperator("Add Data Source");
while(!wo.btNext().isEnabled()){
new Timeout("pausing", 1000).sleep(); // give it a second till the Add Data Source dialog enabled
try {
logger.info("Looking for keyword search module in ingest job settings panel");
WizardOperator wo = new WizardOperator("Add Data Source");
while (!wo.btNext().isEnabled()) {
new Timeout("pausing", 1000).sleep(); // give it a second till the Add Data Source dialog enabled
}
JTableOperator jto = new JTableOperator(wo, 0);
int row = jto.findCellRow("Keyword Search", 2, 0);
jto.clickOnCell(row, 1);
logger.info("Selected keyword search module in ingest job settings panel");
JButtonOperator jbo1 = new JButtonOperator(wo, "Global Settings");
jbo1.pushNoBlock();
logger.info("Pushed Global Settings button for keyword search module in ingest job settings panel");
} catch (TimeoutExpiredException ex) {
screenshot("TimeoutScreenshot");
logger.log(Level.SEVERE, "AutopsyTestCases.testNewCaseWizard encountered timed out", ex);
}
JTableOperator jto = new JTableOperator(wo, 0);
int row = jto.findCellRow("Keyword Search", 2, 0);
jto.clickOnCell(row, 1);
logger.info("Selected keyword search module in ingest job settings panel");
JButtonOperator jbo1 = new JButtonOperator(wo, "Global Settings");
jbo1.pushNoBlock();
logger.info("Pushed Global Settings button for keyword search module in ingest job settings panel");
}
public void testConfigureSearch() {
logger.info("Search Configure");
JDialog jd = JDialogOperator.waitJDialog("Global Keyword Search Settings", false, false);
JDialogOperator jdo = new JDialogOperator(jd);
String words = getEscapedPath(System.getProperty("keyword_path"));
JButtonOperator jbo0 = new JButtonOperator(jdo, "Import List", 0);
jbo0.pushNoBlock();
JFileChooserOperator jfco0 = new JFileChooserOperator();
jfco0.chooseFile(words);
JTableOperator jto = new JTableOperator(jdo, 0);
jto.clickOnCell(0, 0);
new Timeout("pausing", 1000).sleep(); // give it a second to process
if (Boolean.parseBoolean(System.getProperty("mugen_mode"))) {
JTabbedPaneOperator jtpo = new JTabbedPaneOperator(jdo);
jtpo.selectPage("String Extraction");
JCheckBoxOperator jcbo0 = new JCheckBoxOperator(jtpo, "Arabic (Arabic)");
jcbo0.doClick();
JCheckBoxOperator jcbo1 = new JCheckBoxOperator(jtpo, "Han (Chinese, Japanese, Korean)");
jcbo1.doClick();
try {
logger.info("Search Configure");
JDialog jd = JDialogOperator.waitJDialog("Global Keyword Search Settings", false, false);
JDialogOperator jdo = new JDialogOperator(jd);
String words = getEscapedPath(System.getProperty("keyword_path"));
JButtonOperator jbo0 = new JButtonOperator(jdo, "Import List", 0);
jbo0.pushNoBlock();
JFileChooserOperator jfco0 = new JFileChooserOperator();
jfco0.chooseFile(words);
JTableOperator jto = new JTableOperator(jdo, 0);
jto.clickOnCell(0, 0);
new Timeout("pausing", 1000).sleep(); // give it a second to process
if (Boolean.parseBoolean(System.getProperty("mugen_mode"))) {
JTabbedPaneOperator jtpo = new JTabbedPaneOperator(jdo);
jtpo.selectPage("String Extraction");
JCheckBoxOperator jcbo0 = new JCheckBoxOperator(jtpo, "Arabic (Arabic)");
jcbo0.doClick();
JCheckBoxOperator jcbo1 = new JCheckBoxOperator(jtpo, "Han (Chinese, Japanese, Korean)");
jcbo1.doClick();
new Timeout("pausing", 1000).sleep(); // give it a second to process
}
JButtonOperator jbo2 = new JButtonOperator(jdo, "OK", 0);
jbo2.pushNoBlock();
WizardOperator wo = new WizardOperator("Add Data Source");
new Timeout("pausing", 10000).sleep(); // let things catch up
wo.btNext().clickMouse();
} catch (TimeoutExpiredException ex) {
screenshot("TimeoutScreenshot");
logger.log(Level.SEVERE, "AutopsyTestCases.testNewCaseWizard encountered timed out", ex);
}
JButtonOperator jbo2 = new JButtonOperator(jdo, "OK", 0);
jbo2.pushNoBlock();
WizardOperator wo = new WizardOperator("Add Data Source");
new Timeout("pausing", 10000).sleep(); // let things catch up
wo.btNext().clickMouse();
}
public void testIngest() {
logger.info("Ingest 3");
new Timeout("pausing", 10000).sleep(); // wait for ingest to actually start
long startIngest = System.currentTimeMillis();
IngestManager man = IngestManager.getInstance();
while (man.isIngestRunning()) {
new Timeout("pausing", 1000).sleep(); // give it a second (or five) to process
try {
logger.info("Ingest 3");
new Timeout("pausing", 10000).sleep(); // wait for ingest to actually start
long startIngest = System.currentTimeMillis();
IngestManager man = IngestManager.getInstance();
while (man.isIngestRunning()) {
new Timeout("pausing", 1000).sleep(); // give it a second (or five) to process
}
logger.log(Level.INFO, "Ingest (including enqueue) took {0}ms", (System.currentTimeMillis() - startIngest));
// allow keyword search to finish saving artifacts, just in case
// but randomize the timing so that we don't always get the same error
// consistently, making it seem like default behavior
Random rand = new Random();
new Timeout("pausing", 10000 + (rand.nextInt(15000) + 5000)).sleep();
} catch (TimeoutExpiredException ex) {
screenshot("TimeoutScreenshot");
logger.log(Level.SEVERE, "AutopsyTestCases.testNewCaseWizard encountered timed out", ex);
}
logger.log(Level.INFO, "Ingest (including enqueue) took {0}ms", (System.currentTimeMillis() - startIngest));
// allow keyword search to finish saving artifacts, just in case
// but randomize the timing so that we don't always get the same error
// consistently, making it seem like default behavior
Random rand = new Random();
new Timeout("pausing", 10000 + (rand.nextInt(15000) + 5000)).sleep();
screenshot("Finished Ingest");
}
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");
try {
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);
} catch (TimeoutExpiredException ex) {
screenshot("TimeoutScreenshot");
logger.log(Level.SEVERE, "AutopsyTestCases.testNewCaseWizard encountered timed out", ex);
}
}
public void testGenerateReportToolbar() {
logger.info("Generate Report Toolbars");
MainWindowOperator mwo = MainWindowOperator.getDefault();
JButtonOperator jbo = new JButtonOperator(mwo, "Generate Report");
jbo.pushNoBlock();
new Timeout("pausing", 5000).sleep();
try {
logger.info("Generate Report Toolbars");
MainWindowOperator mwo = MainWindowOperator.getDefault();
JButtonOperator jbo = new JButtonOperator(mwo, "Generate Report");
jbo.pushNoBlock();
} catch (TimeoutExpiredException ex) {
screenshot("TimeoutScreenshot");
logger.log(Level.SEVERE, "AutopsyTestCases.testNewCaseWizard encountered timed out", ex);
}
}
public void testGenerateReportButton() throws IOException {
logger.info("Generate Report Button");
resetTimeouts("ComponentOperator.WaitComponentTimeout", 240000);
JDialog reportDialog = JDialogOperator.waitJDialog("Generate Report", false, false);
JDialogOperator reportDialogOperator = new JDialogOperator(reportDialog);
JListOperator listOperator = new JListOperator(reportDialogOperator);
JButtonOperator jbo0 = new JButtonOperator(reportDialogOperator, "Next");
DateFormat dateFormat = new SimpleDateFormat("MM-dd-yyyy-HH-mm-ss");
Date date = new Date();
String datenotime = dateFormat.format(date);
listOperator.clickOnItem(0, 1);
jbo0.pushNoBlock();
new Timeout("pausing", 2000).sleep();
JButtonOperator jbo1 = new JButtonOperator(reportDialogOperator, "Finish");
jbo1.pushNoBlock();
JDialog previewDialog = JDialogOperator.waitJDialog("Progress", false, false);
screenshot("Progress");
JDialogOperator previewDialogOperator = new JDialogOperator(previewDialog);
JLabelOperator.waitJLabel(previewDialog, "Complete", false, false);
JButtonOperator jbo2 = new JButtonOperator(previewDialogOperator, "Close");
jbo2.pushNoBlock();
new Timeout("pausing", 10000).sleep();
System.setProperty("ReportStr", datenotime);
screenshot("Done Testing");
try {
logger.info("Generate Report Button");
setTimeout("ComponentOperator.WaitComponentTimeout", 240000);
JDialog reportDialog = JDialogOperator.waitJDialog("Generate Report", false, false);
JDialogOperator reportDialogOperator = new JDialogOperator(reportDialog);
JListOperator listOperator = new JListOperator(reportDialogOperator);
JButtonOperator jbo0 = new JButtonOperator(reportDialogOperator, "Next");
DateFormat dateFormat = new SimpleDateFormat("MM-dd-yyyy-HH-mm-ss");
Date date = new Date();
String datenotime = dateFormat.format(date);
listOperator.clickOnItem(0, 1);
jbo0.pushNoBlock();
new Timeout("pausing", 2000).sleep();
JButtonOperator jbo1 = new JButtonOperator(reportDialogOperator, "Finish");
jbo1.pushNoBlock();
JDialog previewDialog = JDialogOperator.waitJDialog("Progress", false, false);
JDialogOperator previewDialogOperator = new JDialogOperator(previewDialog);
JLabelOperator.waitJLabel(previewDialog, "Complete", false, false);
JButtonOperator jbo2 = new JButtonOperator(previewDialogOperator, "Close");
jbo2.pushNoBlock();
new Timeout("pausing", 10000).sleep();
System.setProperty("ReportStr", datenotime);
} catch (TimeoutExpiredException ex) {
screenshot("TimeoutScreenshot");
logger.log(Level.SEVERE, "AutopsyTestCases.testNewCaseWizard encountered timed out", ex);
}
}
public void screenshot(String name) {
logger.info("Taking screenshot.");
try {
Rectangle screenRect = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
BufferedImage capture = new Robot().createScreenCapture(screenRect);
String outPath = getEscapedPath(System.getProperty("out_path"));
ImageIO.write(capture, "png", new File(outPath + "\\" + name + ".png"));
new Timeout("pausing", 1000).sleep(); // give it a second to save
} catch (IOException ex) {
logger.log(Level.WARNING, "IOException taking screenshot.", ex);
} catch (AWTException ex) {
logger.log(Level.WARNING, "AWTException taking screenshot.", ex);
String outPath = getEscapedPath(System.getProperty("out_path"));
File screenShotFile = new File(outPath + "\\" + name + ".png");
if (!screenShotFile.exists()) {
logger.info("Taking screenshot.");
try {
Rectangle screenRect = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
BufferedImage capture = new Robot().createScreenCapture(screenRect);
ImageIO.write(capture, "png", screenShotFile);
new Timeout("pausing", 1000).sleep(); // give it a second to save
} catch (IOException ex) {
logger.log(Level.WARNING, "IOException taking screenshot.", ex);
} catch (AWTException ex) {
logger.log(Level.WARNING, "AWTException taking screenshot.", ex);
}
}
}
/*
* Nightly test failed at WindowWaiter.WaitWindowTimeOut because of TimeoutExpiredException. So we
* use this conveninent method to override the default Jemmy Timeouts value.
*/
private Timeouts resetTimeouts(String name, int value) {
/*
* Nightly test failed at WindowWaiter.WaitWindowTimeOut because of
* TimeoutExpiredException. So we use this conveninent method to override
* the default Jemmy Timeouts value.
*/
private Timeouts setTimeout(String name, int value) {
Timeouts timeouts = JemmyProperties.getCurrentTimeouts();
timeouts.setTimeout(name, value);
return timeouts;
}
private void setMultiUserPerferences() {
UserPreferences.setIsMultiUserModeEnabled(true);
//PostgreSQL database settings
@ -393,8 +458,8 @@ public class AutopsyTestCases {
logger.log(Level.SEVERE, "Error saving messaging service connection info", ex); //NON-NLS
}
}
private void expandNodes (JTreeOperator jto, TreePath tp) {
private void expandNodes(JTreeOperator jto, TreePath tp) {
try {
jto.expandPath(tp);
for (TreePath t : jto.getChildPaths(tp)) {