Merge branch 'develop' of https://github.com/sleuthkit/autopsy into 4606-AddUserLoginsToOsAccountArts

This commit is contained in:
William Schaefer 2019-01-10 18:19:18 -05:00
commit 44b34e410f
12 changed files with 1251 additions and 2 deletions

View File

@ -67,6 +67,7 @@ import org.sleuthkit.autopsy.appservices.AutopsyService;
import org.sleuthkit.autopsy.appservices.AutopsyService.CaseContext;
import static org.sleuthkit.autopsy.casemodule.Bundle.*;
import org.sleuthkit.autopsy.casemodule.CaseMetadata.CaseMetadataException;
import org.sleuthkit.autopsy.casemodule.datasourceSummary.DataSourceSummaryAction;
import org.sleuthkit.autopsy.casemodule.events.AddingDataSourceEvent;
import org.sleuthkit.autopsy.casemodule.events.AddingDataSourceFailedEvent;
import org.sleuthkit.autopsy.casemodule.events.BlackBoardArtifactTagAddedEvent;
@ -1165,6 +1166,7 @@ public class Case {
CallableSystemAction.get(AddImageAction.class).setEnabled(true);
CallableSystemAction.get(CaseCloseAction.class).setEnabled(true);
CallableSystemAction.get(CasePropertiesAction.class).setEnabled(true);
CallableSystemAction.get(DataSourceSummaryAction.class).setEnabled(true);
CallableSystemAction.get(CaseDeleteAction.class).setEnabled(true);
CallableSystemAction.get(OpenTimelineAction.class).setEnabled(true);
CallableSystemAction.get(OpenCommVisualizationToolAction.class).setEnabled(true);
@ -1218,6 +1220,7 @@ public class Case {
CallableSystemAction.get(AddImageAction.class).setEnabled(false);
CallableSystemAction.get(CaseCloseAction.class).setEnabled(false);
CallableSystemAction.get(CasePropertiesAction.class).setEnabled(false);
CallableSystemAction.get(DataSourceSummaryAction.class).setEnabled(false);
CallableSystemAction.get(CaseDeleteAction.class).setEnabled(false);
CallableSystemAction.get(OpenTimelineAction.class).setEnabled(false);
CallableSystemAction.get(OpenCommVisualizationToolAction.class).setEnabled(false);

View File

@ -55,7 +55,7 @@ final class CasePropertiesAction extends CallableSystemAction {
casePropertiesDialog = new JDialog(mainWindow, title, true);
CaseInformationPanel caseInformationPanel = new CaseInformationPanel();
caseInformationPanel.addCloseButtonAction((ActionEvent e) -> {
casePropertiesDialog.setVisible(false);
casePropertiesDialog.dispose();
});
casePropertiesDialog.add(caseInformationPanel);
casePropertiesDialog.setResizable(true);

View File

@ -61,7 +61,8 @@ public final class IngestJobInfoPanel extends javax.swing.JPanel {
private void customizeComponents() {
refresh();
this.ingestJobTable.getSelectionModel().addListSelectionListener((ListSelectionEvent e) -> {
this.ingestModuleTableModel = new IngestModuleTableModel(this.ingestJobs.get(ingestJobTable.getSelectedRow()));
IngestJobInfo currJob = (ingestJobTable.getSelectedRow() < 0 ? null : this.ingestJobs.get(ingestJobTable.getSelectedRow()));
this.ingestModuleTableModel = new IngestModuleTableModel(currJob);
this.ingestModuleTable.setModel(this.ingestModuleTableModel);
});

View File

@ -0,0 +1,5 @@
DataSourceSummaryPanel.fileCountsLabel.text=Files (based on mimetype)
DataSourceSummaryPanel.opperatingSystemLabel.text=OS:
DataSourceSummaryPanel.ingestJobsLabel.text=Ingest Jobs
DataSourceSummaryPanel.closeButton.text=Close
DataSourceSummaryPanel.gotoDataSourceButton.text=Goto Data Source

View File

@ -0,0 +1,69 @@
/*
* 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.casemodule.datasourceSummary;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.util.EnumSet;
import javax.swing.Action;
import org.openide.awt.ActionID;
import org.openide.awt.ActionRegistration;
import org.openide.util.HelpCtx;
import org.openide.util.NbBundle.Messages;
import org.openide.util.actions.CallableSystemAction;
import org.sleuthkit.autopsy.casemodule.Case;
@ActionID(category = "Case", id = "org.sleuthkit.autopsy.casemodule.datasourceSummary.DataSourceSummaryAction")
@ActionRegistration(displayName = "#CTL_DataSourceSummaryAction", lazy = false)
@Messages({"CTL_DataSourceSummaryAction=Data Source Summary"})
/**
* DataSourceSummaryAction action for the Case menu to activate a ViewSummaryInformationAction selecting the first data source.
*/
public class DataSourceSummaryAction extends CallableSystemAction {
private static final long serialVersionUID = 1L;
/**
* Create a datasource summary action which will be disabled when no case is
* open.
*/
DataSourceSummaryAction() {
putValue(Action.NAME, Bundle.CTL_DataSourceSummaryAction());
this.setEnabled(false);
Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), (PropertyChangeEvent evt) -> {
setEnabled(null != evt.getNewValue());
});
}
@Override
public void performAction() {
//perform the action of a ViewSummaryInformationAction with a ActionEvent which will not be used
new ViewSummaryInformationAction(null).actionPerformed(new ActionEvent(Boolean.TRUE, 0, ""));
}
@Override
public String getName() {
return Bundle.CTL_DataSourceSummaryAction();
}
@Override
public HelpCtx getHelpCtx() {
return HelpCtx.DEFAULT_HELP;
}
}

View File

@ -0,0 +1,182 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.6" 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="jSeparator1" alignment="1" max="32767" attributes="0"/>
<Group type="102" attributes="0">
<EmptySpace min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="dataSourcesScrollPane" alignment="1" max="32767" attributes="0"/>
<Group type="102" alignment="1" attributes="0">
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
<Component id="gotoDataSourceButton" linkSize="1" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="closeButton" linkSize="1" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="1" attributes="0">
<Component id="fileCountsLabel" max="32767" attributes="0"/>
<Component id="fileCountsScrollPane" alignment="1" min="-2" pref="140" max="-2" attributes="0"/>
</Group>
<EmptySpace type="unrelated" min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="ingestJobsLabel" max="32767" attributes="0"/>
<Component id="ingestJobsScrollPane" pref="474" max="32767" attributes="0"/>
<Group type="102" alignment="1" attributes="0">
<Component id="opperatingSystemLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="opperatingSystemValueLabel" max="32767" attributes="0"/>
</Group>
</Group>
</Group>
</Group>
<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" pref="8" max="-2" attributes="0"/>
<Component id="dataSourcesScrollPane" pref="120" max="32767" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Component id="jSeparator1" min="-2" pref="5" max="-2" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="fileCountsLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="ingestJobsLabel" alignment="3" min="-2" pref="14" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="fileCountsScrollPane" min="-2" pref="107" max="-2" attributes="0"/>
<Component id="ingestJobsScrollPane" pref="0" max="32767" attributes="0"/>
</Group>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="opperatingSystemLabel" alignment="1" min="-2" max="-2" attributes="0"/>
<Component id="opperatingSystemValueLabel" min="-2" pref="14" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" pref="10" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="closeButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="gotoDataSourceButton" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JSeparator" name="jSeparator1">
</Component>
<Container class="javax.swing.JScrollPane" name="dataSourcesScrollPane">
<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.JTable" name="dataSourcesTable">
<Properties>
<Property name="model" type="javax.swing.table.TableModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="dataSourceTableModel" type="code"/>
</Property>
<Property name="selectionModel" type="javax.swing.ListSelectionModel" editor="org.netbeans.modules.form.editors2.JTableSelectionModelEditor">
<JTableSelectionModel selectionMode="0"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JScrollPane" name="ingestJobsScrollPane">
<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.JTable" name="ingestJobsTable">
<Properties>
<Property name="model" type="javax.swing.table.TableModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="ingestJobTableModel" type="code"/>
</Property>
<Property name="selectionModel" type="javax.swing.ListSelectionModel" editor="org.netbeans.modules.form.editors2.JTableSelectionModelEditor">
<JTableSelectionModel selectionMode="0"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JScrollPane" name="fileCountsScrollPane">
<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.JTable" name="fileCountsTable">
<Properties>
<Property name="model" type="javax.swing.table.TableModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="filesTableModel" type="code"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Container>
<Component class="javax.swing.JLabel" name="opperatingSystemLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryPanel.opperatingSystemLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="opperatingSystemValueLabel">
</Component>
<Component class="javax.swing.JLabel" name="fileCountsLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryPanel.fileCountsLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="ingestJobsLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryPanel.ingestJobsLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="closeButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryPanel.closeButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="gotoDataSourceButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/datasourceSummary/Bundle.properties" key="DataSourceSummaryPanel.gotoDataSourceButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="gotoDataSourceButtonActionPerformed"/>
</Events>
</Component>
</SubComponents>
</Form>

View File

@ -0,0 +1,698 @@
/*
* 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.casemodule.datasourceSummary;
import java.awt.Rectangle;
import java.awt.event.ActionListener;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JOptionPane;
import javax.swing.event.ListSelectionEvent;
import javax.swing.table.AbstractTableModel;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.datamodel.utils.FileTypeUtils;
import org.sleuthkit.autopsy.directorytree.ViewContextAction;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.CaseDbAccessManager.CaseDbAccessQueryCallback;
import org.sleuthkit.datamodel.DataSource;
import org.sleuthkit.datamodel.IngestJobInfo;
import org.sleuthkit.datamodel.OSInfo;
import org.sleuthkit.datamodel.OSUtility;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData;
final class DataSourceSummaryPanel extends javax.swing.JPanel {
private static final long serialVersionUID = 1L;
private final List<IngestJobInfo> allIngestJobs = new ArrayList<>();
private List<IngestJobInfo> ingestJobs = new ArrayList<>();
private DataSourceTableModel dataSourceTableModel = new DataSourceTableModel();
private IngestJobTableModel ingestJobTableModel = new IngestJobTableModel();
private FilesTableModel filesTableModel = new FilesTableModel(null);
private final List<DataSource> dataSources = new ArrayList<>();
private final DateFormat datetimeFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
private static final Logger logger = Logger.getLogger(DataSourceSummaryPanel.class.getName());
private List<OSInfo> osInfoList;
/**
* Creates new form DataSourceSummaryPanel for displaying a summary of the
* data sources for the fcurrent case and the contents found for each
* datasource.
*/
@Messages({"DataSourceSummaryPanel.getDataSources.error.text=Failed to get the list of datasources for the current case.",
"DataSourceSummaryPanel.getDataSources.error.title=Load Failure"})
DataSourceSummaryPanel() {
initComponents();
ingestJobsTable.getTableHeader().setReorderingAllowed(false);
fileCountsTable.getTableHeader().setReorderingAllowed(false);
dataSourcesTable.getTableHeader().setReorderingAllowed(false);
try {
SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase();
allIngestJobs.addAll(skCase.getIngestJobs());
dataSources.addAll(skCase.getDataSources());
osInfoList = OSUtility.getOSInfo(skCase);
} catch (TskCoreException | NoCurrentCaseException ex) {
logger.log(Level.SEVERE, "Failed to load ingest jobs.", ex);
JOptionPane.showMessageDialog(this, Bundle.DataSourceSummaryPanel_getDataSources_error_text(), Bundle.DataSourceSummaryPanel_getDataSources_error_title(), JOptionPane.ERROR_MESSAGE);
}
dataSourcesTable.getSelectionModel().addListSelectionListener((ListSelectionEvent e) -> {
if (!e.getValueIsAdjusting()) {
DataSource selectedDataSource = (dataSourcesTable.getSelectedRow() < 0 ? null : dataSources.get(dataSourcesTable.getSelectedRow()));
gotoDataSourceButton.setEnabled(selectedDataSource != null);
updateIngestJobs(selectedDataSource);
filesTableModel = new FilesTableModel(selectedDataSource);
fileCountsTable.setModel(filesTableModel);
opperatingSystemValueLabel.setText(getOSName(selectedDataSource));
this.repaint();
}
});
}
/**
* Get the name of the operating system if it is available. Otherwise get
* and empty string.
*
* @param selectedDataSource the datasource to get the OS information for
*
* @return the name of the opperating system on the specified datasource,
* empty string if no opperating system info found
*/
private String getOSName(DataSource selectedDataSource) {
String osName = "";
if (selectedDataSource != null) {
for (OSInfo osInfo : osInfoList) {
try {
//assumes only one Opperating System per datasource
//get the datasource id from the OSInfo's first artifact if it has artifacts
if (!osInfo.getArtifacts().isEmpty() && osInfo.getArtifacts().get(0).getDataSource().getId() == selectedDataSource.getId()) {
osName = osInfo.getOSName();
//if this OSInfo object has a name use it otherwise keep checking OSInfo objects
if (!osName.isEmpty()) {
break;
}
}
} catch (TskCoreException ignored) {
//unable to get datasource for the OSInfo Object
//continue checking for OSInfo objects to try and get get the desired information
}
}
}
return osName;
}
/**
* Update the ingestJobs list with the ingest jobs for the
* selectedDataSource
*
* @param selectedDataSource the datasource to find the ingest jobs for
*/
@Messages({"DataSourceSummaryPanel.loadIngestJob.error.text=Failed to load ingest jobs.",
"DataSourceSummaryPanel.loadIngestJob.error.title=Load Failure"})
private void updateIngestJobs(DataSource selectedDataSource) {
ingestJobs.clear();
if (selectedDataSource != null) {
for (IngestJobInfo ingestJob : allIngestJobs) {
if (ingestJob.getObjectId() == selectedDataSource.getId()) {
ingestJobs.add(ingestJob);
}
}
}
ingestJobTableModel = new IngestJobTableModel();
ingestJobsTable.setModel(ingestJobTableModel);
}
/**
* 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() {
jSeparator1 = new javax.swing.JSeparator();
dataSourcesScrollPane = new javax.swing.JScrollPane();
dataSourcesTable = new javax.swing.JTable();
ingestJobsScrollPane = new javax.swing.JScrollPane();
ingestJobsTable = new javax.swing.JTable();
fileCountsScrollPane = new javax.swing.JScrollPane();
fileCountsTable = new javax.swing.JTable();
opperatingSystemLabel = new javax.swing.JLabel();
opperatingSystemValueLabel = new javax.swing.JLabel();
fileCountsLabel = new javax.swing.JLabel();
ingestJobsLabel = new javax.swing.JLabel();
closeButton = new javax.swing.JButton();
gotoDataSourceButton = new javax.swing.JButton();
dataSourcesTable.setModel(dataSourceTableModel);
dataSourcesTable.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
dataSourcesScrollPane.setViewportView(dataSourcesTable);
ingestJobsTable.setModel(ingestJobTableModel);
ingestJobsTable.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
ingestJobsScrollPane.setViewportView(ingestJobsTable);
fileCountsTable.setModel(filesTableModel);
fileCountsScrollPane.setViewportView(fileCountsTable);
org.openide.awt.Mnemonics.setLocalizedText(opperatingSystemLabel, org.openide.util.NbBundle.getMessage(DataSourceSummaryPanel.class, "DataSourceSummaryPanel.opperatingSystemLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(fileCountsLabel, org.openide.util.NbBundle.getMessage(DataSourceSummaryPanel.class, "DataSourceSummaryPanel.fileCountsLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(ingestJobsLabel, org.openide.util.NbBundle.getMessage(DataSourceSummaryPanel.class, "DataSourceSummaryPanel.ingestJobsLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(closeButton, org.openide.util.NbBundle.getMessage(DataSourceSummaryPanel.class, "DataSourceSummaryPanel.closeButton.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(gotoDataSourceButton, org.openide.util.NbBundle.getMessage(DataSourceSummaryPanel.class, "DataSourceSummaryPanel.gotoDataSourceButton.text")); // NOI18N
gotoDataSourceButton.setEnabled(false);
gotoDataSourceButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
gotoDataSourceButtonActionPerformed(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jSeparator1, javax.swing.GroupLayout.Alignment.TRAILING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(dataSourcesScrollPane, javax.swing.GroupLayout.Alignment.TRAILING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addGap(0, 0, Short.MAX_VALUE)
.addComponent(gotoDataSourceButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(closeButton))
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(fileCountsLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(fileCountsScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 140, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(ingestJobsLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(ingestJobsScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 474, Short.MAX_VALUE)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addComponent(opperatingSystemLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(opperatingSystemValueLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))))
.addContainerGap())
);
layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {closeButton, gotoDataSourceButton});
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(8, 8, 8)
.addComponent(dataSourcesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 120, Short.MAX_VALUE)
.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.BASELINE)
.addComponent(fileCountsLabel)
.addComponent(ingestJobsLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(fileCountsScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 107, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(ingestJobsScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(opperatingSystemLabel, javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(opperatingSystemValueLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGap(10, 10, 10)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(closeButton)
.addComponent(gotoDataSourceButton))
.addContainerGap())
);
}// </editor-fold>//GEN-END:initComponents
/**
* Adds an action listener to the Close button of the panel.
*
* @param action
*/
void addCloseButtonAction(ActionListener action) {
this.closeButton.addActionListener(action);
//the gotoDataSourceButton should also close the dialog
this.gotoDataSourceButton.addActionListener(action);
}
/**
* Select the data source with the specicied data source id. If no data
* source matches the dataSourceID it will select the first datasource.
*
* @param dataSourceID the ID of the datasource to select, null will cause
* the first datasource to be selected
*/
void selectDataSource(Long dataSourceID) {
if (dataSourceID != null) {
for (int i = 0; i < dataSources.size(); i++) {
if (dataSources.get(i).getId() == dataSourceID) {
dataSourcesTable.setRowSelectionInterval(i, i);
//scroll down from top of table to where selected datasource is
dataSourcesTable.scrollRectToVisible(new Rectangle(dataSourcesTable.getCellRect(i, 0, true)));
return;
}
}
}
//if there are data sources in the list and none were found that matched the specied dataSourceID select the first one
if (!dataSources.isEmpty()) {
dataSourcesTable.setRowSelectionInterval(0, 0);
}
}
/**
* Performed when the Goto Data Source button is clicked, will cause the
* window to be closed and the data source which was selected to be
* navigated to in the tree.
*/
private void gotoDataSourceButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_gotoDataSourceButtonActionPerformed
//the dialog will be closed due to the action listener added in addCloseButtonAction
DataSource selectedDataSource = (dataSourcesTable.getSelectedRow() < 0 ? null : dataSources.get(dataSourcesTable.getSelectedRow()));
if (selectedDataSource != null) {
new ViewContextAction("", selectedDataSource).actionPerformed(evt);
}
}//GEN-LAST:event_gotoDataSourceButtonActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton closeButton;
private javax.swing.JScrollPane dataSourcesScrollPane;
private javax.swing.JTable dataSourcesTable;
private javax.swing.JLabel fileCountsLabel;
private javax.swing.JScrollPane fileCountsScrollPane;
private javax.swing.JTable fileCountsTable;
private javax.swing.JButton gotoDataSourceButton;
private javax.swing.JLabel ingestJobsLabel;
private javax.swing.JScrollPane ingestJobsScrollPane;
private javax.swing.JTable ingestJobsTable;
private javax.swing.JSeparator jSeparator1;
private javax.swing.JLabel opperatingSystemLabel;
private javax.swing.JLabel opperatingSystemValueLabel;
// End of variables declaration//GEN-END:variables
/**
* Table model for the Data source table, to display all data sources for
* the current case.
*/
@Messages({"DataSourceSummaryPanel.DataSourceTableModel.dataSourceName.header=Data Source Name",
"DataSourceSummaryPanel.DataSourceTableModel.type.header=Type",
"DataSourceSummaryPanel.DataSourceTableModel.files.header=Files",
"DataSourceSummaryPanel.DataSourceTableModel.results.header=Results",
"DataSourceSummaryPanel.DataSourceTableModel.tags.header=Tags"})
private class DataSourceTableModel extends AbstractTableModel {
private static final long serialVersionUID = 1L;
private final List<String> columnHeaders = new ArrayList<>();
private final Map<Long, Long> fileCountsMap;
private final Map<Long, Long> artifactCountsMap;
private final Map<Long, Long> tagCountsMap;
/**
* Create a new DataSourceTableModel for the current case.
*/
DataSourceTableModel() {
columnHeaders.add(Bundle.DataSourceSummaryPanel_DataSourceTableModel_dataSourceName_header());
columnHeaders.add(Bundle.DataSourceSummaryPanel_DataSourceTableModel_type_header());
columnHeaders.add(Bundle.DataSourceSummaryPanel_DataSourceTableModel_files_header());
columnHeaders.add(Bundle.DataSourceSummaryPanel_DataSourceTableModel_results_header());
columnHeaders.add(Bundle.DataSourceSummaryPanel_DataSourceTableModel_tags_header());
fileCountsMap = getCountsOfFiles();
artifactCountsMap = getCountsOfArtifacts();
tagCountsMap = getCountsOfTags();
}
@Override
public int getRowCount() {
return dataSources.size();
}
@Override
public int getColumnCount() {
return columnHeaders.size();
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
DataSource currentDataSource = dataSources.get(rowIndex);
Long count;
switch (columnIndex) {
case 0:
return currentDataSource.getName();
case 1:
return "";
case 2:
//display 0 if no count is found
count = fileCountsMap.get(currentDataSource.getId());
return count == null ? 0 : count;
case 3:
//display 0 if no count is found
count = artifactCountsMap.get(currentDataSource.getId());
return count == null ? 0 : count;
case 4:
//display 0 if no count is found
count = tagCountsMap.get(currentDataSource.getId());
return count == null ? 0 : count;
default:
break;
}
return null;
}
/**
* Get a map containing the number of files in each data source in the
* current case.
*
* @return Collection which maps datasource id to a count for the number
* of files in the datasource, will only contain entries for
* datasources which have at least 1 file
*/
private Map<Long, Long> getCountsOfFiles() {
try {
SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase();
DataSourceCountsCallback callback = new DataSourceCountsCallback();
final String countFilesQuery = "data_source_obj_id, COUNT(*) AS count"
+ " FROM tsk_files WHERE type<>" + TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType()
+ " AND dir_type<>" + TskData.TSK_FS_NAME_TYPE_ENUM.VIRT_DIR.getValue()
+ " AND name<>'' GROUP BY data_source_obj_id"; //NON-NLS
skCase.getCaseDbAccessManager().select(countFilesQuery, callback);
return callback.getMapOfCounts();
} catch (TskCoreException | NoCurrentCaseException ex) {
logger.log(Level.WARNING, "Unable to get counts of files for all datasources, providing empty results", ex);
return Collections.emptyMap();
}
}
/**
* Get a map containing the number of artifacts in each data source in
* the current case.
*
* @return Collection which maps datasource id to a count for the number
* of artifacts in the datasource, will only contain entries for
* datasources which have at least 1 artifact
*/
private Map<Long, Long> getCountsOfArtifacts() {
try {
SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase();
DataSourceCountsCallback callback = new DataSourceCountsCallback();
final String countArtifactsQuery = "data_source_obj_id, COUNT(*) AS count"
+ " FROM blackboard_artifacts WHERE review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID()
+ " GROUP BY data_source_obj_id"; //NON-NLS
skCase.getCaseDbAccessManager().select(countArtifactsQuery, callback);
return callback.getMapOfCounts();
} catch (TskCoreException | NoCurrentCaseException ex) {
logger.log(Level.WARNING, "Unable to get counts of artifacts for all datasources, providing empty results", ex);
return Collections.emptyMap();
}
}
/**
* Get a map containing the number of tags which have been applied in
* each data source in the current case. Not necessarily the same as the
* number of items tagged, as an item can have any number of tags.
*
* @return Collection which maps datasource id to a count for the number
* of tags which have been applied in the datasource, will only
* contain entries for datasources which have at least 1 item
* tagged.
*/
private Map<Long, Long> getCountsOfTags() {
try {
SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase();
DataSourceCountsCallback fileCountcallback = new DataSourceCountsCallback();
final String countFileTagsQuery = "data_source_obj_id, COUNT(*) AS count"
+ " FROM content_tags as content_tags, tsk_files as tsk_files"
+ " WHERE content_tags.obj_id = tsk_files.obj_id"
+ " GROUP BY data_source_obj_id"; //NON-NLS
skCase.getCaseDbAccessManager().select(countFileTagsQuery, fileCountcallback);
Map<Long, Long> tagCountMap = new HashMap<>(fileCountcallback.getMapOfCounts());
DataSourceCountsCallback artifactCountcallback = new DataSourceCountsCallback();
final String countArtifactTagsQuery = "data_source_obj_id, COUNT(*) AS count"
+ " FROM blackboard_artifact_tags as artifact_tags, blackboard_artifacts AS arts"
+ " WHERE artifact_tags.artifact_id = arts.artifact_id"
+ " GROUP BY data_source_obj_id"; //NON-NLS
skCase.getCaseDbAccessManager().select(countArtifactTagsQuery, artifactCountcallback);
//combine the results from the count artifact tags query into the copy of the mapped results from the count file tags query
artifactCountcallback.getMapOfCounts().forEach((key, value) -> tagCountMap.merge(key, value, (value1, value2) -> value1 + value2));
return tagCountMap;
} catch (TskCoreException | NoCurrentCaseException ex) {
logger.log(Level.WARNING, "Unable to get counts of tags for all datasources, providing empty results", ex);
return Collections.emptyMap();
}
}
@Override
public String getColumnName(int column) {
return columnHeaders.get(column);
}
/**
* Get the map of Data Source ID to counts of items found for a query
* which selects data_source_obj_id and count(*) with a group by
* data_source_obj_id clause.
*/
private class DataSourceCountsCallback implements CaseDbAccessQueryCallback {
Map<Long, Long> dataSourceObjIdCounts = new HashMap<>();
@Override
public void process(ResultSet rs) {
try {
while (rs.next()) {
try {
dataSourceObjIdCounts.put(rs.getLong("data_source_obj_id"), rs.getLong("count"));
} catch (SQLException ex) {
logger.log(Level.WARNING, "Unable to get data_source_obj_id or count from result set", ex);
}
}
} catch (SQLException ex) {
logger.log(Level.WARNING, "Failed to get next result for counts by datasource", ex);
}
}
/**
* Get the processed results
*
* @return Collection which maps datasource id to a count for the
* number of items found with that datasource id, only
* contains entries for datasources with at least 1 item
* found.
*/
Map<Long, Long> getMapOfCounts() {
return Collections.unmodifiableMap(dataSourceObjIdCounts);
}
}
}
/**
* Table model for the Ingest Job table to display ingest jobs for the
* selected datasource.
*/
@Messages({"DataSourceSummaryPanel.IngestJobTableModel.StartTime.header=Start Time",
"DataSourceSummaryPanel.IngestJobTableModel.EndTime.header=End Time",
"DataSourceSummaryPanel.IngestJobTableModel.IngestStatus.header=Ingest Status"})
private class IngestJobTableModel extends AbstractTableModel {
private static final long serialVersionUID = 1L;
private final List<String> columnHeaders = new ArrayList<>();
/**
* Create a new IngestJobTableModel
*/
IngestJobTableModel() {
columnHeaders.add(Bundle.DataSourceSummaryPanel_IngestJobTableModel_StartTime_header());
columnHeaders.add(Bundle.DataSourceSummaryPanel_IngestJobTableModel_EndTime_header());
columnHeaders.add(Bundle.DataSourceSummaryPanel_IngestJobTableModel_IngestStatus_header());
}
@Override
public int getRowCount() {
return ingestJobs.size();
}
@Override
public int getColumnCount() {
return columnHeaders.size();
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
IngestJobInfo currIngestJob = ingestJobs.get(rowIndex);
switch (columnIndex) {
case 0:
return datetimeFormat.format(currIngestJob.getStartDateTime());
case 1:
Date endDate = currIngestJob.getEndDateTime();
if (endDate.getTime() == 0) {
return "N/A";
}
return datetimeFormat.format(currIngestJob.getEndDateTime());
case 2:
return currIngestJob.getStatus().getDisplayName();
default:
break;
}
return null;
}
@Override
public String getColumnName(int column) {
return columnHeaders.get(column);
}
}
/**
* Table model for the files table model to display counts of specific file
* types found in the currently selected data source.
*/
@Messages({"DataSourceSummaryPanel.FilesTableModel.type.header=File Type",
"DataSourceSummaryPanel.FilesTableModel.count.header=Count"})
private class FilesTableModel extends AbstractTableModel {
private static final long serialVersionUID = 1L;
private final DataSource currentDataSource;
private final List<String> columnHeaders = new ArrayList<>();
/**
* Create a FilesTableModel for the speicified datasource.
*
* @param selectedDataSource the datasource which this filesTablemodel
* will represent
*/
FilesTableModel(DataSource selectedDataSource) {
columnHeaders.add(Bundle.DataSourceSummaryPanel_FilesTableModel_type_header());
columnHeaders.add(Bundle.DataSourceSummaryPanel_FilesTableModel_count_header());
currentDataSource = selectedDataSource;
}
@Override
public int getRowCount() {
//should be kept equal to the number of types we are displaying in the tables
return 5;
}
@Override
public int getColumnCount() {
return columnHeaders.size();
}
@Messages({
"DataSourceSummaryPanel.FilesTableModel.images.row=Images",
"DataSourceSummaryPanel.FilesTableModel.videos.row=Videos",
"DataSourceSummaryPanel.FilesTableModel.audio.row=Audio",
"DataSourceSummaryPanel.FilesTableModel.documents.row=Documents",
"DataSourceSummaryPanel.FilesTableModel.executables.row=Executables"
})
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
if (columnIndex == 0) {
switch (rowIndex) {
case 0:
return Bundle.DataSourceSummaryPanel_FilesTableModel_images_row();
case 1:
return Bundle.DataSourceSummaryPanel_FilesTableModel_videos_row();
case 2:
return Bundle.DataSourceSummaryPanel_FilesTableModel_audio_row();
case 3:
return Bundle.DataSourceSummaryPanel_FilesTableModel_documents_row();
case 4:
return Bundle.DataSourceSummaryPanel_FilesTableModel_executables_row();
default:
break;
}
} else if (columnIndex == 1) {
switch (rowIndex) {
case 0:
return getCountOfFiles(FileTypeUtils.FileTypeCategory.IMAGE.getMediaTypes());
case 1:
return getCountOfFiles(FileTypeUtils.FileTypeCategory.VIDEO.getMediaTypes());
case 2:
return getCountOfFiles(FileTypeUtils.FileTypeCategory.AUDIO.getMediaTypes());
case 3:
return getCountOfFiles(FileTypeUtils.FileTypeCategory.DOCUMENTS.getMediaTypes());
case 4:
return getCountOfFiles(FileTypeUtils.FileTypeCategory.EXECUTABLE.getMediaTypes());
default:
break;
}
}
return null;
}
/**
* Get the number of files in the case database for the current data
* source which have the specified mimetypes.
*
* @param setOfMimeTypes the set of mime types which we are finding the
* number of occurences of
*
* @return a Long value which represents the number of occurrences of
* the specified mime types in the current case for the
* specified data source, null if no count was retrieved
*/
private Long getCountOfFiles(Set<String> setOfMimeTypes) {
if (currentDataSource != null) {
try {
String inClause = String.join("', '", setOfMimeTypes);
SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase();
return skCase.countFilesWhere("data_source_obj_id=" + currentDataSource.getId()
+ " AND type<>" + TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType()
+ " AND dir_type<>" + TskData.TSK_FS_NAME_TYPE_ENUM.VIRT_DIR.getValue()
+ " AND mime_type IN ('" + inClause + "')"
+ " AND name<>''");
} catch (TskCoreException | NoCurrentCaseException ex) {
logger.log(Level.WARNING, "Unable to get count of files for specified mime types", ex);
//unable to get count of files for the specified mimetypes cell will be displayed as empty
}
}
return null;
}
@Override
public String getColumnName(int column) {
return columnHeaders.get(column);
}
}
}

View File

@ -0,0 +1,75 @@
/*
* 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.casemodule.datasourceSummary;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.JDialog;
import javax.swing.SwingUtilities;
import org.openide.util.NbBundle.Messages;
import org.openide.windows.WindowManager;
/**
* ViewSummaryInformationAction action for opening a Data Source Summary Panel
* with the specified data source selected if it is present.
*/
public final class ViewSummaryInformationAction extends AbstractAction {
private static JDialog dataSourceSummaryDialog;
private static Long selectDataSource;
private static final long serialVersionUID = 1L;
/**
* Create a ViewSummaryInformationAction for the selected datasource.
*
* @param selectedDataSource - the data source which is currently selected
* and will be selected initially when the
* DataSourceSummaryPanel opens.
*/
@Messages({"ViewSummaryInformationAction.name.text=View Summary Information"})
public ViewSummaryInformationAction(Long selectedDataSource) {
super(Bundle.ViewSummaryInformationAction_name_text());
selectDataSource = selectedDataSource;
}
@Messages({"ViewSummaryInformationAction.window.title=Data Source Summary"})
@Override
public void actionPerformed(ActionEvent actionEvent) {
SwingUtilities.invokeLater(() -> {
String title = Bundle.ViewSummaryInformationAction_window_title();
Frame mainWindow = WindowManager.getDefault().getMainWindow();
dataSourceSummaryDialog = new JDialog(mainWindow, title, true);
DataSourceSummaryPanel dataSourceSummaryPanel = new DataSourceSummaryPanel();
//allow the buttons in DataSourceSummaryPanel to close this dialog
dataSourceSummaryPanel.addCloseButtonAction((ActionEvent event) -> {
dataSourceSummaryDialog.dispose();
});
//select the specifed data source
dataSourceSummaryPanel.selectDataSource(selectDataSource);
dataSourceSummaryDialog.add(dataSourceSummaryPanel);
dataSourceSummaryDialog.setResizable(true);
dataSourceSummaryDialog.pack();
dataSourceSummaryDialog.setLocationRelativeTo(mainWindow);
dataSourceSummaryDialog.setVisible(true);
dataSourceSummaryDialog.toFront();
});
}
}

View File

@ -48,6 +48,7 @@
<attr name="noIconInMenu" boolvalue="false"/>
</file>
<file name="org-sleuthkit-autopsy-casemodule-CasePropertiesAction.instance"/>
<file name="org-sleuthkit-autopsy-casemodule-datasourceSummary-DataSourceSummaryAction.instance"/>
<file name="org-sleuthkit-autopsy-casemodule-CaseDeleteAction.instance"/>
<file name="org-sleuthkit-autopsy-casemodule-CaseSaveAction.instance">
<attr name="delegate" newvalue="org.sleuthkit.autopsy.casemodule.CaseSaveAction"/>
@ -182,6 +183,10 @@
<attr name="originalFile" stringvalue="Actions/Case/org-sleuthkit-autopsy-casemodule-CasePropertiesAction.instance"/>
<attr name="position" intvalue="301"/>
</file>
<file name="org-sleuthkit-autopsy-casemodule-datasourceSummary-DataSourceSummaryAction.shadow">
<attr name="originalFile" stringvalue="Actions/Case/org-sleuthkit-autopsy-casemodule-datasourceSummary-DataSourceSummaryAction.instance"/>
<attr name="position" intvalue="302"/>
</file>
<file name="org-netbeans-modules-print-action-PageSetupAction.shadow_hidden"/>
<file name="org-netbeans-modules-print-action-PrintAction.shadow_hidden"/>
<file name="org-openide-actions-SaveAction.shadow_hidden"/>

View File

@ -34,6 +34,7 @@ import org.openide.util.NbBundle;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.casemodule.datasourceSummary.ViewSummaryInformationAction;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.directorytree.ExplorerNodeActionVisitor;
import org.sleuthkit.autopsy.directorytree.FileSearchAction;
@ -108,6 +109,7 @@ public class ImageNode extends AbstractContentNode<Image> {
actionsList.addAll(ExplorerNodeActionVisitor.getActions(content));
actionsList.add(new FileSearchAction(
Bundle.ImageNode_getActions_openFileSearchByAttr_text()));
actionsList.add(new ViewSummaryInformationAction(content.getId()));
actionsList.add(new RunIngestModulesAction(Collections.<Content>singletonList(content)));
actionsList.add(new NewWindowViewAction(
NbBundle.getMessage(this.getClass(), "ImageNode.getActions.viewInNewWin.text"), this));

View File

@ -23,6 +23,7 @@ import java.util.Collections;
import java.util.List;
import javax.swing.Action;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.datasourceSummary.ViewSummaryInformationAction;
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
import org.sleuthkit.autopsy.directorytree.ExtractAction;
import org.sleuthkit.autopsy.directorytree.FileSearchAction;
@ -63,6 +64,7 @@ public abstract class SpecialDirectoryNode extends AbstractAbstractFileNode<Spec
actions.add(null); // creates a menu separator
actions.add(new FileSearchAction(Bundle.ImageNode_getActions_openFileSearchByAttr_text()));
if (content.isDataSource()) {
actions.add(new ViewSummaryInformationAction(content.getId()));
actions.add(new RunIngestModulesAction(Collections.<Content>singletonList(content)));
} else {
actions.add(new RunIngestModulesAction(content));

View File

@ -0,0 +1,207 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2018-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.datamodel.utils;
import com.google.common.collect.ImmutableSet;
import static java.util.Arrays.asList;
import java.util.Collection;
import java.util.Collections;
import javax.imageio.ImageIO;
import static org.apache.commons.collections4.ListUtils.removeAll;
import org.openide.util.NbBundle;
/**
* Utilities for dealing with file/mime-types
*/
public final class FileTypeUtils {
private static final ImmutableSet<String> IMAGE_MIME_TYPES
= new ImmutableSet.Builder<String>()
.addAll(removeAll(asList(ImageIO.getReaderMIMETypes()),
asList("application/octet-stream"))) //this claims to be supported, but is not really an image.
.add("image/bmp", //NON-NLS
"image/gif", //NON-NLS
"image/jpeg", //NON-NLS
"image/png", //NON-NLS
"image/tiff", //NON-NLS
"image/vnd.adobe.photoshop", //NON-NLS
"image/x-raw-nikon", //NON-NLS
"image/x-ms-bmp", //NON-NLS
"image/x-icon", //NON-NLS
"image/webp", //NON-NLS
"image/vnd.microsoft.icon", //NON-NLS
"image/x-rgb", //NON-NLS
"image/x-ms-bmp", //NON-NLS
"image/x-xbitmap", //NON-NLS
"image/x-portable-graymap", //NON-NLS
"image/x-portable-bitmap" //NON-NLS
).build();
private static final ImmutableSet<String> AUDIO_MIME_TYPES
= new ImmutableSet.Builder<String>()
.add("audio/midi", //NON-NLS
"audio/mpeg", //NON-NLS
"audio/webm", //NON-NLS
"audio/ogg", //NON-NLS
"audio/wav", //NON-NLS
"audio/vnd.wave", //NON-NLS
"audio/x-ms-wma"//NON-NLS
).build();
private static final ImmutableSet<String> VIDEO_MIME_TYPES
= new ImmutableSet.Builder<String>()
.add("video/webm", //NON-NLS
"video/3gpp", //NON-NLS
"video/3gpp2", //NON-NLS
"video/ogg", //NON-NLS
"video/mpeg", //NON-NLS
"video/mp4", //NON-NLS
"video/quicktime", //NON-NLS
"video/x-msvideo", //NON-NLS
"video/x-flv", //NON-NLS
"video/x-m4v", //NON-NLS
"video/x-ms-wmv"//NON-NLS
).build();
private static final ImmutableSet<String> DOCUMENT_MIME_TYPES
= new ImmutableSet.Builder<String>()
.add("text/plain", //NON-NLS
"text/css", //NON-NLS
"text/html", //NON-NLS
"text/csv", //NON-NLS
"text/xml", //NON-NLS
"text/x-log", //NON-NLS
"application/rtf", //NON-NLS
"application/pdf", //NON-NLS
"application/json", //NON-NLS
"application/javascript", //NON-NLS
"application/xml", //NON-NLS
"application/x-msoffice", //NON-NLS
"application/x-ooxml", //NON-NLS
"application/msword", //NON-NLS
"application/msword2", //NON-NLS
"application/vnd.wordperfect", //NON-NLS
"application/vnd.openxmlformats-officedocument.wordprocessingml.document", //NON-NLS
"application/vnd.ms-powerpoint", //NON-NLS
"application/vnd.openxmlformats-officedocument.presentationml.presentation", //NON-NLS
"application/vnd.ms-excel", //NON-NLS
"application/vnd.ms-excel.sheet.4", //NON-NLS
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", //NON-NLS
"application/vnd.oasis.opendocument.presentation", //NON-NLS
"application/vnd.oasis.opendocument.spreadsheet", //NON-NLS
"application/vnd.oasis.opendocument.text" //NON-NLS
).build();
private static final ImmutableSet<String> EXECUTABLE_MIME_TYPES
= new ImmutableSet.Builder<String>()
.add("application/x-bat",//NON-NLS
"application/x-dosexec",//NON-NLS
"application/vnd.microsoft.portable-executable",//NON-NLS
"application/x-msdownload",//NON-NLS
"application/exe",//NON-NLS
"application/x-exe",//NON-NLS
"application/dos-exe",//NON-NLS
"vms/exe",//NON-NLS
"application/x-winexe",//NON-NLS
"application/msdos-windows",//NON-NLS
"application/x-msdos-program"//NON-NLS
).build();
private static final ImmutableSet<String> MULTI_MEDIA_MIME_TYPES
= new ImmutableSet.Builder<String>()
.addAll(IMAGE_MIME_TYPES)
.addAll(AUDIO_MIME_TYPES)
.addAll(VIDEO_MIME_TYPES)
.build();
private static final ImmutableSet<String> VISUAL_MEDIA_MIME_TYPES
= new ImmutableSet.Builder<String>()
.addAll(IMAGE_MIME_TYPES)
.addAll(VIDEO_MIME_TYPES)
.add("application/vnd.ms-asf", //NON-NLS
"application/vnd.rn-realmedia", //NON-NLS
"application/x-shockwave-flash" //NON-NLS
).build();
private FileTypeUtils() {
}
/**
* Enum of categories/groups of file types.
*/
@NbBundle.Messages({
"FileTypeCategory.Audio.displayName=Audio",
"FileTypeCategory.Video.displayName=Video",
"FileTypeCategory.Image.displayName=Image",
"FileTypeCategory.Media.displayName=Media",
"FileTypeCategory.Visual.displayName=Visual",
"FileTypeCategory.Documents.displayName=Documents",
"FileTypeCategory.Executables.displayName=Executables"})
public enum FileTypeCategory {
IMAGE(Bundle.FileTypeCategory_Image_displayName(),
IMAGE_MIME_TYPES,
Collections.emptyList()),
VIDEO(Bundle.FileTypeCategory_Video_displayName(),
VIDEO_MIME_TYPES,
Collections.emptyList()),
AUDIO(Bundle.FileTypeCategory_Audio_displayName(),
AUDIO_MIME_TYPES,
Collections.emptyList()),
/**
* Images, Videos, flash Animations, etc
*/
VISUAL(Bundle.FileTypeCategory_Media_displayName(),
VISUAL_MEDIA_MIME_TYPES,
Collections.emptyList()),
/**
* VISUAL plus AUDIO.
*/
MEDIA(Bundle.FileTypeCategory_Media_displayName(),
MULTI_MEDIA_MIME_TYPES,
Collections.emptyList()),
EXECUTABLE(Bundle.FileTypeCategory_Executables_displayName(),
EXECUTABLE_MIME_TYPES,
Collections.emptyList()),
/**
* (Plain) Text and "Office" documents.
*/
DOCUMENTS(Bundle.FileTypeCategory_Documents_displayName(),
DOCUMENT_MIME_TYPES,
Collections.emptyList());
private final String displayName;
private final ImmutableSet<String> mediaTypes;
private final ImmutableSet<String> extensions;
private FileTypeCategory(String displayName, Collection<String> mediaTypes, Collection<String> extensions) {
this.displayName = displayName;
this.mediaTypes = ImmutableSet.copyOf(mediaTypes);
this.extensions = ImmutableSet.copyOf(extensions);
}
public String getDisplayName() {
return displayName;
}
public ImmutableSet<String> getMediaTypes() {
return mediaTypes;
}
public ImmutableSet<String> getExtensions() {
throw new UnsupportedOperationException("This method is not implemented yet."); //just to be explicit.
}
}
}