Data source summary recent file panel

This commit is contained in:
Kelly Kelly 2020-09-02 10:44:54 -04:00
parent 71a896a494
commit f8aaa4bc25
8 changed files with 829 additions and 8 deletions

View File

@ -0,0 +1,399 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2020 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.datasourcesummary.datamodel;
import java.nio.file.Paths;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.SortedMap;
import java.util.TreeMap;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_RECENT_OBJECT;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.DataSource;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.autopsy.datasourcesummary.datamodel.SleuthkitCaseProvider.SleuthkitCaseProviderException;
/**
* Helper class for getting data for the Recent Files Data Summary tab.
*/
public class RecentFilesSummary {
private final static BlackboardAttribute.Type DATETIME_ACCESSED_ATT = new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED);
private final static BlackboardAttribute.Type DOMAIN_ATT = new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN);
private final static BlackboardAttribute.Type PATH_ATT = new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH);
private final static BlackboardAttribute.Type DATETIME_ATT = new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME);
private final static BlackboardAttribute.Type ASSOCATED_ATT = new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT);
private final static BlackboardAttribute.Type EMAIL_FROM_ATT = new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL_FROM);
private final static BlackboardArtifact.Type ASSOCATED_OBJ_ART = new BlackboardArtifact.Type(BlackboardArtifact.ARTIFACT_TYPE.TSK_ASSOCIATED_OBJECT);
private static final DateFormat DATETIME_FORMAT = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss", Locale.getDefault());
private final SleuthkitCaseProvider provider;
/**
* Default constructor.
*/
public RecentFilesSummary() {
this(SleuthkitCaseProvider.DEFAULT);
}
/**
* Construct object with given SleuthkitCaseProvider
*
* @param provider SleuthkitCaseProvider provider, cannot be null.
*/
public RecentFilesSummary(SleuthkitCaseProvider provider) {
if (provider == null) {
throw new IllegalArgumentException("Unable to construct RecentFileSummary object. SleuthkitCaseProvider cannot be null");
}
this.provider = provider;
}
/**
* Return a list of the most recently opened documents based on the
* TSK_RECENT_OBJECT artifact.
*
* @param dataSource The data source to query.
* @param maxCount The maximum number of results to return, pass 0 to get
* a list of all results.
*
* @return A list RecentFileDetails representing the most recently opened
* documents or an empty list if none were found.
*
* @throws SleuthkitCaseProviderException
* @throws TskCoreException
*/
public List<RecentFileDetails> getRecentlyOpenedDocuments(DataSource dataSource, int maxCount) throws SleuthkitCaseProviderException, TskCoreException {
if (dataSource == null) {
throw new IllegalArgumentException("Failed to get recently opened documents given data source was null");
}
List<BlackboardArtifact> artifactList
= DataSourceInfoUtilities.getArtifacts(provider.get(),
new BlackboardArtifact.Type(TSK_RECENT_OBJECT),
dataSource,
DATETIME_ATT,
DataSourceInfoUtilities.SortOrder.DESCENDING,
10);
List<RecentFileDetails> fileDetails = new ArrayList<>();
for (BlackboardArtifact artifact : artifactList) {
Long accessedTime = null;
String path = "";
// Get all the attributes in one call.
List<BlackboardAttribute> attributeList = artifact.getAttributes();
for (BlackboardAttribute attribute : attributeList) {
if (attribute.getAttributeType().equals(DATETIME_ATT)) {
accessedTime = attribute.getValueLong();
} else if (attribute.getAttributeType().equals(PATH_ATT)) {
path = attribute.getValueString();
}
if (accessedTime != null) {
fileDetails.add(new RecentFileDetails(path, accessedTime));
}
}
}
return fileDetails;
}
/**
* Return a list of the most recent downloads based on the value of the the
* artifact TSK_DATETIME_ACCESSED attribute.
*
* @param dataSource Data source to query.
* @param maxCount Maximum number of results to return, passing 0 will
* return all results.
*
* @return A list of RecentFileDetails objects or empty list if none were
* found.
*
* @throws TskCoreException
* @throws SleuthkitCaseProviderException
*/
public List<RecentDownloadDetails> getRecentDownloads(DataSource dataSource, int maxCount) throws TskCoreException, SleuthkitCaseProviderException {
List<BlackboardArtifact> artifactList
= DataSourceInfoUtilities.getArtifacts(provider.get(),
new BlackboardArtifact.Type(TSK_WEB_DOWNLOAD),
dataSource,
DATETIME_ACCESSED_ATT,
DataSourceInfoUtilities.SortOrder.DESCENDING,
maxCount);
List<RecentDownloadDetails> fileDetails = new ArrayList<>();
for (BlackboardArtifact artifact : artifactList) {
// Get all the attributes in one call.
Long accessedTime = null;
String domain = "";
String path = "";
List<BlackboardAttribute> attributeList = artifact.getAttributes();
for (BlackboardAttribute attribute : attributeList) {
if (attribute.getAttributeType().equals(DATETIME_ACCESSED_ATT)) {
accessedTime = attribute.getValueLong();
} else if (attribute.getAttributeType().equals(DOMAIN_ATT)) {
domain = attribute.getValueString();
} else if (attribute.getAttributeType().equals(PATH_ATT)) {
path = attribute.getValueString();
}
}
if (accessedTime != null) {
fileDetails.add(new RecentDownloadDetails(path, accessedTime, domain));
}
}
return fileDetails;
}
/**
* Returns a list of the most recent message attachments.
*
* @param dataSource Data source to query.
* @param maxCount Maximum number of results to return, passing 0 will
* return all results.
*
* @return A list of RecentFileDetails of the most recent attachments.
*
* @throws SleuthkitCaseProviderException
* @throws TskCoreException
*/
public List<RecentAttachmentDetails> getRecentAttachments(DataSource dataSource, int maxCount) throws SleuthkitCaseProviderException, TskCoreException {
return createListFromMap(buildAttachmentMap(dataSource), maxCount);
}
/**
* Build a map of all of the message attachment sorted in date order.
*
* @param dataSource Data source to query.
*
* @return Returns a SortedMap of details objects returned in descending
* order.
*
* @throws SleuthkitCaseProviderException
* @throws TskCoreException
*/
private SortedMap<Long, List<RecentAttachmentDetails>> buildAttachmentMap(DataSource dataSource) throws SleuthkitCaseProviderException, TskCoreException {
SleuthkitCase skCase = provider.get();
TreeMap<Long, List<RecentAttachmentDetails>> sortedMap = new TreeMap<>();
List<BlackboardArtifact> associatedArtifacts = skCase.getBlackboard().getArtifacts(ASSOCATED_OBJ_ART.getTypeID(), dataSource.getId());
for (BlackboardArtifact artifact : associatedArtifacts) {
BlackboardAttribute attribute = artifact.getAttribute(ASSOCATED_ATT);
if (attribute == null) {
continue;
}
BlackboardArtifact messageArtifact = skCase.getBlackboardArtifact(attribute.getValueLong());
if (isMessageArtifact(messageArtifact)) {
Content content = artifact.getParent();
if (content instanceof AbstractFile) {
String sender;
Long date;
String path;
BlackboardAttribute senderAttribute = messageArtifact.getAttribute(EMAIL_FROM_ATT);
if (senderAttribute != null) {
sender = senderAttribute.getValueString();
} else {
sender = "";
}
AbstractFile abstractFile = (AbstractFile) content;
date = abstractFile.getCrtime();
path = Paths.get(abstractFile.getParentPath(), abstractFile.getName()).toString();
List<RecentAttachmentDetails> list = sortedMap.get(date);
if (list == null) {
list = new ArrayList<>();
sortedMap.put(date, list);
}
list.add(new RecentAttachmentDetails(path, date, sender));
}
}
}
return sortedMap.descendingMap();
}
/**
* Create a list of detail objects from the given sorted map of the max
* size.
*
* @param sortedMap A Map of attachment details sorted by date.
* @param maxCount Maximum number of values to return.
*
* @return A list of the details of the most recent attachments or empty
* list if none where found.
*/
private List<RecentAttachmentDetails> createListFromMap(SortedMap<Long, List<RecentAttachmentDetails>> sortedMap, int maxCount) {
List<RecentAttachmentDetails> fileList = new ArrayList<>();
for (List<RecentAttachmentDetails> mapList : sortedMap.values()) {
if (maxCount == 0 || fileList.size() + mapList.size() <= maxCount) {
fileList.addAll(mapList);
continue;
}
if (maxCount == fileList.size()) {
break;
}
for (RecentAttachmentDetails details : mapList) {
if (fileList.size() < maxCount) {
fileList.add(details);
} else {
break;
}
}
}
return fileList;
}
/**
* Is the given artifact a message.
*
* @param nodeArtifact An artifact that might be a message. Must not be
* null.
*
* @return True if the given artifact is a message artifact
*/
private boolean isMessageArtifact(BlackboardArtifact nodeArtifact) {
final int artifactTypeID = nodeArtifact.getArtifactTypeID();
return artifactTypeID == TSK_EMAIL_MSG.getTypeID()
|| artifactTypeID == TSK_MESSAGE.getTypeID();
}
/**
* General data model object for files object.
*/
public static class RecentFileDetails {
private final String path;
private final long date;
/**
* Constructor for files with just a path and date.
*
* @param path File path.
* @param date File access date\time in seconds with java epoch
*/
RecentFileDetails(String path, long date) {
this.path = path;
this.date = date;
}
/**
* Returns the formatted date because the JTablePanel render assumes
* only string data.
*
* @return Formatted date time.
*/
public String getDate() {
return DATETIME_FORMAT.format(date * 1000);
}
/**
* Returns the file path.
*
* @return The file path.
*/
public String getPath() {
return path;
}
}
/**
* Data model for recently downloaded files.
*/
public static class RecentDownloadDetails extends RecentFileDetails {
private final String webDomain;
/**
* Constructor for files with just a path and date.
*
* @param path File path.
* @param date File access date\time in seconds with java epoch.
* @param webDomain The webdomain from which the file was downloaded.
*/
RecentDownloadDetails(String path, long date, String webDomain) {
super(path, date);
this.webDomain = webDomain;
}
/**
* Returns the web domain.
*
* @return The web domain or empty string if not available or
* applicable.
*/
public String getWebDomain() {
return webDomain;
}
}
/**
* Data model for recently attachments.
*/
public static class RecentAttachmentDetails extends RecentFileDetails {
private final String sender;
/**
* Constructor for recent download files which have a path, date and
* domain value.
*
* @param path File path.
* @param date File crtime.
* @param sender The sender of the message from which the
* file was attached.
*/
RecentAttachmentDetails(String path, long date, String sender) {
super(path, date);
this.sender = sender;
}
/**
* Return the sender of the attached file.
*
* @return The sender of the attached file or empty string if not
* available.
*/
public String getSender() {
return sender;
}
}
}

View File

@ -37,3 +37,6 @@ DataSourceSummaryCountsPanel.byCategoryLabel.text=Files by Category
DataSourceSummaryCountsPanel.resultsByTypeLabel.text=Results by Type DataSourceSummaryCountsPanel.resultsByTypeLabel.text=Results by Type
DataSourceSummaryUserActivityPanel.programsRunLabel.text=Recent Programs DataSourceSummaryUserActivityPanel.programsRunLabel.text=Recent Programs
DataSourceSummaryUserActivityPanel.recentDomainsLabel.text=Recent Domains DataSourceSummaryUserActivityPanel.recentDomainsLabel.text=Recent Domains
RecentFilesPanel.openDocsLabel.text=Recently Opened Documents
RecentFilesPanel.downloadLabel.text=Recent Downloads
RecentFilesPanel.attachmentLabel.text=Recent Attachements

View File

@ -72,6 +72,7 @@ DataSourceSummaryNode.viewDataSourceAction.text=Go to Data Source
DataSourceSummaryTabbedPane_countsTab_title=Counts DataSourceSummaryTabbedPane_countsTab_title=Counts
DataSourceSummaryTabbedPane_detailsTab_title=Details DataSourceSummaryTabbedPane_detailsTab_title=Details
DataSourceSummaryTabbedPane_ingestHistoryTab_title=Ingest History DataSourceSummaryTabbedPane_ingestHistoryTab_title=Ingest History
DataSourceSummaryTabbedPane_recentFileTab_title=Recent Files
DataSourceSummaryTabbedPane_userActivityTab_title=User Activity DataSourceSummaryTabbedPane_userActivityTab_title=User Activity
DataSourceSummaryUserActivityPanel.programsRunLabel.text=Recent Programs DataSourceSummaryUserActivityPanel.programsRunLabel.text=Recent Programs
DataSourceSummaryUserActivityPanel.recentDomainsLabel.text=Recent Domains DataSourceSummaryUserActivityPanel.recentDomainsLabel.text=Recent Domains
@ -84,4 +85,12 @@ DataSourceSummaryUserActivityPanel_TopProgramsTableModel_count_header=Run Times
DataSourceSummaryUserActivityPanel_TopProgramsTableModel_folder_header=Folder DataSourceSummaryUserActivityPanel_TopProgramsTableModel_folder_header=Folder
DataSourceSummaryUserActivityPanel_TopProgramsTableModel_lastrun_header=Last Run DataSourceSummaryUserActivityPanel_TopProgramsTableModel_lastrun_header=Last Run
DataSourceSummaryUserActivityPanel_TopProgramsTableModel_name_header=Program DataSourceSummaryUserActivityPanel_TopProgramsTableModel_name_header=Program
RecentFilePanel_col_header_domain=Domain
RecentFilePanel_col_header_path=Path
RecentFilePanel_col_header_sender=Sender
RecentFilePanel_no_open_documents=No recently open documents found.
RecentFilesPanel.openDocsLabel.text=Recently Opened Documents
RecentFilesPanel.downloadLabel.text=Recent Downloads
RecentFilesPanel.attachmentLabel.text=Recent Attachements
RecentFilesPanel_col_head_date=Date
ViewSummaryInformationAction.name.text=View Summary Information ViewSummaryInformationAction.name.text=View Summary Information

View File

@ -35,7 +35,8 @@ import org.sleuthkit.datamodel.DataSource;
"DataSourceSummaryTabbedPane_countsTab_title=Counts", "DataSourceSummaryTabbedPane_countsTab_title=Counts",
"DataSourceSummaryTabbedPane_detailsTab_title=Details", "DataSourceSummaryTabbedPane_detailsTab_title=Details",
"DataSourceSummaryTabbedPane_userActivityTab_title=User Activity", "DataSourceSummaryTabbedPane_userActivityTab_title=User Activity",
"DataSourceSummaryTabbedPane_ingestHistoryTab_title=Ingest History" "DataSourceSummaryTabbedPane_ingestHistoryTab_title=Ingest History",
"DataSourceSummaryTabbedPane_recentFileTab_title=Recent Files"
}) })
public class DataSourceSummaryTabbedPane extends JTabbedPane { public class DataSourceSummaryTabbedPane extends JTabbedPane {
@ -45,7 +46,8 @@ public class DataSourceSummaryTabbedPane extends JTabbedPane {
private final List<Pair<String, BaseDataSourceSummaryPanel>> tabs = Arrays.asList( private final List<Pair<String, BaseDataSourceSummaryPanel>> tabs = Arrays.asList(
Pair.of(Bundle.DataSourceSummaryTabbedPane_detailsTab_title(), new DataSourceSummaryDetailsPanel()), Pair.of(Bundle.DataSourceSummaryTabbedPane_detailsTab_title(), new DataSourceSummaryDetailsPanel()),
Pair.of(Bundle.DataSourceSummaryTabbedPane_countsTab_title(), new DataSourceSummaryCountsPanel()), Pair.of(Bundle.DataSourceSummaryTabbedPane_countsTab_title(), new DataSourceSummaryCountsPanel()),
Pair.of(Bundle.DataSourceSummaryTabbedPane_detailsTab_title(), new DataSourceSummaryUserActivityPanel()) Pair.of(Bundle.DataSourceSummaryTabbedPane_userActivityTab_title(), new DataSourceSummaryUserActivityPanel()),
Pair.of(Bundle.DataSourceSummaryTabbedPane_recentFileTab_title(), new RecentFilesPanel())
); );
private final IngestJobInfoPanel ingestHistoryPanel = new IngestJobInfoPanel(); private final IngestJobInfoPanel ingestHistoryPanel = new IngestJobInfoPanel();

View File

@ -0,0 +1,92 @@
<?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"/>
<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>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
<SubComponents>
<Container class="javax.swing.JPanel" name="openedDocPane">
<AuxValues>
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new JTablePanel&lt;RecentFileDetails&gt;()"/>
</AuxValues>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="1" gridWidth="1" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="5" insetsLeft="5" insetsBottom="0" insetsRight="5" anchor="11" weightX="1.0" weightY="1.0"/>
</Constraint>
</Constraints>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignFlowLayout"/>
</Container>
<Container class="javax.swing.JPanel" name="downloadsPane">
<AuxValues>
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new JTablePanel&lt;RecentDownloadDetails&gt;()"/>
</AuxValues>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="3" gridWidth="1" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="5" insetsLeft="5" insetsBottom="0" insetsRight="5" anchor="11" weightX="1.0" weightY="1.0"/>
</Constraint>
</Constraints>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignFlowLayout"/>
</Container>
<Container class="javax.swing.JPanel" name="attachmentsPane">
<AuxValues>
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new JTablePanel&lt;RecentAttachmentDetails&gt;()"/>
</AuxValues>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="5" gridWidth="1" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="5" insetsLeft="5" insetsBottom="10" insetsRight="5" anchor="11" weightX="1.0" weightY="1.0"/>
</Constraint>
</Constraints>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignFlowLayout"/>
</Container>
<Component class="javax.swing.JLabel" name="openDocsLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties" key="RecentFilesPanel.openDocsLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="10" insetsLeft="5" insetsBottom="0" insetsRight="5" anchor="11" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JLabel" name="downloadLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties" key="RecentFilesPanel.downloadLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="2" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="15" insetsLeft="5" insetsBottom="0" insetsRight="5" anchor="10" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JLabel" name="attachmentLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/datasourcesummary/ui/Bundle.properties" key="RecentFilesPanel.attachmentLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="4" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="15" insetsLeft="5" insetsBottom="0" insetsRight="5" anchor="11" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
</SubComponents>
</Form>

View File

@ -0,0 +1,294 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2020 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.datasourcesummary.ui;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary;
import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary.RecentAttachmentDetails;
import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary.RecentDownloadDetails;
import org.sleuthkit.autopsy.datasourcesummary.datamodel.RecentFilesSummary.RecentFileDetails;
import org.sleuthkit.autopsy.datasourcesummary.uiutils.CellModelTableCellRenderer.DefaultCellModel;
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchResult;
import org.sleuthkit.autopsy.datasourcesummary.uiutils.DataFetchWorker;
import org.sleuthkit.autopsy.datasourcesummary.uiutils.JTablePanel;
import org.sleuthkit.autopsy.datasourcesummary.uiutils.JTablePanel.ColumnModel;
import org.sleuthkit.autopsy.datasourcesummary.uiutils.ListTableModel;
import org.sleuthkit.datamodel.DataSource;
/**
* Data Source Summary recent files panel.
*/
public final class RecentFilesPanel extends BaseDataSourceSummaryPanel {
private static final long serialVersionUID = 1L;
private final List<JTablePanel<?>> tablePanelList = new ArrayList<>();
private final List<DataFetchWorker.DataFetchComponents<DataSource, ?>> dataFetchComponents = new ArrayList<>();
private final RecentFilesSummary dataHandler;
@Messages({
"RecentFilesPanel_col_head_date=Date",
"RecentFilePanel_col_header_domain=Domain",
"RecentFilePanel_col_header_path=Path",
"RecentFilePanel_col_header_sender=Sender"
})
/**
* Default constructor.
*/
public RecentFilesPanel() {
this(new RecentFilesSummary());
}
/**
* Creates new form RecentFilesPanel
*/
public RecentFilesPanel(RecentFilesSummary dataHandler) {
this.dataHandler = dataHandler;
initComponents();
initalizeTables();
}
@Override
protected void onNewDataSource(DataSource dataSource) {
// if no data source is present or the case is not open,
// set results for tables to null.
if (dataSource == null || !Case.isCaseOpen()) {
this.dataFetchComponents.forEach((item) -> item.getResultHandler()
.accept(DataFetchResult.getSuccessResult(null)));
} else {
// set tables to display loading screen
tablePanelList.forEach((table) -> table.showDefaultLoadingMessage());
// create swing workers to run for each table
List<DataFetchWorker<?, ?>> workers = dataFetchComponents
.stream()
.map((components) -> new DataFetchWorker<>(components, dataSource))
.collect(Collectors.toList());
// submit swing workers to run
submit(workers);
}
}
/**
* Setup the data model and columns for the panel tables.
*/
private void initalizeTables() {
initalizeOpenDocsTable();
initalizeDownloadTable();
initalizeAttchementsTable();
}
@Messages({
"RecentFilePanel_no_open_documents=No recently open documents found."
})
/**
* Setup the data model and columns for the recently open table.
*/
@SuppressWarnings("unchecked")
private void initalizeOpenDocsTable() {
List<ColumnModel<RecentFileDetails>> list = Arrays.asList(
new ColumnModel<>(Bundle.RecentFilePanel_col_header_path(),
(prog) -> {
return new DefaultCellModel(prog.getPath());
}, 250),
new ColumnModel<>(Bundle.RecentFilesPanel_col_head_date(),
(prog) -> {
return new DefaultCellModel(prog.getDate());
}, 80));
ListTableModel<RecentFileDetails> tableModel = JTablePanel.getTableModel(list);
JTablePanel<RecentFileDetails> pane = (JTablePanel<RecentFileDetails>) openedDocPane;
pane.setModel(tableModel);
pane.setColumnModel(JTablePanel.getTableColumnModel(list));
tablePanelList.add(pane);
DataFetchWorker.DataFetchComponents<DataSource, List<RecentFileDetails>> worker
= new DataFetchWorker.DataFetchComponents<>(
(dataSource) -> dataHandler.getRecentlyOpenedDocuments(dataSource, 10),
(result) -> pane.showDataFetchResult(result, JTablePanel.getDefaultErrorMessage(),
Bundle.RecentFilePanel_no_open_documents()));
dataFetchComponents.add(worker);
}
/**
* Setup the data model and columns for the recent download table.
*/
@SuppressWarnings("unchecked")
private void initalizeDownloadTable() {
List<ColumnModel<RecentDownloadDetails>> list = Arrays.asList(
new ColumnModel<>(Bundle.RecentFilePanel_col_header_domain(),
(prog) -> {
return new DefaultCellModel(prog.getWebDomain());
}, 100),
new ColumnModel<>(Bundle.RecentFilePanel_col_header_path(),
(prog) -> {
return new DefaultCellModel(prog.getPath());
}, 250),
new ColumnModel<>(Bundle.RecentFilesPanel_col_head_date(),
(prog) -> {
return new DefaultCellModel(prog.getDate());
}, 80));
ListTableModel<RecentDownloadDetails> tableModel = JTablePanel.getTableModel(list);
JTablePanel<RecentDownloadDetails> pane = (JTablePanel<RecentDownloadDetails>) downloadsPane;
pane.setModel(tableModel);
pane.setColumnModel(JTablePanel.getTableColumnModel(list));
tablePanelList.add(pane);
DataFetchWorker.DataFetchComponents<DataSource, List<RecentDownloadDetails>> worker
= new DataFetchWorker.DataFetchComponents<>(
(dataSource) -> dataHandler.getRecentDownloads(dataSource, 10),
(result) -> pane.showDataFetchResult(result, JTablePanel.getDefaultErrorMessage(),
Bundle.RecentFilePanel_no_open_documents()));
dataFetchComponents.add(worker);
}
/**
* Setup the data model and columns for the recent attachments.
*/
@SuppressWarnings("unchecked")
private void initalizeAttchementsTable() {
List<ColumnModel<RecentAttachmentDetails>> list = Arrays.asList(
new ColumnModel<>(Bundle.RecentFilePanel_col_header_path(),
(prog) -> {
return new DefaultCellModel(prog.getPath());
}, 250),
new ColumnModel<>(Bundle.RecentFilesPanel_col_head_date(),
(prog) -> {
return new DefaultCellModel(prog.getDate());
}, 80),
new ColumnModel<>(Bundle.RecentFilePanel_col_header_sender(),
(prog) -> {
return new DefaultCellModel(prog.getSender());
}, 150));
ListTableModel<RecentAttachmentDetails> tableModel = JTablePanel.getTableModel(list);
JTablePanel<RecentAttachmentDetails> pane = (JTablePanel<RecentAttachmentDetails>) attachmentsPane;
pane.setModel(tableModel);
pane.setColumnModel(JTablePanel.getTableColumnModel(list));
tablePanelList.add(pane);
DataFetchWorker.DataFetchComponents<DataSource, List<RecentAttachmentDetails>> worker
= new DataFetchWorker.DataFetchComponents<>(
(dataSource) -> dataHandler.getRecentAttachments(dataSource, 10),
(result) -> pane.showDataFetchResult(result, JTablePanel.getDefaultErrorMessage(),
Bundle.RecentFilePanel_no_open_documents()));
dataFetchComponents.add(worker);
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
java.awt.GridBagConstraints gridBagConstraints;
openedDocPane = new JTablePanel<RecentFileDetails>();
downloadsPane = new JTablePanel<RecentDownloadDetails>();
attachmentsPane = new JTablePanel<RecentAttachmentDetails>();
openDocsLabel = new javax.swing.JLabel();
downloadLabel = new javax.swing.JLabel();
attachmentLabel = new javax.swing.JLabel();
setLayout(new java.awt.GridBagLayout());
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 1.0;
gridBagConstraints.insets = new java.awt.Insets(5, 5, 0, 5);
add(openedDocPane, gridBagConstraints);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 3;
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 1.0;
gridBagConstraints.insets = new java.awt.Insets(5, 5, 0, 5);
add(downloadsPane, gridBagConstraints);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 5;
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 1.0;
gridBagConstraints.insets = new java.awt.Insets(5, 5, 10, 5);
add(attachmentsPane, gridBagConstraints);
org.openide.awt.Mnemonics.setLocalizedText(openDocsLabel, org.openide.util.NbBundle.getMessage(RecentFilesPanel.class, "RecentFilesPanel.openDocsLabel.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH;
gridBagConstraints.insets = new java.awt.Insets(10, 5, 0, 5);
add(openDocsLabel, gridBagConstraints);
org.openide.awt.Mnemonics.setLocalizedText(downloadLabel, org.openide.util.NbBundle.getMessage(RecentFilesPanel.class, "RecentFilesPanel.downloadLabel.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 2;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.insets = new java.awt.Insets(15, 5, 0, 5);
add(downloadLabel, gridBagConstraints);
org.openide.awt.Mnemonics.setLocalizedText(attachmentLabel, org.openide.util.NbBundle.getMessage(RecentFilesPanel.class, "RecentFilesPanel.attachmentLabel.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 4;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH;
gridBagConstraints.insets = new java.awt.Insets(15, 5, 0, 5);
add(attachmentLabel, gridBagConstraints);
}// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JLabel attachmentLabel;
private javax.swing.JPanel attachmentsPane;
private javax.swing.JLabel downloadLabel;
private javax.swing.JPanel downloadsPane;
private javax.swing.JLabel openDocsLabel;
private javax.swing.JPanel openedDocPane;
// End of variables declaration//GEN-END:variables
}

View File

@ -98,6 +98,7 @@ public class CellModelTableCellRenderer extends DefaultTableCellRenderer {
*/ */
public DefaultCellModel(String text) { public DefaultCellModel(String text) {
this.text = text; this.text = text;
this.setTooltip(text);
} }
@Override @Override

View File

@ -231,7 +231,7 @@ public class JTablePanel<T> extends JPanel {
.map((colModel) -> colModel.getCellRenderer()) .map((colModel) -> colModel.getCellRenderer())
.collect(Collectors.toList()); .collect(Collectors.toList());
return new DefaultListTableModel<T>(columnRenderers); return new DefaultListTableModel<>(columnRenderers);
} }
/** /**
@ -264,26 +264,47 @@ public class JTablePanel<T> extends JPanel {
private final JScrollPane tableScrollPane; private final JScrollPane tableScrollPane;
private final Overlay overlayLayer; private final Overlay overlayLayer;
private final ListTableModel<T> tableModel; private ListTableModel<T> tableModel;
private final JTable table; private final JTable table;
/** /**
* Main constructor. * Panel constructor.
* *
* @param tableModel The model to use for the table. * @param tableModel The model to use for the table.
*/ */
public JTablePanel(ListTableModel<T> tableModel) { public JTablePanel(ListTableModel<T> tableModel) {
this.tableModel = tableModel; this();
this.table = new JTable(tableModel); setModel(tableModel);
}
/**
* Default constructor.
*/
public JTablePanel() {
this.table = new JTable();
this.table.getTableHeader().setReorderingAllowed(false); this.table.getTableHeader().setReorderingAllowed(false);
this.overlayLayer = new Overlay(); this.overlayLayer = new Overlay();
this.tableScrollPane = new JScrollPane(table); this.tableScrollPane = new JScrollPane(table);
JLayer<JComponent> dualLayer = new JLayer<JComponent>(tableScrollPane, overlayLayer); JLayer<JComponent> dualLayer = new JLayer<>(tableScrollPane, overlayLayer);
setLayout(new BorderLayout()); setLayout(new BorderLayout());
add(dualLayer, BorderLayout.CENTER); add(dualLayer, BorderLayout.CENTER);
} }
/**
* Set the table model.
*
* @param tableModel
*/
public void setModel(ListTableModel<T> tableModel) {
if (tableModel == null) {
throw new IllegalArgumentException("Null table model passed to setModel");
}
this.tableModel = tableModel;
table.setModel(tableModel);
}
/** /**
* @return The underlying JTable's column model. * @return The underlying JTable's column model.
*/ */