mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-16 17:57:43 +00:00
merged in develop
This commit is contained in:
commit
4d394710d7
@ -110,11 +110,11 @@
|
||||
<target name="getTestDataFiles">
|
||||
<mkdir dir="${basedir}/test/qa-functional/data"/>
|
||||
<get src="https://drive.google.com/uc?id=1FkinvA7EFqP4nOSOyTAOli5KefM67ufA" dest="${test-input}/EmbeddedIM_img1_v2.vhd" skipexisting="true"/>
|
||||
<get src="https://drive.google.com/uc?id=1JACMDyH4y54ypGzFWl82ZzMQf3qbrioP" dest="${test-input}/BitlockerDetection_img1_v1.vhd" skipexisting="true"/>
|
||||
<get src="https://drive.google.com/uc?id=17sGybvmBGsWWJYo1IWKmO04oG9hKpPi3" dest="${test-input}/SqlCipherDetection_img1_v1.vhd" skipexisting="true"/>
|
||||
<get src="https://drive.google.com/uc?id=1zPlIn1xmOeC1VYKmV3fJHl5qE6E_M7K-" dest="${test-input}/BitlockerDetection_img1_v1.vhd" skipexisting="true"/>
|
||||
<get src="https://drive.google.com/uc?id=1brQqmX8MJnBPUFEbsdUvZ1X81PmQNVCY" dest="${test-input}/SqlCipherDetection_img1_v1.vhd" skipexisting="true"/>
|
||||
<get src="https://drive.google.com/uc?id=0BxdBkzm5VKGNT0dGY0dqcHVsU3M" dest="${test-input}/IngestFilters_img1_v1.img" skipexisting="true"/>
|
||||
<get src="https://drive.google.com/uc?id=1bghoSm7z7nhmGIxlllyY1MMlbLntxm7n" dest="${test-input}/IngestFilters_local1_v1.zip" skipexisting="true"/>
|
||||
<get src="https://drive.google.com/uc?id=1BrSiUQ1fzxFS9vIaK4mYKX6qIVp9kRWT" dest="${test-input}/PasswordDetection_img1_v1.img" skipexisting="true"/>
|
||||
<get src="https://drive.google.com/uc?id=1Ovyv_xVty8xMYgsc3C45pvphfhbdKg1x" dest="${test-input}/PasswordDetection_img1_v1.img" skipexisting="true"/>
|
||||
<get src="https://drive.google.com/uc?id=1HD8s4rculgHV1qZT5g80Kg7j4m1qccrN" dest="${test-input}/VeracryptDetection_img1_v1.vhd" skipexisting="true"/>
|
||||
<get src="https://drive.google.com/uc?id=1mr9waEDG5H8GBBn_yXwMUQ6senwC1goL" dest="${test-input}/CommonFiles_img1_v1.vhd" skipexisting="true"/>
|
||||
<get src="https://drive.google.com/uc?id=1-vmbmAAb2HBLbf58GpAA97ozGUFiYHbN" dest="${test-input}/CommonFiles_img2_v1.vhd" skipexisting="true"/>
|
||||
|
@ -231,15 +231,10 @@ AddImageWizardIngestConfigPanel.dsProcDone.errs.text=*Errors encountered in addi
|
||||
AddImageWizardIngestConfigVisual.getName.text=Configure Ingest Modules
|
||||
AddImageWizardIterator.stepXofN=Step {0} of {1}
|
||||
AddLocalFilesTask.localFileAdd.progress.text=Adding: {0}/{1}
|
||||
Case.getCurCase.exception.noneOpen=Cannot get the current case; there is no case open\!
|
||||
Case.getCurCase.exception.noneOpen=Cannot get the current case; there is no case open!
|
||||
Case.open.msgDlg.updated.msg=Updated case database schema.\nA backup copy of the database with the following path has been made:\n {0}
|
||||
Case.open.msgDlg.updated.title=Case Database Schema Update
|
||||
Case.checkImgExist.confDlg.doesntExist.msg=One of the images associated with \n\
|
||||
this case are missing. Would you like to search for them now?\n\
|
||||
Previously, the image was located at:\n\
|
||||
{0}\n\
|
||||
Please note that you will still be able to browse directories and generate reports\n\
|
||||
if you choose No, but you will not be able to view file content or run the ingest process.
|
||||
Case.checkImgExist.confDlg.doesntExist.msg=One of the images associated with \nthis case are missing. Would you like to search for them now?\nPreviously, the image was located at:\n{0}\nPlease note that you will still be able to browse directories and generate reports\nif you choose No, but you will not be able to view file content or run the ingest process.
|
||||
Case.checkImgExist.confDlg.doesntExist.title=Missing Image
|
||||
Case.addImg.exception.msg=Error adding image to the case
|
||||
Case.updateCaseName.exception.msg=Error while trying to update the case name.
|
||||
@ -258,12 +253,9 @@ Case.GetCaseTypeGivenPath.Failure=Unable to get case type
|
||||
Case.metaDataFileCorrupt.exception.msg=The case metadata file (.aut) is corrupted.
|
||||
Case.deleteReports.deleteFromDiskException.log.msg=Unable to delete the report from the disk.
|
||||
Case.deleteReports.deleteFromDiskException.msg=Unable to delete the report {0} from the disk.\nYou may manually delete it from {1}
|
||||
CaseDeleteAction.closeConfMsg.text=Are you sure want to close and delete this case? \n\
|
||||
Case Name: {0}\n\
|
||||
Case Directory: {1}
|
||||
CaseDeleteAction.closeConfMsg.text=Are you sure want to close and delete this case? \nCase Name: {0}\nCase Directory: {1}
|
||||
CaseDeleteAction.closeConfMsg.title=Warning: Closing the Current Case
|
||||
CaseDeleteAction.msgDlg.fileInUse.msg=The delete action cannot be fully completed because the folder or file in it is open by another program.\n\n\
|
||||
Close the folder and file and try again or you can delete the case manually.
|
||||
CaseDeleteAction.msgDlg.fileInUse.msg=The delete action cannot be fully completed because the folder or file in it is open by another program.\n\nClose the folder and file and try again or you can delete the case manually.
|
||||
CaseDeleteAction.msgDlg.fileInUse.title=Error: Folder In Use
|
||||
CaseDeleteAction.msgDlg.caseDelete.msg=Case {0} has been deleted.
|
||||
CaseOpenAction.autFilter.title={0} Case File ( {1})
|
||||
@ -295,8 +287,7 @@ NewCaseWizardAction.databaseProblem1.text=Cannot open database. Cancelling case
|
||||
NewCaseWizardAction.databaseProblem2.text=Error
|
||||
NewCaseWizardPanel1.validate.errMsg.invalidSymbols=The Case Name cannot contain any of the following symbols: \\ / : * ? " < > |
|
||||
NewCaseWizardPanel1.validate.errMsg.dirExists=Case directory ''{0}'' already exists.
|
||||
NewCaseWizardPanel1.validate.confMsg.createDir.msg=The base directory "{0}" does not exist. \n\n\
|
||||
Do you want to create that directory?
|
||||
NewCaseWizardPanel1.validate.confMsg.createDir.msg=The base directory "{0}" does not exist. \n\nDo you want to create that directory?
|
||||
NewCaseWizardPanel1.validate.confMsg.createDir.title=Create directory
|
||||
NewCaseWizardPanel1.validate.errMsg.cantCreateParDir.msg=Error: Could not create case parent directory {0}
|
||||
NewCaseWizardPanel1.validate.errMsg.prevCreateBaseDir.msg=Prevented from creating base directory {0}
|
||||
@ -332,7 +323,6 @@ StartupWindow.title.text=Welcome
|
||||
UnpackagePortableCaseDialog.title.text=Unpackage Portable Case
|
||||
UnpackagePortableCaseDialog.UnpackagePortableCaseDialog.extensions=Portable case package (.zip, .zip.001)
|
||||
UnpackagePortableCaseDialog.validatePaths.badExtension=File extension must be .zip or .zip.001
|
||||
# {0} - case folder
|
||||
UnpackagePortableCaseDialog.validatePaths.caseFolderExists=Folder {0} already exists
|
||||
UnpackagePortableCaseDialog.validatePaths.caseIsNotFile=Selected path is not a file
|
||||
UnpackagePortableCaseDialog.validatePaths.caseNotFound=File does not exist
|
||||
@ -346,15 +336,15 @@ UnpackageWorker.doInBackground.errorFinding7zip=Could not locate 7-Zip executabl
|
||||
UpdateRecentCases.menuItem.clearRecentCases.text=Clear Recent Cases
|
||||
UpdateRecentCases.menuItem.empty=-Empty-
|
||||
AddImageWizardIngestConfigPanel.CANCEL_BUTTON.text=Cancel
|
||||
NewCaseVisualPanel1.CaseFolderOnCDriveError.text=Warning: Path to multi-user case folder is on \"C:\" drive
|
||||
NewCaseVisualPanel1.CaseFolderOnInternalDriveWindowsError.text=Warning: Path to case folder is on \"C:\" drive. Case folder is created on the target system
|
||||
NewCaseVisualPanel1.CaseFolderOnCDriveError.text=Warning: Path to multi-user case folder is on "C:" drive
|
||||
NewCaseVisualPanel1.CaseFolderOnInternalDriveWindowsError.text=Warning: Path to case folder is on "C:" drive. Case folder is created on the target system
|
||||
NewCaseVisualPanel1.CaseFolderOnInternalDriveLinuxError.text=Warning: Path to case folder is on the target system. Create case folder in mounted drive.
|
||||
CollaborationMonitor.addingDataSourceStatus.msg={0} adding data source
|
||||
CollaborationMonitor.analyzingDataSourceStatus.msg={0} analyzing {1}
|
||||
MissingImageDialog.lbWarning.text=
|
||||
MissingImageDialog.lbWarning.toolTipText=
|
||||
NewCaseVisualPanel1.caseParentDirWarningLabel.text=
|
||||
NewCaseVisualPanel1.multiUserCaseRadioButton.text=Multi-user
|
||||
NewCaseVisualPanel1.multiUserCaseRadioButton.text=Multi-user\t\t
|
||||
NewCaseVisualPanel1.singleUserCaseRadioButton.text=Single-user
|
||||
NewCaseVisualPanel1.caseTypeLabel.text=Case Type:
|
||||
SingleUserCaseConverter.BadDatabaseFileName=Database file does not exist!
|
||||
|
@ -5,10 +5,7 @@ CentralRepoCommentDialog.title.addEditCentralRepoComment=Add/Edit Central Reposi
|
||||
OpenIDE-Module-Name=Central Repository
|
||||
OpenIDE-Module-Display-Category=Ingest Module
|
||||
OpenIDE-Module-Short-Description=Correlation Engine Ingest Module
|
||||
OpenIDE-Module-Long-Description=\
|
||||
Correlation Engine ingest module and central database. \n\n\
|
||||
The Correlation Engine ingest module stores attributes of artifacts matching selected correlation types into a central database.\n\
|
||||
Stored attributes are used in future cases to correlate and analyzes files and artifacts during ingest.
|
||||
OpenIDE-Module-Long-Description=Correlation Engine ingest module and central database. \n\nThe Correlation Engine ingest module stores attributes of artifacts matching selected correlation types into a central database.\nStored attributes are used in future cases to correlate and analyzes files and artifacts during ingest.
|
||||
CentralRepoCommentDialog.commentLabel.text=Comment:
|
||||
CentralRepoCommentDialog.okButton.text=&OK
|
||||
CentralRepoCommentDialog.cancelButton.text=C&ancel
|
||||
|
@ -1,88 +0,0 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2017 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.communications;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import org.openide.nodes.AbstractNode;
|
||||
import org.openide.nodes.ChildFactory;
|
||||
import org.openide.nodes.Children;
|
||||
import org.openide.nodes.Node;
|
||||
import org.python.google.common.collect.Iterables;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.datamodel.AccountDeviceInstance;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.CommunicationsFilter;
|
||||
import org.sleuthkit.datamodel.CommunicationsManager;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* 'Root' Node for the Account/Messages area. Has children which are all the
|
||||
* relationships of all the accounts in this node.
|
||||
*
|
||||
*/
|
||||
final class AccountDetailsNode extends AbstractNode {
|
||||
|
||||
private final static Logger logger = Logger.getLogger(AccountDetailsNode.class.getName());
|
||||
|
||||
AccountDetailsNode(Set<AccountDeviceInstance> accountDeviceInstances, CommunicationsFilter filter, CommunicationsManager commsManager) {
|
||||
super(Children.create(new AccountRelationshipChildren(accountDeviceInstances, commsManager, filter), true));
|
||||
String displayName = (accountDeviceInstances.size() == 1)
|
||||
? Iterables.getOnlyElement(accountDeviceInstances).getAccount().getTypeSpecificID()
|
||||
: accountDeviceInstances.size() + " accounts";
|
||||
setDisplayName(displayName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Children object for the relationships that the accounts are part of.
|
||||
*/
|
||||
private static class AccountRelationshipChildren extends ChildFactory<Content> {
|
||||
|
||||
private final Set<AccountDeviceInstance> accountDeviceInstances;
|
||||
private final CommunicationsManager commsManager;
|
||||
private final CommunicationsFilter filter;
|
||||
|
||||
private AccountRelationshipChildren(Set<AccountDeviceInstance> accountDeviceInstances, CommunicationsManager commsManager, CommunicationsFilter filter) {
|
||||
this.accountDeviceInstances = accountDeviceInstances;
|
||||
this.commsManager = commsManager;
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean createKeys(List<Content> list) {
|
||||
try {
|
||||
list.addAll(commsManager.getRelationshipSources(accountDeviceInstances, filter));
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Error getting communications", ex);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Node createNodeForKey(Content t) {
|
||||
if (t instanceof BlackboardArtifact) {
|
||||
return new RelationshipNode((BlackboardArtifact) t);
|
||||
} else {
|
||||
throw new UnsupportedOperationException("Cannot create a RelationshipNode for non BlackboardArtifact content.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -20,6 +20,8 @@ package org.sleuthkit.autopsy.communications;
|
||||
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
import java.awt.Component;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.ListSelectionModel;
|
||||
@ -31,11 +33,16 @@ import org.openide.explorer.ExplorerManager;
|
||||
import org.openide.explorer.ExplorerUtils;
|
||||
import org.openide.nodes.AbstractNode;
|
||||
import org.openide.nodes.Children;
|
||||
import org.openide.nodes.Node;
|
||||
import org.openide.util.Lookup;
|
||||
import org.openide.util.lookup.ProxyLookup;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.communications.relationships.RelationshipBrowser;
|
||||
import org.sleuthkit.autopsy.communications.relationships.SelectionInfo;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.datamodel.AccountDeviceInstance;
|
||||
import org.sleuthkit.datamodel.CommunicationsFilter;
|
||||
import org.sleuthkit.datamodel.CommunicationsManager;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
@ -56,8 +63,9 @@ public final class AccountsBrowser extends JPanel implements ExplorerManager.Pro
|
||||
|
||||
private final Outline outline;
|
||||
|
||||
private final ExplorerManager messageBrowserEM = new ExplorerManager();
|
||||
private final ExplorerManager accountsTableEM = new ExplorerManager();
|
||||
|
||||
final RelationshipBrowser relationshipBrowser;
|
||||
|
||||
/*
|
||||
* This lookup proxies the selection lookup of both he accounts table and
|
||||
@ -78,21 +86,30 @@ public final class AccountsBrowser extends JPanel implements ExplorerManager.Pro
|
||||
((DefaultOutlineModel) outline.getOutlineModel()).setNodesColumnLabel(Bundle.AccountNode_accountName());
|
||||
outline.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
|
||||
outline.setColumnSorted(3, false, 1); //it would be nice if the column index wasn't hardcoded
|
||||
|
||||
relationshipBrowser = new RelationshipBrowser();
|
||||
jSplitPane1.setRightComponent(relationshipBrowser);
|
||||
|
||||
accountsTableEM.addPropertyChangeListener(evt -> {
|
||||
if (ExplorerManager.PROP_ROOT_CONTEXT.equals(evt.getPropertyName())) {
|
||||
SwingUtilities.invokeLater(this::setColumnWidths);
|
||||
} else if (ExplorerManager.PROP_EXPLORED_CONTEXT.equals(evt.getPropertyName())) {
|
||||
SwingUtilities.invokeLater(this::setColumnWidths);
|
||||
} else if (evt.getPropertyName().equals(ExplorerManager.PROP_SELECTED_NODES)) {
|
||||
final Node[] selectedNodes = accountsTableEM.getSelectedNodes();
|
||||
final Set<AccountDeviceInstance> accountDeviceInstances = new HashSet<>();
|
||||
|
||||
CommunicationsFilter filter = null;
|
||||
for (final Node node : selectedNodes) {
|
||||
accountDeviceInstances.add(((AccountDeviceInstanceNode) node).getAccountDeviceInstance());
|
||||
filter = ((AccountDeviceInstanceNode)node).getFilter();
|
||||
}
|
||||
relationshipBrowser.setSelectionInfo(new SelectionInfo(accountDeviceInstances, filter));
|
||||
}
|
||||
});
|
||||
final MessageBrowser messageBrowser = new MessageBrowser(accountsTableEM, messageBrowserEM);
|
||||
|
||||
jSplitPane1.setRightComponent(messageBrowser);
|
||||
|
||||
proxyLookup = new ProxyLookup(
|
||||
messageBrowser.getLookup(),
|
||||
ExplorerUtils.createLookup(accountsTableEM, getActionMap()));
|
||||
|
||||
proxyLookup = new ProxyLookup(relationshipBrowser.getLookup(),
|
||||
ExplorerUtils.createLookup(accountsTableEM, getActionMap()));
|
||||
}
|
||||
|
||||
private void setColumnWidths() {
|
||||
|
@ -32,19 +32,13 @@ VisualizationPanel.zoomInButton.toolTipText=Zoom in
|
||||
VisualizationPanel.zoomInButton.text=
|
||||
VisualizationPanel.zoomOutButton.toolTipText=Zoom out
|
||||
VisualizationPanel.zoomOutButton.text=
|
||||
<<<<<<< HEAD
|
||||
VisualizationPanel.fastOrganicLayoutButton.text=Redraw
|
||||
VisualizationPanel.clearVizButton.text_1=Clear
|
||||
VisualizationPanel.fastOrganicLayoutButton.text=
|
||||
VisualizationPanel.backButton.text_1=
|
||||
VisualizationPanel.forwardButton.text=
|
||||
=======
|
||||
VisualizationPanel.circleLayoutButton.text=Circle
|
||||
VisualizationPanel.organicLayoutButton.text=Organic
|
||||
VisualizationPanel.fastOrganicLayoutButton.text=
|
||||
VisualizationPanel.hierarchyLayoutButton.text=Hierarchical
|
||||
VisualizationPanel.clearVizButton.text_1=
|
||||
VisualizationPanel.snapshotButton.text_1=Snapshot Report
|
||||
>>>>>>> develop
|
||||
VisualizationPanel.clearVizButton.actionCommand=
|
||||
VisualizationPanel.backButton.toolTipText=Click to go back
|
||||
VisualizationPanel.forwardButton.toolTipText=Click to go forward
|
||||
@ -53,3 +47,4 @@ VisualizationPanel.clearVizButton.toolTipText=Click to clear the chart
|
||||
FiltersPanel.limitHeaderLabel.text=Communications Limit:
|
||||
FiltersPanel.mostRecentLabel.text=Most Recent:
|
||||
FiltersPanel.limitErrorMsgLabel.text=Invalid integer value.
|
||||
VisualizationPanel.forwardButton.text=
|
||||
|
@ -22,7 +22,6 @@ FiltersPanel.refreshButton.text=Refresh
|
||||
FiltersPanel.deviceRequiredLabel.text=Select at least one.
|
||||
FiltersPanel.accountTypeRequiredLabel.text=Select at least one.
|
||||
FiltersPanel.needsRefreshLabel.text=Displayed data is out of date. Press Refresh.
|
||||
MessageBrowser.DataResultViewerTable.title=Messages
|
||||
OpenCVTAction.displayName=Communications
|
||||
PinAccountsAction.pluralText=Add Selected Accounts to Visualization
|
||||
PinAccountsAction.singularText=Add Selected Account to Visualization
|
||||
@ -76,19 +75,13 @@ VisualizationPanel.zoomInButton.toolTipText=Zoom in
|
||||
VisualizationPanel.zoomInButton.text=
|
||||
VisualizationPanel.zoomOutButton.toolTipText=Zoom out
|
||||
VisualizationPanel.zoomOutButton.text=
|
||||
<<<<<<< HEAD
|
||||
VisualizationPanel.fastOrganicLayoutButton.text=Redraw
|
||||
VisualizationPanel.clearVizButton.text_1=Clear
|
||||
VisualizationPanel.fastOrganicLayoutButton.text=
|
||||
VisualizationPanel.backButton.text_1=
|
||||
VisualizationPanel.forwardButton.text=
|
||||
=======
|
||||
VisualizationPanel.circleLayoutButton.text=Circle
|
||||
VisualizationPanel.organicLayoutButton.text=Organic
|
||||
VisualizationPanel.fastOrganicLayoutButton.text=
|
||||
VisualizationPanel.hierarchyLayoutButton.text=Hierarchical
|
||||
VisualizationPanel.clearVizButton.text_1=
|
||||
VisualizationPanel.snapshotButton.text_1=Snapshot Report
|
||||
>>>>>>> develop
|
||||
VisualizationPanel.clearVizButton.actionCommand=
|
||||
VisualizationPanel.backButton.toolTipText=Click to go back
|
||||
VisualizationPanel.forwardButton.toolTipText=Click to go forward
|
||||
@ -97,6 +90,7 @@ VisualizationPanel.clearVizButton.toolTipText=Click to clear the chart
|
||||
FiltersPanel.limitHeaderLabel.text=Communications Limit:
|
||||
FiltersPanel.mostRecentLabel.text=Most Recent:
|
||||
FiltersPanel.limitErrorMsgLabel.text=Invalid integer value.
|
||||
VisualizationPanel.forwardButton.text=
|
||||
VisualizationPanel_action_dialogs_title=Communications
|
||||
VisualizationPanel_action_name_text=Snapshot Report
|
||||
VisualizationPanel_module_name=Communications
|
||||
|
@ -19,6 +19,7 @@
|
||||
package org.sleuthkit.autopsy.communications;
|
||||
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
import java.awt.Component;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
import java.util.List;
|
||||
@ -61,8 +62,11 @@ public final class CVTTopComponent extends TopComponent {
|
||||
associateLookup(proxyLookup);
|
||||
// Make sure the Global Actions Context is proxying the selection of the active tab.
|
||||
browseVisualizeTabPane.addChangeListener(changeEvent -> {
|
||||
Lookup.Provider selectedComponent = (Lookup.Provider) browseVisualizeTabPane.getSelectedComponent();
|
||||
proxyLookup.setNewLookups(selectedComponent.getLookup());
|
||||
Component selectedComponent = browseVisualizeTabPane.getSelectedComponent();
|
||||
if(selectedComponent instanceof Lookup.Provider) {
|
||||
Lookup lookup = ((Lookup.Provider)selectedComponent).getLookup();
|
||||
proxyLookup.setNewLookups(lookup);
|
||||
}
|
||||
filtersPane.setDeviceAccountTypeEnabled(browseVisualizeTabPane.getSelectedIndex() != 0);
|
||||
});
|
||||
|
||||
|
@ -53,6 +53,7 @@ import org.sleuthkit.datamodel.CommunicationsFilter.DeviceFilter;
|
||||
import org.sleuthkit.datamodel.CommunicationsFilter.MostRecentFilter;
|
||||
import org.sleuthkit.datamodel.DataSource;
|
||||
import static org.sleuthkit.datamodel.Relationship.Type.CALL_LOG;
|
||||
import static org.sleuthkit.datamodel.Relationship.Type.CONTACT;
|
||||
import static org.sleuthkit.datamodel.Relationship.Type.MESSAGE;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
@ -675,7 +676,7 @@ final public class FiltersPanel extends JPanel {
|
||||
commsFilter.addAndFilter(getAccountTypeFilter());
|
||||
commsFilter.addAndFilter(getDateRangeFilter());
|
||||
commsFilter.addAndFilter(new CommunicationsFilter.RelationshipTypeFilter(
|
||||
ImmutableSet.of(CALL_LOG, MESSAGE)));
|
||||
ImmutableSet.of(CALL_LOG, MESSAGE, CONTACT)));
|
||||
commsFilter.addAndFilter(getMostRecentFilter());
|
||||
return commsFilter;
|
||||
}
|
||||
|
@ -1,231 +0,0 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2017-2018 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 obt ain 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.communications;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.KeyboardFocusManager;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import javax.swing.JPanel;
|
||||
import static javax.swing.SwingUtilities.isDescendingFrom;
|
||||
import org.openide.explorer.ExplorerManager;
|
||||
import static org.openide.explorer.ExplorerUtils.createLookup;
|
||||
import org.openide.nodes.Node;
|
||||
import org.openide.util.Lookup;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.corecomponents.DataResultPanel;
|
||||
import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable;
|
||||
import org.sleuthkit.autopsy.corecomponents.TableFilterNode;
|
||||
import org.sleuthkit.autopsy.directorytree.DataResultFilterNode;
|
||||
|
||||
/**
|
||||
* The right hand side of the CVT. Has a DataResultPanel to show a listing of
|
||||
* messages and other account details, and a ContentViewer to show individual
|
||||
* messages.
|
||||
*/
|
||||
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
|
||||
public final class MessageBrowser extends JPanel implements ExplorerManager.Provider, Lookup.Provider {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private final ExplorerManager tableEM;
|
||||
private final ExplorerManager gacExplorerManager;
|
||||
private final DataResultPanel messagesResultPanel;
|
||||
/* lookup that will be exposed through the (Global Actions Context) */
|
||||
private final ModifiableProxyLookup proxyLookup = new ModifiableProxyLookup();
|
||||
|
||||
private final PropertyChangeListener focusPropertyListener = new PropertyChangeListener() {
|
||||
/**
|
||||
* Listener that keeps the proxyLookup in sync with the focused area of
|
||||
* the UI.
|
||||
*
|
||||
* Since the embedded MessageContentViewer (attachments panel) is not in
|
||||
* its own TopComponenet, its selection does not get proxied into the
|
||||
* Global Actions Context (GAC), and many of the available actions don't
|
||||
* work on it. Further, we can't put the selection from both the
|
||||
* Messages table and the Attachments table in the GAC because they
|
||||
* could both include AbstractFiles, muddling the selection seen by the
|
||||
* actions. Instead, depending on where the focus is in the window, we
|
||||
* want to put different Content in the Global Actions Context to be
|
||||
* picked up by, e.g., the tagging actions. The best way I could figure
|
||||
* to do this was to listen to all focus events and swap out what is in
|
||||
* the lookup appropriately. An alternative to this would be to
|
||||
* investigate using the ContextAwareAction interface.
|
||||
*
|
||||
* @see org.sleuthkit.autopsy.timeline.TimeLineTopComponent for a
|
||||
* similar situation and a similar solution.
|
||||
*
|
||||
* @param focusEvent The focus change event.
|
||||
*/
|
||||
@Override
|
||||
public void propertyChange(final PropertyChangeEvent focusEvent) {
|
||||
if (focusEvent.getPropertyName().equalsIgnoreCase("focusOwner")) {
|
||||
final Component newFocusOwner = (Component) focusEvent.getNewValue();
|
||||
|
||||
if (newFocusOwner == null) {
|
||||
return;
|
||||
}
|
||||
if (isDescendingFrom(newFocusOwner, messageDataContent)) {
|
||||
//if the focus owner is within the MessageContentViewer ( the attachments table)
|
||||
proxyLookup.setNewLookups(createLookup(messageDataContent.getExplorerManager(), getActionMap()));
|
||||
} else if (isDescendingFrom(newFocusOwner, messagesResultPanel)) {
|
||||
//... or if it is within the Messages table.
|
||||
proxyLookup.setNewLookups(createLookup(gacExplorerManager, getActionMap()));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructs the right hand side of the Communications Visualization Tool
|
||||
* (CVT).
|
||||
*
|
||||
* @param tableEM An explorer manager to listen to as the driver
|
||||
* of the Message Table.
|
||||
* @param gacExplorerManager An explorer manager associated with the
|
||||
* GlobalActionsContext (GAC) so that selections
|
||||
* in the messages browser can be exposed to
|
||||
* context-sensitive actions.
|
||||
*/
|
||||
@NbBundle.Messages({"MessageBrowser.DataResultViewerTable.title=Messages"})
|
||||
MessageBrowser(final ExplorerManager tableEM, final ExplorerManager gacExplorerManager) {
|
||||
this.tableEM = tableEM;
|
||||
this.gacExplorerManager = gacExplorerManager;
|
||||
initComponents();
|
||||
//create an uninitialized DataResultPanel so we can control the ResultViewers that get added.
|
||||
messagesResultPanel = DataResultPanel.createInstanceUninitialized("Account", "", Node.EMPTY, 0, messageDataContent);
|
||||
splitPane.setTopComponent(messagesResultPanel);
|
||||
splitPane.setBottomComponent(messageDataContent);
|
||||
messagesResultPanel.addResultViewer(new DataResultViewerTable(gacExplorerManager,
|
||||
Bundle.MessageBrowser_DataResultViewerTable_title()));
|
||||
messagesResultPanel.open();
|
||||
|
||||
this.tableEM.addPropertyChangeListener(new PropertyChangeListener() {
|
||||
/**
|
||||
* Listener that pushes selections in the tableEM (the Accounts
|
||||
* table) into the Messages table.
|
||||
*
|
||||
* @param pce The ExplorerManager event.
|
||||
*/
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent pce) {
|
||||
if (pce.getPropertyName().equals(ExplorerManager.PROP_SELECTED_NODES)) {
|
||||
final Node[] selectedNodes = MessageBrowser.this.tableEM.getSelectedNodes();
|
||||
messagesResultPanel.setNumberOfChildNodes(0);
|
||||
messagesResultPanel.setNode(null);
|
||||
messagesResultPanel.setPath("");
|
||||
if (selectedNodes.length > 0) {
|
||||
Node rootNode;
|
||||
final Node selectedNode = selectedNodes[0];
|
||||
|
||||
if (selectedNode instanceof AccountDeviceInstanceNode) {
|
||||
rootNode = makeRootNodeFromAccountDeviceInstanceNodes(selectedNodes);
|
||||
} else {
|
||||
rootNode = selectedNode;
|
||||
}
|
||||
messagesResultPanel.setPath(rootNode.getDisplayName());
|
||||
messagesResultPanel.setNode(new TableFilterNode(new DataResultFilterNode(rootNode, gacExplorerManager), true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Node makeRootNodeFromAccountDeviceInstanceNodes(final Node[] selectedNodes) {
|
||||
//Use lookup here?
|
||||
final AccountDeviceInstanceNode adiNode = (AccountDeviceInstanceNode) selectedNodes[0];
|
||||
|
||||
final Set<AccountDeviceInstanceKey> accountDeviceInstances = new HashSet<>();
|
||||
for (final Node n : selectedNodes) {
|
||||
//Use lookup here?
|
||||
accountDeviceInstances.add(((AccountDeviceInstanceNode) n).getAccountDeviceInstanceKey());
|
||||
}
|
||||
return SelectionNode.createFromAccounts(accountDeviceInstances, adiNode.getFilter(), adiNode.getCommsManager());
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExplorerManager getExplorerManager() {
|
||||
return gacExplorerManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Lookup getLookup() {
|
||||
return proxyLookup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNotify() {
|
||||
super.addNotify();
|
||||
//add listener that maintains correct selection in the Global Actions Context
|
||||
KeyboardFocusManager.getCurrentKeyboardFocusManager()
|
||||
.addPropertyChangeListener("focusOwner", focusPropertyListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeNotify() {
|
||||
super.removeNotify();
|
||||
KeyboardFocusManager.getCurrentKeyboardFocusManager()
|
||||
.removePropertyChangeListener("focusOwner", focusPropertyListener);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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() {
|
||||
|
||||
splitPane = new javax.swing.JSplitPane();
|
||||
messageDataContent = new org.sleuthkit.autopsy.communications.MessageDataContent();
|
||||
|
||||
splitPane.setDividerLocation(400);
|
||||
splitPane.setDividerSize(10);
|
||||
splitPane.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT);
|
||||
splitPane.setResizeWeight(0.5);
|
||||
splitPane.setBottomComponent(messageDataContent);
|
||||
|
||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
||||
this.setLayout(layout);
|
||||
layout.setHorizontalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
||||
.addGap(0, 0, 0)
|
||||
.addComponent(splitPane))
|
||||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGap(0, 0, 0)
|
||||
.addComponent(splitPane, javax.swing.GroupLayout.DEFAULT_SIZE, 1083, Short.MAX_VALUE)
|
||||
.addGap(0, 0, 0))
|
||||
);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private org.sleuthkit.autopsy.communications.MessageDataContent messageDataContent;
|
||||
private javax.swing.JSplitPane splitPane;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
|
||||
}
|
@ -26,9 +26,9 @@ import org.openide.util.lookup.ProxyLookup;
|
||||
* delegated to.
|
||||
*
|
||||
*/
|
||||
final class ModifiableProxyLookup extends ProxyLookup {
|
||||
final public class ModifiableProxyLookup extends ProxyLookup {
|
||||
|
||||
ModifiableProxyLookup(final Lookup... lookups) {
|
||||
public ModifiableProxyLookup(final Lookup... lookups) {
|
||||
super(lookups);
|
||||
}
|
||||
|
||||
|
@ -1,35 +0,0 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.communications;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import org.openide.nodes.ChildFactory;
|
||||
import org.openide.nodes.Node;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class RelaionshipSetNodeFactory extends ChildFactory<BlackboardArtifact> {
|
||||
|
||||
private final Collection<BlackboardArtifact> artifacts;
|
||||
|
||||
public RelaionshipSetNodeFactory(Collection<BlackboardArtifact> artifacts) {
|
||||
this.artifacts = artifacts;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean createKeys(List<BlackboardArtifact> list) {
|
||||
list.addAll(artifacts);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Node createNodeForKey(BlackboardArtifact key) {
|
||||
return new RelationshipNode(key);
|
||||
}
|
||||
}
|
@ -1,140 +0,0 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2018 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.communications;
|
||||
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Sets;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
import org.openide.nodes.AbstractNode;
|
||||
import org.openide.nodes.ChildFactory;
|
||||
import org.openide.nodes.Children;
|
||||
import org.openide.nodes.Node;
|
||||
import org.openide.util.Lookup;
|
||||
import org.openide.util.lookup.Lookups;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.datamodel.AccountDeviceInstance;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.CommunicationsFilter;
|
||||
import org.sleuthkit.datamodel.CommunicationsManager;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* 'Root' Node for the Account/Messages area. Represents all the relationships
|
||||
* that are selected in the AccountsBrowser or the VisualizationPanel. Can be
|
||||
* populated with AccountDeviceInstance and/or directly with relationships
|
||||
* (Content).
|
||||
*/
|
||||
final class SelectionNode extends AbstractNode {
|
||||
|
||||
private SelectionNode(Children children, Lookup lookup) {
|
||||
super(children, lookup);
|
||||
}
|
||||
|
||||
static SelectionNode createFromAccountsAndRelationships(
|
||||
Set<Content> edgeRelationshipArtifacts,
|
||||
Set<AccountDeviceInstanceKey> accountDeviceInstanceKeys,
|
||||
CommunicationsFilter filter,
|
||||
CommunicationsManager commsManager) {
|
||||
|
||||
Set<AccountDeviceInstance> accountDeviceInstances = accountDeviceInstanceKeys.stream()
|
||||
.map(AccountDeviceInstanceKey::getAccountDeviceInstance)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
SelectionNode node = new SelectionNode(Children.create(
|
||||
new RelationshipChildren(
|
||||
edgeRelationshipArtifacts,
|
||||
accountDeviceInstances,
|
||||
commsManager,
|
||||
filter),
|
||||
true), Lookups.fixed(accountDeviceInstanceKeys.toArray()));
|
||||
|
||||
//This is not good for internationalization!!!
|
||||
String name = "";
|
||||
final int accounts = accountDeviceInstances.size();
|
||||
if (accounts > 1) {
|
||||
name = accounts + " accounts";
|
||||
} else if (accounts == 1) {
|
||||
name = Iterables.getOnlyElement(accountDeviceInstances).getAccount().getTypeSpecificID();
|
||||
}
|
||||
|
||||
final int edges = edgeRelationshipArtifacts.size();
|
||||
|
||||
if (edges > 0) {
|
||||
name = name + (name.isEmpty() ? "" : " and ") + edges + " relationship" + (edges > 1 ? "s" : "");
|
||||
}
|
||||
|
||||
node.setDisplayName(name);
|
||||
return node;
|
||||
}
|
||||
|
||||
static SelectionNode createFromAccounts(
|
||||
Set<AccountDeviceInstanceKey> accountDeviceInstances,
|
||||
CommunicationsFilter filter,
|
||||
CommunicationsManager commsManager) {
|
||||
|
||||
return createFromAccountsAndRelationships(Collections.emptySet(), accountDeviceInstances, filter, commsManager);
|
||||
}
|
||||
|
||||
/**
|
||||
* Children object for the relationships that the accounts are part of.
|
||||
*/
|
||||
private static class RelationshipChildren extends ChildFactory<Content> {
|
||||
|
||||
static final private Logger logger = Logger.getLogger(RelationshipChildren.class.getName());
|
||||
|
||||
private final Set<Content> edgeRelationshipArtifacts;
|
||||
|
||||
private final Set<AccountDeviceInstance> accountDeviceInstances;
|
||||
|
||||
private final CommunicationsManager commsManager;
|
||||
private final CommunicationsFilter filter;
|
||||
|
||||
private RelationshipChildren(Set<Content> selectedEdgeRelationshipSources, Set<AccountDeviceInstance> selecedAccountDeviceInstances, CommunicationsManager commsManager, CommunicationsFilter filter) {
|
||||
this.edgeRelationshipArtifacts = selectedEdgeRelationshipSources;
|
||||
this.accountDeviceInstances = selecedAccountDeviceInstances;
|
||||
this.commsManager = commsManager;
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean createKeys(List<Content> list) {
|
||||
try {
|
||||
final Set<Content> relationshipSources = commsManager.getRelationshipSources(accountDeviceInstances, filter);
|
||||
list.addAll(Sets.union(relationshipSources, edgeRelationshipArtifacts));
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Error getting communications", ex);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Node createNodeForKey(Content content) {
|
||||
if (content instanceof BlackboardArtifact) {
|
||||
return new RelationshipNode((BlackboardArtifact) content);
|
||||
} else {
|
||||
throw new UnsupportedOperationException("Cannot create a RelationshipNode for non BlackboardArtifact content.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -28,12 +28,12 @@ import org.sleuthkit.datamodel.Account;
|
||||
/**
|
||||
* Utility class with helpers for dealing with accounts.
|
||||
*/
|
||||
class Utils {
|
||||
public final class Utils {
|
||||
|
||||
private Utils() {
|
||||
}
|
||||
|
||||
static ZoneId getUserPreferredZoneId() {
|
||||
static public ZoneId getUserPreferredZoneId() {
|
||||
ZoneId zone = UserPreferences.displayTimesInLocalTime() ?
|
||||
ZoneOffset.systemDefault() : TimeZone.getTimeZone(UserPreferences.getTimeZoneForDisplays()).toZoneId();
|
||||
return zone;
|
||||
@ -44,7 +44,7 @@ class Utils {
|
||||
*
|
||||
* @return The path of the icon for the given Account Type.
|
||||
*/
|
||||
static final String getIconFilePath(Account.Type type) {
|
||||
static public final String getIconFilePath(Account.Type type) {
|
||||
return Accounts.getIconFilePath(type);
|
||||
}
|
||||
|
||||
|
@ -54,7 +54,6 @@ import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseWheelEvent;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyVetoException;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
@ -62,11 +61,11 @@ import java.nio.file.Paths;
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
@ -98,23 +97,20 @@ import org.apache.commons.lang3.StringUtils;
|
||||
import org.controlsfx.control.Notifications;
|
||||
import org.jdesktop.layout.GroupLayout;
|
||||
import org.jdesktop.layout.LayoutStyle;
|
||||
import org.openide.explorer.ExplorerManager;
|
||||
import org.openide.explorer.ExplorerUtils;
|
||||
import org.openide.nodes.Node;
|
||||
import org.openide.util.Lookup;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.lookup.ProxyLookup;
|
||||
import org.openide.windows.WindowManager;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.communications.relationships.RelationshipBrowser;
|
||||
import org.sleuthkit.autopsy.communications.relationships.SelectionInfo;
|
||||
import org.sleuthkit.autopsy.communications.snapshot.CommSnapShotReportWriter;
|
||||
import org.sleuthkit.autopsy.coreutils.FileUtil;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.coreutils.ThreadConfined;
|
||||
import org.sleuthkit.autopsy.progress.ModalDialogProgressIndicator;
|
||||
import org.sleuthkit.datamodel.AccountDeviceInstance;
|
||||
import org.sleuthkit.datamodel.CommunicationsFilter;
|
||||
import org.sleuthkit.datamodel.CommunicationsManager;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
/**
|
||||
* A panel that goes in the Visualize tab of the Communications Visualization
|
||||
@ -127,7 +123,7 @@ import org.sleuthkit.datamodel.TskCoreException;
|
||||
* actions to work correctly.
|
||||
*/
|
||||
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
|
||||
final public class VisualizationPanel extends JPanel implements Lookup.Provider {
|
||||
final public class VisualizationPanel extends JPanel {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Logger logger = Logger.getLogger(VisualizationPanel.class.getName());
|
||||
@ -140,9 +136,6 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider
|
||||
@NbBundle.Messages("VisualizationPanel.cancelButton.text=Cancel")
|
||||
private static final String CANCEL = Bundle.VisualizationPanel_cancelButton_text();
|
||||
|
||||
private final ExplorerManager vizEM = new ExplorerManager();
|
||||
private final ExplorerManager gacEM = new ExplorerManager();
|
||||
private final ProxyLookup proxyLookup;
|
||||
private Frame windowAncestor;
|
||||
|
||||
private CommunicationsManager commsManager;
|
||||
@ -161,6 +154,8 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider
|
||||
|
||||
private final Map<NamedGraphLayout, JButton> layoutButtons = new HashMap<>();
|
||||
private NamedGraphLayout currentLayout;
|
||||
|
||||
private final RelationshipBrowser relationshipBrowser;
|
||||
|
||||
private final StateManager stateManager;
|
||||
|
||||
@ -225,13 +220,9 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider
|
||||
final GraphMouseListener graphMouseListener = new GraphMouseListener();
|
||||
graphComponent.getGraphControl().addMouseWheelListener(graphMouseListener);
|
||||
graphComponent.getGraphControl().addMouseListener(graphMouseListener);
|
||||
|
||||
final MessageBrowser messageBrowser = new MessageBrowser(vizEM, gacEM);
|
||||
splitPane.setRightComponent(messageBrowser);
|
||||
proxyLookup = new ProxyLookup(
|
||||
ExplorerUtils.createLookup(vizEM, getActionMap()),
|
||||
messageBrowser.getLookup()
|
||||
);
|
||||
|
||||
relationshipBrowser = new RelationshipBrowser();
|
||||
splitPane.setRightComponent(relationshipBrowser);
|
||||
|
||||
//feed selection to explorermanager
|
||||
graph.getSelectionModel().addListener(mxEvent.CHANGE, new SelectionListener());
|
||||
@ -257,12 +248,7 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider
|
||||
|
||||
setStateButtonsEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Lookup getLookup() {
|
||||
return proxyLookup;
|
||||
}
|
||||
|
||||
|
||||
@Subscribe
|
||||
void handle(LockedVertexModel.VertexLockEvent event) {
|
||||
final Set<mxCell> vertices = event.getVertices();
|
||||
@ -387,219 +373,223 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider
|
||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||
private void initComponents() {
|
||||
|
||||
splitPane = new JSplitPane();
|
||||
borderLayoutPanel = new JPanel();
|
||||
placeHolderPanel = new JPanel();
|
||||
jTextArea1 = new JTextArea();
|
||||
toolbar = new JPanel();
|
||||
fastOrganicLayoutButton = new JButton();
|
||||
zoomOutButton = new JButton();
|
||||
zoomInButton = new JButton();
|
||||
zoomActualButton = new JButton();
|
||||
fitZoomButton = new JButton();
|
||||
jLabel2 = new JLabel();
|
||||
zoomLabel = new JLabel();
|
||||
clearVizButton = new JButton();
|
||||
jSeparator2 = new JToolBar.Separator();
|
||||
backButton = new JButton();
|
||||
forwardButton = new JButton();
|
||||
snapshotButton = new JButton();
|
||||
jSeparator3 = new JToolBar.Separator();
|
||||
jSeparator4 = new JToolBar.Separator();
|
||||
notificationsJFXPanel = new JFXPanel();
|
||||
splitPane = new javax.swing.JSplitPane();
|
||||
borderLayoutPanel = new javax.swing.JPanel();
|
||||
placeHolderPanel = new javax.swing.JPanel();
|
||||
jTextArea1 = new javax.swing.JTextArea();
|
||||
toolbar = new javax.swing.JPanel();
|
||||
fastOrganicLayoutButton = new javax.swing.JButton();
|
||||
zoomOutButton = new javax.swing.JButton();
|
||||
zoomInButton = new javax.swing.JButton();
|
||||
zoomActualButton = new javax.swing.JButton();
|
||||
fitZoomButton = new javax.swing.JButton();
|
||||
jLabel2 = new javax.swing.JLabel();
|
||||
zoomLabel = new javax.swing.JLabel();
|
||||
clearVizButton = new javax.swing.JButton();
|
||||
jSeparator2 = new javax.swing.JToolBar.Separator();
|
||||
backButton = new javax.swing.JButton();
|
||||
forwardButton = new javax.swing.JButton();
|
||||
snapshotButton = new javax.swing.JButton();
|
||||
jSeparator3 = new javax.swing.JToolBar.Separator();
|
||||
jSeparator4 = new javax.swing.JToolBar.Separator();
|
||||
notificationsJFXPanel = new javafx.embed.swing.JFXPanel();
|
||||
|
||||
setLayout(new BorderLayout());
|
||||
setLayout(new java.awt.BorderLayout());
|
||||
|
||||
splitPane.setDividerLocation(800);
|
||||
splitPane.setResizeWeight(0.5);
|
||||
|
||||
borderLayoutPanel.setLayout(new BorderLayout());
|
||||
borderLayoutPanel.setLayout(new java.awt.BorderLayout());
|
||||
|
||||
jTextArea1.setBackground(new Color(240, 240, 240));
|
||||
jTextArea1.setBackground(new java.awt.Color(240, 240, 240));
|
||||
jTextArea1.setColumns(20);
|
||||
jTextArea1.setLineWrap(true);
|
||||
jTextArea1.setRows(5);
|
||||
jTextArea1.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.jTextArea1.text")); // NOI18N
|
||||
jTextArea1.setText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.jTextArea1.text")); // NOI18N
|
||||
|
||||
GroupLayout placeHolderPanelLayout = new GroupLayout(placeHolderPanel);
|
||||
org.jdesktop.layout.GroupLayout placeHolderPanelLayout = new org.jdesktop.layout.GroupLayout(placeHolderPanel);
|
||||
placeHolderPanel.setLayout(placeHolderPanelLayout);
|
||||
placeHolderPanelLayout.setHorizontalGroup(placeHolderPanelLayout.createParallelGroup(GroupLayout.LEADING)
|
||||
placeHolderPanelLayout.setHorizontalGroup(
|
||||
placeHolderPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
|
||||
.add(placeHolderPanelLayout.createSequentialGroup()
|
||||
.addContainerGap(250, Short.MAX_VALUE)
|
||||
.add(jTextArea1, GroupLayout.PREFERRED_SIZE, 424, GroupLayout.PREFERRED_SIZE)
|
||||
.add(jTextArea1, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 424, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
|
||||
.addContainerGap(423, Short.MAX_VALUE))
|
||||
);
|
||||
placeHolderPanelLayout.setVerticalGroup(placeHolderPanelLayout.createParallelGroup(GroupLayout.LEADING)
|
||||
placeHolderPanelLayout.setVerticalGroup(
|
||||
placeHolderPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
|
||||
.add(placeHolderPanelLayout.createSequentialGroup()
|
||||
.addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.add(jTextArea1, GroupLayout.PREFERRED_SIZE, 47, GroupLayout.PREFERRED_SIZE)
|
||||
.addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
.addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.add(jTextArea1, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 47, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
|
||||
.addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
);
|
||||
|
||||
borderLayoutPanel.add(placeHolderPanel, BorderLayout.CENTER);
|
||||
borderLayoutPanel.add(placeHolderPanel, java.awt.BorderLayout.CENTER);
|
||||
|
||||
fastOrganicLayoutButton.setIcon(new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/arrow-circle-double-135.png"))); // NOI18N
|
||||
fastOrganicLayoutButton.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.fastOrganicLayoutButton.text")); // NOI18N
|
||||
fastOrganicLayoutButton.setToolTipText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.fastOrganicLayoutButton.toolTipText")); // NOI18N
|
||||
fastOrganicLayoutButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/arrow-circle-double-135.png"))); // NOI18N
|
||||
fastOrganicLayoutButton.setText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.fastOrganicLayoutButton.text")); // NOI18N
|
||||
fastOrganicLayoutButton.setToolTipText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.fastOrganicLayoutButton.toolTipText")); // NOI18N
|
||||
fastOrganicLayoutButton.setFocusable(false);
|
||||
fastOrganicLayoutButton.setVerticalTextPosition(SwingConstants.BOTTOM);
|
||||
fastOrganicLayoutButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
|
||||
|
||||
zoomOutButton.setIcon(new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/magnifier-zoom-out-red.png"))); // NOI18N
|
||||
zoomOutButton.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomOutButton.text")); // NOI18N
|
||||
zoomOutButton.setToolTipText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomOutButton.toolTipText")); // NOI18N
|
||||
zoomOutButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/magnifier-zoom-out-red.png"))); // NOI18N
|
||||
zoomOutButton.setText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomOutButton.text")); // NOI18N
|
||||
zoomOutButton.setToolTipText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomOutButton.toolTipText")); // NOI18N
|
||||
zoomOutButton.setFocusable(false);
|
||||
zoomOutButton.setHorizontalTextPosition(SwingConstants.CENTER);
|
||||
zoomOutButton.setVerticalTextPosition(SwingConstants.BOTTOM);
|
||||
zoomOutButton.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent evt) {
|
||||
zoomOutButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
|
||||
zoomOutButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
|
||||
zoomOutButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
zoomOutButtonActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
zoomInButton.setIcon(new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/magnifier-zoom-in-green.png"))); // NOI18N
|
||||
zoomInButton.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomInButton.text")); // NOI18N
|
||||
zoomInButton.setToolTipText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomInButton.toolTipText")); // NOI18N
|
||||
zoomInButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/magnifier-zoom-in-green.png"))); // NOI18N
|
||||
zoomInButton.setText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomInButton.text")); // NOI18N
|
||||
zoomInButton.setToolTipText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomInButton.toolTipText")); // NOI18N
|
||||
zoomInButton.setFocusable(false);
|
||||
zoomInButton.setHorizontalTextPosition(SwingConstants.CENTER);
|
||||
zoomInButton.setVerticalTextPosition(SwingConstants.BOTTOM);
|
||||
zoomInButton.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent evt) {
|
||||
zoomInButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
|
||||
zoomInButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
|
||||
zoomInButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
zoomInButtonActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
zoomActualButton.setIcon(new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/magnifier-zoom-actual.png"))); // NOI18N
|
||||
zoomActualButton.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomActualButton.text")); // NOI18N
|
||||
zoomActualButton.setToolTipText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomActualButton.toolTipText")); // NOI18N
|
||||
zoomActualButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/magnifier-zoom-actual.png"))); // NOI18N
|
||||
zoomActualButton.setText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomActualButton.text")); // NOI18N
|
||||
zoomActualButton.setToolTipText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomActualButton.toolTipText")); // NOI18N
|
||||
zoomActualButton.setFocusable(false);
|
||||
zoomActualButton.setHorizontalTextPosition(SwingConstants.CENTER);
|
||||
zoomActualButton.setVerticalTextPosition(SwingConstants.BOTTOM);
|
||||
zoomActualButton.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent evt) {
|
||||
zoomActualButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
|
||||
zoomActualButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
|
||||
zoomActualButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
zoomActualButtonActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
fitZoomButton.setIcon(new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/magnifier-zoom-fit.png"))); // NOI18N
|
||||
fitZoomButton.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.fitZoomButton.text")); // NOI18N
|
||||
fitZoomButton.setToolTipText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.fitZoomButton.toolTipText")); // NOI18N
|
||||
fitZoomButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/magnifier-zoom-fit.png"))); // NOI18N
|
||||
fitZoomButton.setText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.fitZoomButton.text")); // NOI18N
|
||||
fitZoomButton.setToolTipText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.fitZoomButton.toolTipText")); // NOI18N
|
||||
fitZoomButton.setFocusable(false);
|
||||
fitZoomButton.setHorizontalTextPosition(SwingConstants.CENTER);
|
||||
fitZoomButton.setVerticalTextPosition(SwingConstants.BOTTOM);
|
||||
fitZoomButton.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent evt) {
|
||||
fitZoomButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
|
||||
fitZoomButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
|
||||
fitZoomButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
fitZoomButtonActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
jLabel2.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.jLabel2.text")); // NOI18N
|
||||
jLabel2.setText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.jLabel2.text")); // NOI18N
|
||||
|
||||
zoomLabel.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomLabel.text")); // NOI18N
|
||||
zoomLabel.setText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.zoomLabel.text")); // NOI18N
|
||||
|
||||
clearVizButton.setIcon(new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/broom.png"))); // NOI18N
|
||||
clearVizButton.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.clearVizButton.text_1")); // NOI18N
|
||||
clearVizButton.setToolTipText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.clearVizButton.toolTipText")); // NOI18N
|
||||
clearVizButton.setActionCommand(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.clearVizButton.actionCommand")); // NOI18N
|
||||
clearVizButton.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent evt) {
|
||||
clearVizButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/communications/images/broom.png"))); // NOI18N
|
||||
clearVizButton.setText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.clearVizButton.text_1")); // NOI18N
|
||||
clearVizButton.setToolTipText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.clearVizButton.toolTipText")); // NOI18N
|
||||
clearVizButton.setActionCommand(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.clearVizButton.actionCommand")); // NOI18N
|
||||
clearVizButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
clearVizButtonActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
jSeparator2.setOrientation(SwingConstants.VERTICAL);
|
||||
jSeparator2.setOrientation(javax.swing.SwingConstants.VERTICAL);
|
||||
|
||||
backButton.setIcon(new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/resultset_previous.png"))); // NOI18N
|
||||
backButton.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.backButton.text_1")); // NOI18N
|
||||
backButton.setToolTipText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.backButton.toolTipText")); // NOI18N
|
||||
backButton.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent evt) {
|
||||
backButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/resultset_previous.png"))); // NOI18N
|
||||
backButton.setText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.backButton.text_1")); // NOI18N
|
||||
backButton.setToolTipText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.backButton.toolTipText")); // NOI18N
|
||||
backButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
backButtonActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
forwardButton.setIcon(new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/resultset_next.png"))); // NOI18N
|
||||
forwardButton.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.forwardButton.text")); // NOI18N
|
||||
forwardButton.setToolTipText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.forwardButton.toolTipText")); // NOI18N
|
||||
forwardButton.setHorizontalTextPosition(SwingConstants.LEADING);
|
||||
forwardButton.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent evt) {
|
||||
forwardButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/resultset_next.png"))); // NOI18N
|
||||
forwardButton.setText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.forwardButton.text")); // NOI18N
|
||||
forwardButton.setToolTipText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.forwardButton.toolTipText")); // NOI18N
|
||||
forwardButton.setHorizontalTextPosition(javax.swing.SwingConstants.LEADING);
|
||||
forwardButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
forwardButtonActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
snapshotButton.setIcon(new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/report/images/image.png"))); // NOI18N
|
||||
snapshotButton.setText(NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.snapshotButton.text_1")); // NOI18N
|
||||
snapshotButton.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent evt) {
|
||||
snapshotButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/report/images/image.png"))); // NOI18N
|
||||
snapshotButton.setText(org.openide.util.NbBundle.getMessage(VisualizationPanel.class, "VisualizationPanel.snapshotButton.text_1")); // NOI18N
|
||||
snapshotButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
snapshotButtonActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
jSeparator3.setOrientation(SwingConstants.VERTICAL);
|
||||
jSeparator3.setOrientation(javax.swing.SwingConstants.VERTICAL);
|
||||
|
||||
jSeparator4.setOrientation(SwingConstants.VERTICAL);
|
||||
jSeparator4.setOrientation(javax.swing.SwingConstants.VERTICAL);
|
||||
|
||||
GroupLayout toolbarLayout = new GroupLayout(toolbar);
|
||||
org.jdesktop.layout.GroupLayout toolbarLayout = new org.jdesktop.layout.GroupLayout(toolbar);
|
||||
toolbar.setLayout(toolbarLayout);
|
||||
toolbarLayout.setHorizontalGroup(toolbarLayout.createParallelGroup(GroupLayout.LEADING)
|
||||
toolbarLayout.setHorizontalGroup(
|
||||
toolbarLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
|
||||
.add(toolbarLayout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.add(backButton)
|
||||
.addPreferredGap(LayoutStyle.RELATED)
|
||||
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
|
||||
.add(forwardButton)
|
||||
.addPreferredGap(LayoutStyle.RELATED)
|
||||
.add(jSeparator4, GroupLayout.PREFERRED_SIZE, 10, GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(LayoutStyle.RELATED)
|
||||
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
|
||||
.add(jSeparator4, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 10, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
|
||||
.add(fastOrganicLayoutButton)
|
||||
.addPreferredGap(LayoutStyle.RELATED)
|
||||
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
|
||||
.add(clearVizButton)
|
||||
.addPreferredGap(LayoutStyle.RELATED)
|
||||
.add(jSeparator2, GroupLayout.PREFERRED_SIZE, 10, GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(LayoutStyle.RELATED)
|
||||
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
|
||||
.add(jSeparator2, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 10, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
|
||||
.add(jLabel2)
|
||||
.addPreferredGap(LayoutStyle.RELATED)
|
||||
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
|
||||
.add(zoomLabel)
|
||||
.addPreferredGap(LayoutStyle.RELATED)
|
||||
.add(zoomOutButton, GroupLayout.PREFERRED_SIZE, 32, GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(LayoutStyle.RELATED)
|
||||
.add(zoomInButton, GroupLayout.PREFERRED_SIZE, 32, GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(LayoutStyle.RELATED)
|
||||
.add(zoomActualButton, GroupLayout.PREFERRED_SIZE, 33, GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(LayoutStyle.RELATED)
|
||||
.add(fitZoomButton, GroupLayout.PREFERRED_SIZE, 32, GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(LayoutStyle.RELATED)
|
||||
.add(jSeparator3, GroupLayout.PREFERRED_SIZE, 10, GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(LayoutStyle.RELATED)
|
||||
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
|
||||
.add(zoomOutButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 32, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
|
||||
.add(zoomInButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 32, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
|
||||
.add(zoomActualButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 33, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
|
||||
.add(fitZoomButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 32, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
|
||||
.add(jSeparator3, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 10, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
|
||||
.add(snapshotButton)
|
||||
.addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
.addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
);
|
||||
toolbarLayout.setVerticalGroup(toolbarLayout.createParallelGroup(GroupLayout.LEADING)
|
||||
toolbarLayout.setVerticalGroup(
|
||||
toolbarLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
|
||||
.add(toolbarLayout.createSequentialGroup()
|
||||
.add(3, 3, 3)
|
||||
.add(toolbarLayout.createParallelGroup(GroupLayout.CENTER)
|
||||
.add(toolbarLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.CENTER)
|
||||
.add(fastOrganicLayoutButton)
|
||||
.add(zoomOutButton)
|
||||
.add(zoomInButton, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.add(zoomActualButton, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.add(fitZoomButton, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.add(zoomInButton, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.add(zoomActualButton, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.add(fitZoomButton, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.add(jLabel2)
|
||||
.add(zoomLabel)
|
||||
.add(clearVizButton)
|
||||
.add(jSeparator2, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.add(jSeparator2, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.add(backButton)
|
||||
.add(forwardButton)
|
||||
.add(snapshotButton)
|
||||
.add(jSeparator3, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.add(jSeparator4, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
.add(jSeparator3, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.add(jSeparator4, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
.add(3, 3, 3))
|
||||
);
|
||||
|
||||
borderLayoutPanel.add(toolbar, BorderLayout.PAGE_START);
|
||||
borderLayoutPanel.add(notificationsJFXPanel, BorderLayout.PAGE_END);
|
||||
borderLayoutPanel.add(toolbar, java.awt.BorderLayout.PAGE_START);
|
||||
borderLayoutPanel.add(notificationsJFXPanel, java.awt.BorderLayout.PAGE_END);
|
||||
|
||||
splitPane.setLeftComponent(borderLayoutPanel);
|
||||
|
||||
add(splitPane, BorderLayout.CENTER);
|
||||
add(splitPane, java.awt.BorderLayout.CENTER);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
private void fitZoomButtonActionPerformed(ActionEvent evt) {//GEN-FIRST:event_fitZoomButtonActionPerformed
|
||||
@ -890,26 +880,26 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider
|
||||
}
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private JButton backButton;
|
||||
private JPanel borderLayoutPanel;
|
||||
private JButton clearVizButton;
|
||||
private JButton fastOrganicLayoutButton;
|
||||
private JButton fitZoomButton;
|
||||
private JButton forwardButton;
|
||||
private JLabel jLabel2;
|
||||
private JToolBar.Separator jSeparator2;
|
||||
private JToolBar.Separator jSeparator3;
|
||||
private JToolBar.Separator jSeparator4;
|
||||
private JTextArea jTextArea1;
|
||||
private JFXPanel notificationsJFXPanel;
|
||||
private JPanel placeHolderPanel;
|
||||
private JButton snapshotButton;
|
||||
private JSplitPane splitPane;
|
||||
private JPanel toolbar;
|
||||
private JButton zoomActualButton;
|
||||
private JButton zoomInButton;
|
||||
private JLabel zoomLabel;
|
||||
private JButton zoomOutButton;
|
||||
private javax.swing.JButton backButton;
|
||||
private javax.swing.JPanel borderLayoutPanel;
|
||||
private javax.swing.JButton clearVizButton;
|
||||
private javax.swing.JButton fastOrganicLayoutButton;
|
||||
private javax.swing.JButton fitZoomButton;
|
||||
private javax.swing.JButton forwardButton;
|
||||
private javax.swing.JLabel jLabel2;
|
||||
private javax.swing.JToolBar.Separator jSeparator2;
|
||||
private javax.swing.JToolBar.Separator jSeparator3;
|
||||
private javax.swing.JToolBar.Separator jSeparator4;
|
||||
private javax.swing.JTextArea jTextArea1;
|
||||
private javafx.embed.swing.JFXPanel notificationsJFXPanel;
|
||||
private javax.swing.JPanel placeHolderPanel;
|
||||
private javax.swing.JButton snapshotButton;
|
||||
private javax.swing.JSplitPane splitPane;
|
||||
private javax.swing.JPanel toolbar;
|
||||
private javax.swing.JButton zoomActualButton;
|
||||
private javax.swing.JButton zoomInButton;
|
||||
private javax.swing.JLabel zoomLabel;
|
||||
private javax.swing.JButton zoomOutButton;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
|
||||
/**
|
||||
@ -922,40 +912,25 @@ final public class VisualizationPanel extends JPanel implements Lookup.Provider
|
||||
@Override
|
||||
public void invoke(Object sender, mxEventObject evt) {
|
||||
Object[] selectionCells = graph.getSelectionCells();
|
||||
Node rootNode = Node.EMPTY;
|
||||
Node[] selectedNodes = new Node[0];
|
||||
if (selectionCells.length > 0) {
|
||||
mxICell[] selectedCells = Arrays.asList(selectionCells).toArray(new mxCell[selectionCells.length]);
|
||||
HashSet<Content> relationshipSources = new HashSet<>();
|
||||
HashSet<AccountDeviceInstanceKey> adis = new HashSet<>();
|
||||
HashSet<AccountDeviceInstance> deviceInstances = new HashSet<>();
|
||||
for (mxICell cell : selectedCells) {
|
||||
if (cell.isEdge()) {
|
||||
mxICell source = (mxICell) graph.getModel().getTerminal(cell, true);
|
||||
AccountDeviceInstanceKey account1 = (AccountDeviceInstanceKey) source.getValue();
|
||||
mxICell target = (mxICell) graph.getModel().getTerminal(cell, false);
|
||||
AccountDeviceInstanceKey account2 = (AccountDeviceInstanceKey) target.getValue();
|
||||
try {
|
||||
final List<Content> relationshipSources1 = commsManager.getRelationshipSources(
|
||||
account1.getAccountDeviceInstance(),
|
||||
account2.getAccountDeviceInstance(),
|
||||
currentFilter);
|
||||
relationshipSources.addAll(relationshipSources1);
|
||||
} catch (TskCoreException tskCoreException) {
|
||||
logger.log(Level.SEVERE, " Error getting relationsips....", tskCoreException);
|
||||
}
|
||||
|
||||
deviceInstances.add(((AccountDeviceInstanceKey) source.getValue()).getAccountDeviceInstance());
|
||||
deviceInstances.add(((AccountDeviceInstanceKey) target.getValue()).getAccountDeviceInstance());
|
||||
|
||||
} else if (cell.isVertex()) {
|
||||
adis.add((AccountDeviceInstanceKey) cell.getValue());
|
||||
deviceInstances.add(((AccountDeviceInstanceKey) cell.getValue()).getAccountDeviceInstance());
|
||||
}
|
||||
}
|
||||
|
||||
rootNode = SelectionNode.createFromAccountsAndRelationships(relationshipSources, adis, currentFilter, commsManager);
|
||||
selectedNodes = new Node[]{rootNode};
|
||||
}
|
||||
vizEM.setRootContext(rootNode);
|
||||
try {
|
||||
vizEM.setSelectedNodes(selectedNodes);
|
||||
} catch (PropertyVetoException ex) {
|
||||
logger.log(Level.SEVERE, "Selection vetoed.", ex);
|
||||
relationshipBrowser.setSelectionInfo(new SelectionInfo(deviceInstances, currentFilter));
|
||||
} else {
|
||||
relationshipBrowser.setSelectionInfo(new SelectionInfo(Collections.EMPTY_SET, currentFilter));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* 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.communications.relationships;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import org.openide.nodes.AbstractNode;
|
||||
import org.openide.nodes.ChildFactory;
|
||||
import org.openide.nodes.Children;
|
||||
import org.openide.nodes.Node;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.datamodel.Account;
|
||||
import org.sleuthkit.datamodel.AccountFileInstance;
|
||||
import org.sleuthkit.datamodel.CommunicationsManager;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* ChildFactory that creates ContentNode representing the files that reference
|
||||
* the given list of accounts.
|
||||
*/
|
||||
final class AccountSourceContentChildNodeFactory extends ChildFactory<Content> {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(AccountSourceContentChildNodeFactory.class.getName());
|
||||
|
||||
private final Set<Account> accounts;
|
||||
|
||||
AccountSourceContentChildNodeFactory(Set<Account> accounts) {
|
||||
this.accounts = accounts;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean createKeys(List<Content> list) {
|
||||
if (accounts == null || accounts.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
CommunicationsManager communicationManager;
|
||||
try {
|
||||
communicationManager = Case.getCurrentCaseThrows().getSleuthkitCase().getCommunicationsManager();
|
||||
} catch (NoCurrentCaseException | TskCoreException ex) {
|
||||
logger.log(Level.WARNING, "Failed to get communications manager from case.", ex); //NON-NLS
|
||||
return false;
|
||||
}
|
||||
|
||||
accounts.forEach((account) -> {
|
||||
try {
|
||||
List<AccountFileInstance> accountFileInstanceList = communicationManager.getAccountFileInstances(account);
|
||||
|
||||
for (AccountFileInstance fileInstance : accountFileInstanceList) {
|
||||
list.add(fileInstance.getFile());
|
||||
}
|
||||
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.WARNING, String.format("Failed to getAccountFileInstances for account: %d", account.getAccountID()), ex); //NON-NLS
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Node createNodeForKey(Content content) {
|
||||
return new ContentNode(content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple AbstractNode for a Content (file) object.
|
||||
*/
|
||||
final class ContentNode extends AbstractNode {
|
||||
|
||||
private final Content content;
|
||||
|
||||
ContentNode(Content content) {
|
||||
super(Children.LEAF);
|
||||
this.content = content;
|
||||
|
||||
try {
|
||||
setDisplayName(content.getUniquePath());
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.WARNING, String.format("Unable to getUniquePath for Content: %d", content.getId()), ex); //NON-NLS
|
||||
setDisplayName(content.getName());
|
||||
}
|
||||
|
||||
setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-icon.png"); //NON-NLS
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,127 @@
|
||||
/*
|
||||
* 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 obt ain 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.communications.relationships;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import java.util.logging.Level;
|
||||
import org.openide.nodes.Children;
|
||||
import org.openide.nodes.Node;
|
||||
import org.openide.nodes.Sheet;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode;
|
||||
import org.sleuthkit.autopsy.datamodel.FileNode;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* Factory for creating thumbnail children nodes.
|
||||
*/
|
||||
final class AttachmentsChildren extends Children.Keys<AbstractFile> {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(AttachmentsChildren.class.getName());
|
||||
|
||||
private final Set<BlackboardArtifact> artifacts;
|
||||
|
||||
/*
|
||||
* Creates the list of thumbnails from the given list of
|
||||
* BlackboardArtifacts.
|
||||
*
|
||||
* The thumbnails will be initialls sorted by size, then name so that they
|
||||
* appear sorted by size by default.
|
||||
*/
|
||||
AttachmentsChildren(Set<BlackboardArtifact> artifacts) {
|
||||
super(false);
|
||||
|
||||
this.artifacts = artifacts;
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Node[] createNodes(AbstractFile t) {
|
||||
return new Node[]{new AttachementNode(t)};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addNotify() {
|
||||
super.addNotify();
|
||||
|
||||
Set<AbstractFile> thumbnails = new TreeSet<>((AbstractFile file1, AbstractFile file2) -> {
|
||||
int result = Long.compare(file1.getSize(), file2.getSize());
|
||||
if (result == 0) {
|
||||
result = file1.getName().compareTo(file2.getName());
|
||||
}
|
||||
|
||||
return result;
|
||||
});
|
||||
|
||||
artifacts.forEach((bba) -> {
|
||||
try {
|
||||
for (Content childContent : bba.getChildren()) {
|
||||
if (childContent instanceof AbstractFile) {
|
||||
thumbnails.add((AbstractFile) childContent);
|
||||
}
|
||||
}
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.WARNING, "Unable to get children from artifact.", ex); //NON-NLS
|
||||
}
|
||||
});
|
||||
|
||||
setKeys(thumbnails);
|
||||
}
|
||||
|
||||
/**
|
||||
* A node for representing a thumbnail.
|
||||
*/
|
||||
static class AttachementNode extends FileNode {
|
||||
|
||||
AttachementNode(AbstractFile file) {
|
||||
super(file, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Sheet createSheet() {
|
||||
Sheet sheet = super.createSheet();
|
||||
Set<String> keepProps = new HashSet<>(Arrays.asList(
|
||||
NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.nameColLbl"),
|
||||
NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.score.name"),
|
||||
NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.comment.name"),
|
||||
NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.count.name"),
|
||||
NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.sizeColLbl"),
|
||||
NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.mimeType"),
|
||||
NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.knownColLbl")));
|
||||
|
||||
//Remove all other props except for the ones above
|
||||
Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
|
||||
for (Node.Property<?> p : sheetSet.getProperties()) {
|
||||
if (!keepProps.contains(p.getName())) {
|
||||
sheetSet.remove(p.getName());
|
||||
}
|
||||
}
|
||||
|
||||
return sheet;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
ContactDetailsPane.nameLabel.text=Placeholder
|
||||
SummaryViewer.countsPanel.border.title=Counts
|
||||
SummaryViewer.emailLabel.text=Emails:
|
||||
SummaryViewer.contactsLabel.text=Contacts:
|
||||
SummaryViewer.attachmentsLabel.text=Attachments:
|
||||
SummaryViewer.fileReferencesPanel.border.title=File References in Current Case
|
||||
SummaryViewer.caseReferencesPanel.border.title=Other Occurrences
|
||||
OutlineViewPanel.messageLabel.text=<Control Disabled>
|
||||
SummaryViewer.messagesDataLabel.text=messages
|
||||
SummaryViewer.callLogsDataLabel.text=callLogs
|
||||
SummaryViewer.contactsDataLabel.text=contacts
|
||||
SummaryViewer.emailDataLabel.text=emails
|
||||
SummaryViewer.attachmentsDataLabel.text=attachments
|
||||
SummaryViewer.messagesLabel.text=Messages:
|
||||
SummaryViewer.callLogsLabel.text=Call Logs:
|
@ -0,0 +1,44 @@
|
||||
ContactDetailsPane.nameLabel.text=Placeholder
|
||||
ContactNode_Email=Email Address
|
||||
ContactNode_Home_Number=Home Number
|
||||
ContactNode_Mobile_Number=Mobile Number
|
||||
ContactNode_Name=Name
|
||||
ContactNode_Office_Number=Office Number
|
||||
ContactNode_Phone=Phone Number
|
||||
ContactNode_URL=URL
|
||||
ContactsViewer_columnHeader_Email=Email
|
||||
ContactsViewer_columnHeader_Name=Name
|
||||
ContactsViewer_columnHeader_Phone=Phone
|
||||
ContactsViewer_tabTitle=Contacts
|
||||
MediaViewer_Name=Media
|
||||
MessageNode_Node_Property_Attms=Attachments
|
||||
MessageNode_Node_Property_Date=Date
|
||||
MessageNode_Node_Property_From=From
|
||||
MessageNode_Node_Property_Subject=Subject
|
||||
MessageNode_Node_Property_To=To
|
||||
MessageNode_Node_Property_Type=Type
|
||||
MessageViewer_columnHeader_Attms=Attachments
|
||||
MessageViewer_columnHeader_Date=Date
|
||||
MessageViewer_columnHeader_From=From
|
||||
MessageViewer_columnHeader_Subject=Subject
|
||||
MessageViewer_columnHeader_To=To
|
||||
MessageViewer_tabTitle=Messages
|
||||
SummaryViewer.countsPanel.border.title=Counts
|
||||
SummaryViewer.emailLabel.text=Emails:
|
||||
SummaryViewer.contactsLabel.text=Contacts:
|
||||
SummaryViewer.attachmentsLabel.text=Attachments:
|
||||
SummaryViewer.fileReferencesPanel.border.title=File References in Current Case
|
||||
SummaryViewer.caseReferencesPanel.border.title=Other Occurrences
|
||||
OutlineViewPanel.messageLabel.text=<Control Disabled>
|
||||
SummaryViewer.messagesDataLabel.text=messages
|
||||
SummaryViewer.callLogsDataLabel.text=callLogs
|
||||
SummaryViewer.contactsDataLabel.text=contacts
|
||||
SummaryViewer.emailDataLabel.text=emails
|
||||
SummaryViewer.attachmentsDataLabel.text=attachments
|
||||
SummaryViewer.messagesLabel.text=Messages:
|
||||
SummaryViewer.callLogsLabel.text=Call Logs:
|
||||
SummaryViewer_CaseRefNameColumn_Title=Case Name
|
||||
SummaryViewer_CentralRepository_Message=<Enable Central Resposity to see Case References>
|
||||
SummaryViewer_Creation_Date_Title=Creation Date
|
||||
SummaryViewer_FileRefNameColumn_Title=Path
|
||||
SummaryViewer_TabTitle=Summary
|
@ -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">
|
||||
<NonVisualComponents>
|
||||
<Component class="org.sleuthkit.autopsy.contentviewers.MessageContentViewer" name="messageContentViewer1">
|
||||
</Component>
|
||||
</NonVisualComponents>
|
||||
<AuxValues>
|
||||
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
|
||||
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
|
||||
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
||||
</AuxValues>
|
||||
|
||||
<Layout>
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="propertySheet" max="32767" attributes="0"/>
|
||||
<Group type="102" attributes="0">
|
||||
<Component id="nameLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
<EmptySpace 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 max="-2" attributes="0"/>
|
||||
<Component id="nameLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="propertySheet" pref="283" max="32767" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JLabel" name="nameLabel">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Tahoma" size="24" style="0"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="ContactDetailsPane.nameLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="org.openide.explorer.propertysheet.PropertySheet" name="propertySheet">
|
||||
<Properties>
|
||||
<Property name="descriptionAreaVisible" type="boolean" value="false"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Form>
|
@ -0,0 +1,116 @@
|
||||
/*
|
||||
* 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.communications.relationships;
|
||||
|
||||
import org.openide.explorer.ExplorerManager;
|
||||
import org.openide.nodes.Node;
|
||||
|
||||
/**
|
||||
* Displays the propertied of a ContactNode in a PropertySheet.
|
||||
*/
|
||||
public final class ContactDetailsPane extends javax.swing.JPanel implements ExplorerManager.Provider {
|
||||
|
||||
final private ExplorerManager explorerManager = new ExplorerManager();
|
||||
|
||||
/**
|
||||
* Displays the propertied of a ContactNode in a PropertySheet.
|
||||
*/
|
||||
public ContactDetailsPane() {
|
||||
initComponents();
|
||||
this.setEnabled(false);
|
||||
|
||||
nameLabel.setText("");
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the list of nodes for the property sheet.
|
||||
*
|
||||
* @param nodes List of nodes to set
|
||||
*/
|
||||
public void setNode(Node[] nodes) {
|
||||
if (nodes != null && nodes.length == 1) {
|
||||
nameLabel.setText(nodes[0].getDisplayName());
|
||||
propertySheet.setNodes(nodes);
|
||||
} else {
|
||||
nameLabel.setText("");
|
||||
propertySheet.setNodes(null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExplorerManager getExplorerManager() {
|
||||
return explorerManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEnabled(boolean enabled) {
|
||||
super.setEnabled(enabled);
|
||||
nameLabel.setEnabled(enabled);
|
||||
propertySheet.setEnabled(enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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() {
|
||||
|
||||
messageContentViewer1 = new org.sleuthkit.autopsy.contentviewers.MessageContentViewer();
|
||||
nameLabel = new javax.swing.JLabel();
|
||||
propertySheet = new org.openide.explorer.propertysheet.PropertySheet();
|
||||
|
||||
nameLabel.setFont(new java.awt.Font("Tahoma", 0, 24)); // NOI18N
|
||||
org.openide.awt.Mnemonics.setLocalizedText(nameLabel, org.openide.util.NbBundle.getMessage(ContactDetailsPane.class, "ContactDetailsPane.nameLabel.text")); // NOI18N
|
||||
|
||||
propertySheet.setDescriptionAreaVisible(false);
|
||||
|
||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
||||
this.setLayout(layout);
|
||||
layout.setHorizontalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(propertySheet, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addComponent(nameLabel)
|
||||
.addGap(0, 0, Short.MAX_VALUE)))
|
||||
.addContainerGap())
|
||||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addComponent(nameLabel)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(propertySheet, javax.swing.GroupLayout.DEFAULT_SIZE, 283, Short.MAX_VALUE)
|
||||
.addContainerGap())
|
||||
);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private org.sleuthkit.autopsy.contentviewers.MessageContentViewer messageContentViewer1;
|
||||
private javax.swing.JLabel nameLabel;
|
||||
private org.openide.explorer.propertysheet.PropertySheet propertySheet;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
}
|
161
Core/src/org/sleuthkit/autopsy/communications/relationships/ContactNode.java
Executable file
161
Core/src/org/sleuthkit/autopsy/communications/relationships/ContactNode.java
Executable file
@ -0,0 +1,161 @@
|
||||
/*
|
||||
* 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.communications.relationships;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.TimeZone;
|
||||
import java.util.logging.Level;
|
||||
import org.openide.nodes.Sheet;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode;
|
||||
import org.sleuthkit.autopsy.datamodel.NodeProperty;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT;
|
||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME;
|
||||
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME_PERSON;
|
||||
import static org.sleuthkit.datamodel.BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DATETIME;
|
||||
import org.sleuthkit.datamodel.TimeUtilities;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.autopsy.communications.Utils;
|
||||
|
||||
/**
|
||||
* Extends BlackboardArtifactNode to override createSheet to create a contact
|
||||
* artifact specific sheet.
|
||||
*/
|
||||
final class ContactNode extends BlackboardArtifactNode {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(ContactNode.class.getName());
|
||||
|
||||
@Messages({
|
||||
"ContactNode_Name=Name",
|
||||
"ContactNode_Phone=Phone Number",
|
||||
"ContactNode_Email=Email Address",
|
||||
"ContactNode_Mobile_Number=Mobile Number",
|
||||
"ContactNode_Office_Number=Office Number",
|
||||
"ContactNode_URL=URL",
|
||||
"ContactNode_Home_Number=Home Number",})
|
||||
|
||||
ContactNode(BlackboardArtifact artifact) {
|
||||
super(artifact);
|
||||
|
||||
String name = getAttributeDisplayString(artifact, TSK_NAME);
|
||||
if (name == null || name.trim().isEmpty()) {
|
||||
// VCards use TSK_NAME_PERSON instead of TSK_NAME
|
||||
name = getAttributeDisplayString(artifact, TSK_NAME_PERSON);
|
||||
}
|
||||
setDisplayName(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Sheet createSheet() {
|
||||
Sheet sheet = super.createSheet();
|
||||
|
||||
final BlackboardArtifact artifact = getArtifact();
|
||||
BlackboardArtifact.ARTIFACT_TYPE fromID = BlackboardArtifact.ARTIFACT_TYPE.fromID(artifact.getArtifactTypeID());
|
||||
if (fromID != TSK_CONTACT) {
|
||||
return sheet;
|
||||
}
|
||||
|
||||
Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
|
||||
if (sheetSet == null) {
|
||||
sheetSet = Sheet.createPropertiesSet();
|
||||
sheet.put(sheetSet);
|
||||
}
|
||||
|
||||
// Sorting the attributes by type so that the duplicates can be removed
|
||||
// and they can be grouped by type for display. The attribute prefixes
|
||||
// are used so that all attributed of that type are found, including
|
||||
// ones that are not predefined as part of BlackboardAttributes
|
||||
try {
|
||||
HashMap<String, BlackboardAttribute> phoneNumMap = new HashMap<>();
|
||||
HashMap<String, BlackboardAttribute> emailMap = new HashMap<>();
|
||||
HashMap<String, BlackboardAttribute> nameMap = new HashMap<>();
|
||||
HashMap<String, BlackboardAttribute> otherMap = new HashMap<>();
|
||||
for (BlackboardAttribute bba : artifact.getAttributes()) {
|
||||
if (bba.getAttributeType().getTypeName().startsWith("TSK_PHONE")) {
|
||||
phoneNumMap.put(bba.getDisplayString(), bba);
|
||||
} else if (bba.getAttributeType().getTypeName().startsWith("TSK_EMAIL")) {
|
||||
emailMap.put(bba.getDisplayString(), bba);
|
||||
} else if (bba.getAttributeType().getTypeName().startsWith("TSK_NAME")) {
|
||||
nameMap.put(bba.getDisplayString(), bba);
|
||||
} else {
|
||||
otherMap.put(bba.getDisplayString(), bba);
|
||||
}
|
||||
}
|
||||
|
||||
addPropertiesToSheet(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME.getLabel(),
|
||||
sheetSet, nameMap);
|
||||
addPropertiesToSheet(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER.getLabel(),
|
||||
sheetSet, phoneNumMap);
|
||||
addPropertiesToSheet(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL.getLabel(),
|
||||
sheetSet, emailMap);
|
||||
|
||||
for (BlackboardAttribute bba : otherMap.values()) {
|
||||
sheetSet.put(new NodeProperty<>(bba.getAttributeType().getTypeName(), bba.getAttributeType().getDisplayName(), "", bba.getDisplayString()));
|
||||
}
|
||||
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.WARNING, "Error getting attribute values.", ex); //NON-NLS
|
||||
}
|
||||
|
||||
return sheet;
|
||||
}
|
||||
|
||||
private void addPropertiesToSheet(String propertyID, Sheet.Set sheetSet, Map<String, BlackboardAttribute> attributeMap) {
|
||||
int count = 0;
|
||||
for (BlackboardAttribute bba : attributeMap.values()) {
|
||||
if (count++ > 0) {
|
||||
sheetSet.put(new NodeProperty<>(propertyID + "_" + count, bba.getAttributeType().getDisplayName(), "", bba.getDisplayString()));
|
||||
} else {
|
||||
sheetSet.put(new NodeProperty<>(propertyID, bba.getAttributeType().getDisplayName(), "", bba.getDisplayString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String getAttributeDisplayString(final BlackboardArtifact artifact, final BlackboardAttribute.ATTRIBUTE_TYPE attributeType) {
|
||||
try {
|
||||
BlackboardAttribute attribute = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.fromID(attributeType.getTypeID())));
|
||||
if (attribute == null) {
|
||||
return "";
|
||||
} else if (attributeType.getValueType() == DATETIME) {
|
||||
return TimeUtilities.epochToTime(attribute.getValueLong(),
|
||||
TimeZone.getTimeZone(Utils.getUserPreferredZoneId()));
|
||||
} else {
|
||||
return attribute.getDisplayString();
|
||||
}
|
||||
} catch (TskCoreException tskCoreException) {
|
||||
logger.log(Level.WARNING, "Error getting attribute value.", tskCoreException); //NON-NLS
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Circumvent DataResultFilterNode's slightly odd delegation to
|
||||
* BlackboardArtifactNode.getSourceName().
|
||||
*
|
||||
* @return the displayName of this Node, which is the type.
|
||||
*/
|
||||
@Override
|
||||
public String getSourceName() {
|
||||
return getDisplayName();
|
||||
}
|
||||
}
|
@ -0,0 +1,109 @@
|
||||
/*
|
||||
* 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.communications.relationships;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import org.openide.nodes.ChildFactory;
|
||||
import org.openide.nodes.Node;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT;
|
||||
import org.sleuthkit.datamodel.CommunicationsManager;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* ChildFactory for ContactNodes.
|
||||
*/
|
||||
final class ContactsChildNodeFactory extends ChildFactory<BlackboardArtifact>{
|
||||
private static final Logger logger = Logger.getLogger(MessagesChildNodeFactory.class.getName());
|
||||
|
||||
private SelectionInfo selectionInfo;
|
||||
|
||||
/**
|
||||
* Construct a new ContactsChildNodeFactory from the currently selectionInfo
|
||||
*
|
||||
* @param selectionInfo SelectionInfo object for the currently selected
|
||||
* accounts
|
||||
*/
|
||||
ContactsChildNodeFactory(SelectionInfo selectionInfo) {
|
||||
this.selectionInfo = selectionInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the current instance of selectionInfo and calls the refresh method.
|
||||
*
|
||||
* @param selectionInfo New instance of the currently selected accounts
|
||||
*/
|
||||
public void refresh(SelectionInfo selectionInfo) {
|
||||
this.selectionInfo = selectionInfo;
|
||||
refresh(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a list of Keys (BlackboardArtifact) for only contacts of the
|
||||
* currently selected accounts
|
||||
* @param list List of BlackboardArtifact to populate
|
||||
* @return True on success
|
||||
*/
|
||||
@Override
|
||||
protected boolean createKeys(List<BlackboardArtifact> list) {
|
||||
CommunicationsManager communicationManager;
|
||||
try {
|
||||
communicationManager = Case.getCurrentCaseThrows().getSleuthkitCase().getCommunicationsManager();
|
||||
} catch (NoCurrentCaseException | TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Failed to get communications manager from case.", ex); //NON-NLS
|
||||
return false;
|
||||
}
|
||||
|
||||
if(selectionInfo == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final Set<Content> relationshipSources;
|
||||
|
||||
try {
|
||||
relationshipSources = communicationManager.getRelationshipSources(selectionInfo.getAccountDevicesInstances(), selectionInfo.getCommunicationsFilter());
|
||||
|
||||
relationshipSources.stream().filter((content) -> (content instanceof BlackboardArtifact)).forEachOrdered((content) -> {
|
||||
|
||||
BlackboardArtifact bba = (BlackboardArtifact) content;
|
||||
BlackboardArtifact.ARTIFACT_TYPE fromID = BlackboardArtifact.ARTIFACT_TYPE.fromID(bba.getArtifactTypeID());
|
||||
|
||||
if (fromID == TSK_CONTACT) {
|
||||
list.add(bba);
|
||||
}
|
||||
});
|
||||
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Failed to get relationship sources.", ex); //NON-NLS
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Node createNodeForKey(BlackboardArtifact key) {
|
||||
return new ContactNode(key);
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<Form version="1.4" 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="outlineView" max="32767" attributes="0"/>
|
||||
<Component id="contactPane" alignment="0" 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="outlineView" pref="350" max="32767" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="1" max="-2" attributes="0"/>
|
||||
<Component id="contactPane" pref="400" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Component class="org.openide.explorer.view.OutlineView" name="outlineView">
|
||||
<AuxValues>
|
||||
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new org.openide.explorer.view.OutlineView()"/>
|
||||
</AuxValues>
|
||||
</Component>
|
||||
<Component class="org.sleuthkit.autopsy.communications.relationships.ContactDetailsPane" name="contactPane">
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Form>
|
186
Core/src/org/sleuthkit/autopsy/communications/relationships/ContactsViewer.java
Executable file
186
Core/src/org/sleuthkit/autopsy/communications/relationships/ContactsViewer.java
Executable file
@ -0,0 +1,186 @@
|
||||
/*
|
||||
* 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 obt ain 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.communications.relationships;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.KeyboardFocusManager;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.ListSelectionModel;
|
||||
import static javax.swing.SwingUtilities.isDescendingFrom;
|
||||
import org.netbeans.swing.outline.DefaultOutlineModel;
|
||||
import org.netbeans.swing.outline.Outline;
|
||||
import org.openide.explorer.ExplorerManager;
|
||||
import static org.openide.explorer.ExplorerUtils.createLookup;
|
||||
import org.openide.nodes.AbstractNode;
|
||||
import org.openide.nodes.Children;
|
||||
import org.openide.nodes.Node;
|
||||
import org.openide.util.Lookup;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.lookup.ServiceProvider;
|
||||
import org.sleuthkit.autopsy.communications.ModifiableProxyLookup;
|
||||
import org.sleuthkit.autopsy.corecomponents.TableFilterNode;
|
||||
import org.sleuthkit.autopsy.directorytree.DataResultFilterNode;
|
||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||
|
||||
/**
|
||||
* Visualization for contact nodes.
|
||||
*
|
||||
*/
|
||||
@ServiceProvider(service = RelationshipsViewer.class)
|
||||
public final class ContactsViewer extends JPanel implements RelationshipsViewer, ExplorerManager.Provider, Lookup.Provider {
|
||||
|
||||
private final ExplorerManager tableEM;
|
||||
private final Outline outline;
|
||||
private final ModifiableProxyLookup proxyLookup;
|
||||
private final PropertyChangeListener focusPropertyListener;
|
||||
private final ContactsChildNodeFactory nodeFactory;
|
||||
|
||||
@NbBundle.Messages({
|
||||
"ContactsViewer_tabTitle=Contacts",
|
||||
"ContactsViewer_columnHeader_Name=Name",
|
||||
"ContactsViewer_columnHeader_Phone=Phone",
|
||||
"ContactsViewer_columnHeader_Email=Email",})
|
||||
|
||||
/**
|
||||
* Visualization for contact nodes.
|
||||
*/
|
||||
public ContactsViewer() {
|
||||
tableEM = new ExplorerManager();
|
||||
proxyLookup = new ModifiableProxyLookup(createLookup(tableEM, getActionMap()));
|
||||
nodeFactory = new ContactsChildNodeFactory(null);
|
||||
|
||||
// See org.sleuthkit.autopsy.timeline.TimeLineTopComponent for a detailed
|
||||
// explaination of focusPropertyListener
|
||||
focusPropertyListener = (final PropertyChangeEvent focusEvent) -> {
|
||||
if (focusEvent.getPropertyName().equalsIgnoreCase("focusOwner")) {
|
||||
final Component newFocusOwner = (Component) focusEvent.getNewValue();
|
||||
|
||||
if (newFocusOwner == null) {
|
||||
return;
|
||||
}
|
||||
if (isDescendingFrom(newFocusOwner, contactPane)) {
|
||||
//if the focus owner is within the MessageContentViewer (the attachments table)
|
||||
proxyLookup.setNewLookups(createLookup(contactPane.getExplorerManager(), getActionMap()));
|
||||
} else if (isDescendingFrom(newFocusOwner, ContactsViewer.this)) {
|
||||
//... or if it is within the Results table.
|
||||
proxyLookup.setNewLookups(createLookup(tableEM, getActionMap()));
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
initComponents();
|
||||
|
||||
outline = outlineView.getOutline();
|
||||
outlineView.setPropertyColumns(
|
||||
"TSK_EMAIL", BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL.getDisplayName(),
|
||||
"TSK_PHONE_NUMBER", BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER.getDisplayName()
|
||||
);
|
||||
outline.setRootVisible(false);
|
||||
((DefaultOutlineModel) outline.getOutlineModel()).setNodesColumnLabel(Bundle.ContactsViewer_columnHeader_Name());
|
||||
|
||||
tableEM.addPropertyChangeListener((PropertyChangeEvent evt) -> {
|
||||
if (evt.getPropertyName().equals(ExplorerManager.PROP_SELECTED_NODES)) {
|
||||
final Node[] nodes = tableEM.getSelectedNodes();
|
||||
contactPane.setNode(nodes);
|
||||
}
|
||||
});
|
||||
|
||||
tableEM.setRootContext(new TableFilterNode(new DataResultFilterNode(new AbstractNode(Children.create(nodeFactory, true)), getExplorerManager()), true));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return Bundle.ContactsViewer_tabTitle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JPanel getPanel() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelectionInfo(SelectionInfo info) {
|
||||
contactPane.setNode(new Node[]{new AbstractNode(Children.LEAF)});
|
||||
contactPane.setEnabled(false);
|
||||
|
||||
nodeFactory.refresh(info);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExplorerManager getExplorerManager() {
|
||||
return tableEM;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Lookup getLookup() {
|
||||
return proxyLookup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNotify() {
|
||||
super.addNotify();
|
||||
//add listener that maintains correct selection in the Global Actions Context
|
||||
KeyboardFocusManager.getCurrentKeyboardFocusManager()
|
||||
.addPropertyChangeListener("focusOwner", focusPropertyListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeNotify() {
|
||||
super.removeNotify();
|
||||
KeyboardFocusManager.getCurrentKeyboardFocusManager()
|
||||
.removePropertyChangeListener("focusOwner", focusPropertyListener);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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() {
|
||||
|
||||
outlineView = new org.openide.explorer.view.OutlineView();
|
||||
contactPane = new org.sleuthkit.autopsy.communications.relationships.ContactDetailsPane();
|
||||
|
||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
||||
this.setLayout(layout);
|
||||
layout.setHorizontalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(outlineView, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(contactPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addComponent(outlineView, javax.swing.GroupLayout.DEFAULT_SIZE, 350, Short.MAX_VALUE)
|
||||
.addGap(1, 1, 1)
|
||||
.addComponent(contactPane, javax.swing.GroupLayout.DEFAULT_SIZE, 400, Short.MAX_VALUE))
|
||||
);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private org.sleuthkit.autopsy.communications.relationships.ContactDetailsPane contactPane;
|
||||
private org.openide.explorer.view.OutlineView outlineView;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
}
|
@ -0,0 +1,169 @@
|
||||
/*
|
||||
* 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.communications.relationships;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import org.openide.nodes.AbstractNode;
|
||||
import org.openide.nodes.ChildFactory;
|
||||
import org.openide.nodes.Children;
|
||||
import org.openide.nodes.Node;
|
||||
import org.openide.nodes.Sheet;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeNormalizationException;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.datamodel.NodeProperty;
|
||||
import org.sleuthkit.datamodel.Account;
|
||||
|
||||
/**
|
||||
* ChildFactory for CorrelationCases. Finds the cases that reference the given
|
||||
* list of accounts.
|
||||
*/
|
||||
final class CorrelationCaseChildNodeFactory extends ChildFactory<CorrelationCase> {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(CorrelationCaseChildNodeFactory.class.getName());
|
||||
|
||||
private Map<Integer, CorrelationAttributeInstance.Type> correlationTypeMap;
|
||||
private final Set<Account> accounts;
|
||||
|
||||
/**
|
||||
* ChildFactory for CorrelationCases.
|
||||
*
|
||||
* @param accounts List of Account objects
|
||||
*/
|
||||
CorrelationCaseChildNodeFactory(Set<Account> accounts) {
|
||||
this.accounts = accounts;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean createKeys(List<CorrelationCase> list) {
|
||||
if (!EamDb.isEnabled()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
EamDb dbInstance;
|
||||
try {
|
||||
dbInstance = EamDb.getInstance();
|
||||
} catch (EamDbException ex) {
|
||||
logger.log(Level.SEVERE, "Unable to connect to the Central Repository database.", ex); //NON-NLS
|
||||
return false;
|
||||
}
|
||||
|
||||
Map<String, CorrelationCase> uniqueCaseMap = new HashMap<>();
|
||||
|
||||
accounts.forEach((account) -> {
|
||||
try {
|
||||
CorrelationAttributeInstance.Type correlationType = getCorrelationType(account.getAccountType());
|
||||
if (correlationType != null) {
|
||||
List<CorrelationAttributeInstance> correlationInstances = dbInstance.getArtifactInstancesByTypeValue(correlationType, account.getTypeSpecificID());
|
||||
correlationInstances.forEach((correlationInstance) -> {
|
||||
CorrelationCase correlationCase = correlationInstance.getCorrelationCase();
|
||||
uniqueCaseMap.put(correlationCase.getCaseUUID(), correlationCase);
|
||||
});
|
||||
}
|
||||
} catch (EamDbException | CorrelationAttributeNormalizationException ex) {
|
||||
logger.log(Level.WARNING, String.format("Unable to getArtifactInstance for accountID: %d", account.getAccountID()), ex); //NON-NLS
|
||||
}
|
||||
});
|
||||
|
||||
list.addAll(uniqueCaseMap.values());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Node createNodeForKey(CorrelationCase correlationCase) {
|
||||
return new CaseNode(correlationCase);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the CorrelationAttributeInstance.Type for the given Account.Type.
|
||||
*
|
||||
* @param accountType Account type
|
||||
*
|
||||
* @return CorrelationAttributeInstance.Type for given account or null if
|
||||
* there is no match
|
||||
*
|
||||
* @throws EamDbException
|
||||
*/
|
||||
private CorrelationAttributeInstance.Type getCorrelationType(Account.Type accountType) throws EamDbException {
|
||||
if (correlationTypeMap == null) {
|
||||
correlationTypeMap = new HashMap<>();
|
||||
List<CorrelationAttributeInstance.Type> correcationTypeList = CorrelationAttributeInstance.getDefaultCorrelationTypes();
|
||||
correcationTypeList.forEach((type) -> {
|
||||
correlationTypeMap.put(type.getId(), type);
|
||||
});
|
||||
}
|
||||
|
||||
if (Account.Type.EMAIL.equals(accountType)) {
|
||||
return correlationTypeMap.get(CorrelationAttributeInstance.EMAIL_TYPE_ID);
|
||||
} else if (Account.Type.PHONE.equals(accountType)) {
|
||||
return correlationTypeMap.get(CorrelationAttributeInstance.PHONE_TYPE_ID);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple AbstractNode for a CorrelationCase. The property sheet only
|
||||
* contains the creation date.
|
||||
*/
|
||||
final class CaseNode extends AbstractNode {
|
||||
|
||||
private final CorrelationCase correlationCase;
|
||||
|
||||
/**
|
||||
* Construct the object, set the display name and icon.
|
||||
*
|
||||
* @param correlationCase
|
||||
*/
|
||||
CaseNode(CorrelationCase correlationCase) {
|
||||
super(Children.LEAF);
|
||||
this.correlationCase = correlationCase;
|
||||
|
||||
setDisplayName(correlationCase.getDisplayName());
|
||||
setIconBaseWithExtension("org/sleuthkit/autopsy/images/briefcase.png"); //NON-NLS
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Sheet createSheet() {
|
||||
super.createSheet();
|
||||
Sheet sheet = new Sheet();
|
||||
Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
|
||||
if (sheetSet == null) {
|
||||
sheetSet = Sheet.createPropertiesSet();
|
||||
sheet.put(sheetSet);
|
||||
}
|
||||
|
||||
sheetSet.put(new NodeProperty<>("creationDate", //NON-NLS
|
||||
correlationCase.getTitleCreationDate(),
|
||||
correlationCase.getTitleCreationDate(),
|
||||
correlationCase.getCreationDate()));
|
||||
|
||||
return sheet;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
68
Core/src/org/sleuthkit/autopsy/communications/relationships/MediaViewer.form
Executable file
68
Core/src/org/sleuthkit/autopsy/communications/relationships/MediaViewer.form
Executable file
@ -0,0 +1,68 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<Form version="1.4" 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="thumbnailViewer" alignment="1" max="32767" attributes="0"/>
|
||||
<Component id="contentViewer" alignment="1" max="32767" attributes="0"/>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="separator" max="32767" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Component id="thumbnailViewer" pref="350" max="32767" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="separator" min="-2" pref="2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="contentViewer" min="-2" pref="450" max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="3" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Component class="org.sleuthkit.autopsy.corecomponents.DataResultViewerThumbnail" name="thumbnailViewer">
|
||||
<Properties>
|
||||
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[350, 102]"/>
|
||||
</Property>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[450, 400]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<AuxValues>
|
||||
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new org.sleuthkit.autopsy.corecomponents.DataResultViewerThumbnail(tableEM)"/>
|
||||
</AuxValues>
|
||||
</Component>
|
||||
<Component class="org.sleuthkit.autopsy.contentviewers.MessageContentViewer" name="contentViewer">
|
||||
<Properties>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[450, 400]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<AuxValues>
|
||||
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new MessageDataContent()"/>
|
||||
</AuxValues>
|
||||
</Component>
|
||||
<Component class="javax.swing.JSeparator" name="separator">
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Form>
|
233
Core/src/org/sleuthkit/autopsy/communications/relationships/MediaViewer.java
Executable file
233
Core/src/org/sleuthkit/autopsy/communications/relationships/MediaViewer.java
Executable file
@ -0,0 +1,233 @@
|
||||
/*
|
||||
* 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 obt ain 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.communications.relationships;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.KeyboardFocusManager;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.JPanel;
|
||||
import static javax.swing.SwingUtilities.isDescendingFrom;
|
||||
import org.openide.explorer.ExplorerManager;
|
||||
import static org.openide.explorer.ExplorerUtils.createLookup;
|
||||
import org.openide.nodes.AbstractNode;
|
||||
import org.openide.nodes.Node;
|
||||
import org.openide.util.Lookup;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.communications.ModifiableProxyLookup;
|
||||
import org.sleuthkit.autopsy.corecomponents.TableFilterNode;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode;
|
||||
import org.sleuthkit.autopsy.directorytree.DataResultFilterNode;
|
||||
import org.sleuthkit.datamodel.AbstractContent;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.CommunicationsManager;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* A Panel that shows the media (thumbnails) for the selected account.
|
||||
*/
|
||||
final class MediaViewer extends JPanel implements RelationshipsViewer, ExplorerManager.Provider, Lookup.Provider {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(MediaViewer.class.getName());
|
||||
|
||||
private final ExplorerManager tableEM = new ExplorerManager();
|
||||
private final PropertyChangeListener focusPropertyListener;
|
||||
|
||||
private final ModifiableProxyLookup proxyLookup;
|
||||
|
||||
@Messages({
|
||||
"MediaViewer_Name=Media"
|
||||
})
|
||||
/**
|
||||
* Creates new form ThumbnailViewer
|
||||
*/
|
||||
public MediaViewer() {
|
||||
proxyLookup = new ModifiableProxyLookup(createLookup(tableEM, getActionMap()));
|
||||
|
||||
// See org.sleuthkit.autopsy.timeline.TimeLineTopComponent for a detailed
|
||||
// explaination of focusPropertyListener
|
||||
focusPropertyListener = (final PropertyChangeEvent focusEvent) -> {
|
||||
if (focusEvent.getPropertyName().equalsIgnoreCase("focusOwner")) {
|
||||
final Component newFocusOwner = (Component) focusEvent.getNewValue();
|
||||
|
||||
if (newFocusOwner == null) {
|
||||
return;
|
||||
}
|
||||
if (isDescendingFrom(newFocusOwner, contentViewer)) {
|
||||
//if the focus owner is within the MessageContentViewer (the attachments table)
|
||||
proxyLookup.setNewLookups(createLookup(((MessageDataContent) contentViewer).getExplorerManager(), getActionMap()));
|
||||
} else if (isDescendingFrom(newFocusOwner, MediaViewer.this)) {
|
||||
//... or if it is within the Results table.
|
||||
proxyLookup.setNewLookups(createLookup(tableEM, getActionMap()));
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
initComponents();
|
||||
|
||||
tableEM.addPropertyChangeListener((PropertyChangeEvent evt) -> {
|
||||
if (evt.getPropertyName().equals(ExplorerManager.PROP_SELECTED_NODES)) {
|
||||
handleNodeSelectionChange();
|
||||
}
|
||||
});
|
||||
|
||||
thumbnailViewer.resetComponent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return Bundle.MediaViewer_Name();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JPanel getPanel() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelectionInfo(SelectionInfo info) {
|
||||
final Set<Content> relationshipSources;
|
||||
|
||||
CommunicationsManager communicationManager;
|
||||
Set<BlackboardArtifact> artifactList = new HashSet<>();
|
||||
|
||||
try {
|
||||
communicationManager = Case.getCurrentCaseThrows().getSleuthkitCase().getCommunicationsManager();
|
||||
relationshipSources = communicationManager.getRelationshipSources(info.getAccountDevicesInstances(), info.getCommunicationsFilter());
|
||||
|
||||
relationshipSources.stream().filter((content) -> (content instanceof BlackboardArtifact)).forEachOrdered((content) -> {
|
||||
artifactList.add((BlackboardArtifact) content);
|
||||
});
|
||||
|
||||
} catch (TskCoreException | NoCurrentCaseException ex) {
|
||||
logger.log(Level.WARNING, "Unable to update selection." , ex);
|
||||
}
|
||||
|
||||
if(artifactList.size() == 0) {
|
||||
thumbnailViewer.resetComponent();
|
||||
}
|
||||
|
||||
thumbnailViewer.setNode(new TableFilterNode(new DataResultFilterNode(new AbstractNode(new AttachmentsChildren(artifactList)), tableEM), true, this.getClass().getName()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExplorerManager getExplorerManager() {
|
||||
return tableEM;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Lookup getLookup() {
|
||||
return proxyLookup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNotify() {
|
||||
super.addNotify();
|
||||
//add listener that maintains correct selection in the Global Actions Context
|
||||
KeyboardFocusManager.getCurrentKeyboardFocusManager()
|
||||
.addPropertyChangeListener("focusOwner", focusPropertyListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeNotify() {
|
||||
super.removeNotify();
|
||||
KeyboardFocusManager.getCurrentKeyboardFocusManager()
|
||||
.removePropertyChangeListener("focusOwner", focusPropertyListener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the change in thumbnail node selection.
|
||||
*/
|
||||
private void handleNodeSelectionChange() {
|
||||
final Node[] nodes = tableEM.getSelectedNodes();
|
||||
|
||||
if (nodes != null && nodes.length == 1) {
|
||||
AbstractContent thumbnail = nodes[0].getLookup().lookup(AbstractContent.class);
|
||||
if (thumbnail != null) {
|
||||
try {
|
||||
Content parentContent = thumbnail.getParent();
|
||||
if (parentContent != null && parentContent instanceof BlackboardArtifact) {
|
||||
contentViewer.setNode(new BlackboardArtifactNode((BlackboardArtifact) parentContent));
|
||||
}
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.WARNING, "Unable to get parent Content from AbstraceContent instance.", ex); //NON-NLS
|
||||
}
|
||||
}
|
||||
} else {
|
||||
contentViewer.setNode(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() {
|
||||
|
||||
thumbnailViewer = new org.sleuthkit.autopsy.corecomponents.DataResultViewerThumbnail(tableEM);
|
||||
contentViewer = new MessageDataContent();
|
||||
separator = new javax.swing.JSeparator();
|
||||
|
||||
thumbnailViewer.setMinimumSize(new java.awt.Dimension(350, 102));
|
||||
thumbnailViewer.setPreferredSize(new java.awt.Dimension(450, 400));
|
||||
|
||||
contentViewer.setPreferredSize(new java.awt.Dimension(450, 400));
|
||||
|
||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
||||
this.setLayout(layout);
|
||||
layout.setHorizontalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(thumbnailViewer, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(contentViewer, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addComponent(separator)
|
||||
.addContainerGap())
|
||||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addComponent(thumbnailViewer, javax.swing.GroupLayout.DEFAULT_SIZE, 350, Short.MAX_VALUE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(separator, javax.swing.GroupLayout.PREFERRED_SIZE, 2, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(contentViewer, javax.swing.GroupLayout.PREFERRED_SIZE, 450, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addGap(3, 3, 3))
|
||||
);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private org.sleuthkit.autopsy.contentviewers.MessageContentViewer contentViewer;
|
||||
private javax.swing.JSeparator separator;
|
||||
private org.sleuthkit.autopsy.corecomponents.DataResultViewerThumbnail thumbnailViewer;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
|
||||
}
|
@ -16,7 +16,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.communications;
|
||||
package org.sleuthkit.autopsy.communications.relationships;
|
||||
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import org.openide.explorer.ExplorerManager;
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2017-2018 Basis Technology Corp.
|
||||
* Copyright 2019 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -16,7 +16,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.communications;
|
||||
package org.sleuthkit.autopsy.communications.relationships;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.TimeZone;
|
||||
@ -25,12 +25,12 @@ import org.apache.commons.lang3.StringUtils;
|
||||
import org.openide.nodes.Sheet;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance;
|
||||
import org.sleuthkit.autopsy.core.UserPreferences;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode;
|
||||
import org.sleuthkit.autopsy.datamodel.NodeProperty;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||
import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
|
||||
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME;
|
||||
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_SENT;
|
||||
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_START;
|
||||
@ -43,24 +43,35 @@ import static org.sleuthkit.datamodel.BlackboardAttribute.TSK_BLACKBOARD_ATTRIBU
|
||||
import org.sleuthkit.datamodel.Tag;
|
||||
import org.sleuthkit.datamodel.TimeUtilities;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.autopsy.communications.Utils;
|
||||
|
||||
/**
|
||||
* Node for a relationship, as represented by a BlackboardArtifact.
|
||||
* Wraps a BlackboardArtifact as an AbstractNode for use in an OutlookView
|
||||
*/
|
||||
final class RelationshipNode extends BlackboardArtifactNode {
|
||||
final class MessageNode extends BlackboardArtifactNode {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(RelationshipNode.class.getName());
|
||||
private static final Logger logger = Logger.getLogger(MessageNode.class.getName());
|
||||
|
||||
RelationshipNode(BlackboardArtifact artifact) {
|
||||
MessageNode(BlackboardArtifact artifact) {
|
||||
super(artifact);
|
||||
final String stripEnd = StringUtils.stripEnd(artifact.getDisplayName(), "s");
|
||||
String removeEndIgnoreCase = StringUtils.removeEndIgnoreCase(stripEnd, "message");
|
||||
|
||||
final String stripEnd = StringUtils.stripEnd(artifact.getDisplayName(), "s"); // NON-NLS
|
||||
String removeEndIgnoreCase = StringUtils.removeEndIgnoreCase(stripEnd, "message"); // NON-NLS
|
||||
setDisplayName(removeEndIgnoreCase.isEmpty() ? stripEnd : removeEndIgnoreCase);
|
||||
}
|
||||
|
||||
@Messages({
|
||||
"MessageNode_Node_Property_Type=Type",
|
||||
"MessageNode_Node_Property_From=From",
|
||||
"MessageNode_Node_Property_To=To",
|
||||
"MessageNode_Node_Property_Date=Date",
|
||||
"MessageNode_Node_Property_Subject=Subject",
|
||||
"MessageNode_Node_Property_Attms=Attachments"
|
||||
})
|
||||
|
||||
@Override
|
||||
protected Sheet createSheet() {
|
||||
Sheet sheet = new Sheet();
|
||||
Sheet sheet = super.createSheet();
|
||||
List<Tag> tags = getAllTagsFromDatabase();
|
||||
Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
|
||||
if (sheetSet == null) {
|
||||
@ -68,62 +79,63 @@ final class RelationshipNode extends BlackboardArtifactNode {
|
||||
sheet.put(sheetSet);
|
||||
}
|
||||
|
||||
sheetSet.put(new NodeProperty<>("Type", "Type", "Type", getDisplayName()));
|
||||
|
||||
sheetSet.put(new NodeProperty<>("Type", Bundle.MessageNode_Node_Property_Type(), "", getDisplayName())); //NON-NLS
|
||||
|
||||
addScoreProperty(sheetSet, tags);
|
||||
|
||||
|
||||
CorrelationAttributeInstance correlationAttribute = null;
|
||||
if (UserPreferences.hideCentralRepoCommentsAndOccurrences()== false) {
|
||||
if (UserPreferences.hideCentralRepoCommentsAndOccurrences() == false) {
|
||||
correlationAttribute = getCorrelationAttributeInstance();
|
||||
}
|
||||
addCommentProperty(sheetSet, tags, correlationAttribute);
|
||||
|
||||
if (UserPreferences.hideCentralRepoCommentsAndOccurrences()== false) {
|
||||
|
||||
if (UserPreferences.hideCentralRepoCommentsAndOccurrences() == false) {
|
||||
addCountProperty(sheetSet, correlationAttribute);
|
||||
}
|
||||
final BlackboardArtifact artifact = getArtifact();
|
||||
BlackboardArtifact.ARTIFACT_TYPE fromID = BlackboardArtifact.ARTIFACT_TYPE.fromID(getArtifact().getArtifactTypeID());
|
||||
|
||||
BlackboardArtifact.ARTIFACT_TYPE fromID = BlackboardArtifact.ARTIFACT_TYPE.fromID(artifact.getArtifactTypeID());
|
||||
if (null != fromID) {
|
||||
//Consider refactoring this to reduce boilerplate
|
||||
switch (fromID) {
|
||||
case TSK_EMAIL_MSG:
|
||||
sheetSet.put(new NodeProperty<>("From", "From", "From",
|
||||
StringUtils.strip(getAttributeDisplayString(artifact, TSK_EMAIL_FROM), " \t\n;")));
|
||||
sheetSet.put(new NodeProperty<>("To", "To", "To",
|
||||
StringUtils.strip(getAttributeDisplayString(artifact, TSK_EMAIL_TO), " \t\n;")));
|
||||
sheetSet.put(new NodeProperty<>("Date", "Date", "Date",
|
||||
getAttributeDisplayString(artifact, TSK_DATETIME_SENT)));
|
||||
sheetSet.put(new NodeProperty<>("Subject", "Subject", "Subject",
|
||||
getAttributeDisplayString(artifact, TSK_SUBJECT)));
|
||||
sheetSet.put(new NodeProperty<>("From", Bundle.MessageNode_Node_Property_From(), "",
|
||||
StringUtils.strip(getAttributeDisplayString(artifact, TSK_EMAIL_FROM), " \t\n;"))); //NON-NLS
|
||||
sheetSet.put(new NodeProperty<>("To", Bundle.MessageNode_Node_Property_To(), "",
|
||||
StringUtils.strip(getAttributeDisplayString(artifact, TSK_EMAIL_TO), " \t\n;"))); //NON-NLS
|
||||
sheetSet.put(new NodeProperty<>("Date", Bundle.MessageNode_Node_Property_Date(), "",
|
||||
getAttributeDisplayString(artifact, TSK_DATETIME_SENT))); //NON-NLS
|
||||
sheetSet.put(new NodeProperty<>("Subject", Bundle.MessageNode_Node_Property_Subject(), "",
|
||||
getAttributeDisplayString(artifact, TSK_SUBJECT))); //NON-NLS
|
||||
try {
|
||||
sheetSet.put(new NodeProperty<>("Attms", "Attms", "Attms", artifact.getChildrenCount()));
|
||||
sheetSet.put(new NodeProperty<>("Attms", Bundle.MessageNode_Node_Property_Attms(), "", artifact.getChildrenCount())); //NON-NLS
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.WARNING, "Error loading attachment count for " + artifact, ex);
|
||||
logger.log(Level.WARNING, "Error loading attachment count for " + artifact, ex); //NON-NLS
|
||||
}
|
||||
|
||||
break;
|
||||
case TSK_MESSAGE:
|
||||
sheetSet.put(new NodeProperty<>("From", "From", "From",
|
||||
getAttributeDisplayString(artifact, TSK_PHONE_NUMBER_FROM)));
|
||||
sheetSet.put(new NodeProperty<>("To", "To", "To",
|
||||
getAttributeDisplayString(artifact, TSK_PHONE_NUMBER_TO)));
|
||||
sheetSet.put(new NodeProperty<>("Date", "Date", "Date",
|
||||
getAttributeDisplayString(artifact, TSK_DATETIME)));
|
||||
sheetSet.put(new NodeProperty<>("Subject", "Subject", "Subject",
|
||||
getAttributeDisplayString(artifact, TSK_SUBJECT)));
|
||||
sheetSet.put(new NodeProperty<>("From", Bundle.MessageNode_Node_Property_From(), "",
|
||||
getAttributeDisplayString(artifact, TSK_PHONE_NUMBER_FROM))); //NON-NLS
|
||||
sheetSet.put(new NodeProperty<>("To", Bundle.MessageNode_Node_Property_To(), "",
|
||||
getAttributeDisplayString(artifact, TSK_PHONE_NUMBER_TO))); //NON-NLS
|
||||
sheetSet.put(new NodeProperty<>("Date", Bundle.MessageNode_Node_Property_Date(), "",
|
||||
getAttributeDisplayString(artifact, TSK_DATETIME))); //NON-NLS
|
||||
sheetSet.put(new NodeProperty<>("Subject", Bundle.MessageNode_Node_Property_Subject(), "",
|
||||
getAttributeDisplayString(artifact, TSK_SUBJECT))); //NON-NLS
|
||||
try {
|
||||
sheetSet.put(new NodeProperty<>("Attms", "Attms", "Attms", artifact.getChildrenCount()));
|
||||
sheetSet.put(new NodeProperty<>("Attms", Bundle.MessageNode_Node_Property_Attms(), "", artifact.getChildrenCount())); //NON-NLS
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.WARNING, "Error loading attachment count for " + artifact, ex);
|
||||
logger.log(Level.WARNING, "Error loading attachment count for " + artifact, ex); //NON-NLS
|
||||
}
|
||||
break;
|
||||
case TSK_CALLLOG:
|
||||
sheetSet.put(new NodeProperty<>("From", "From", "From",
|
||||
getAttributeDisplayString(artifact, TSK_PHONE_NUMBER_FROM)));
|
||||
sheetSet.put(new NodeProperty<>("To", "To", "To",
|
||||
getAttributeDisplayString(artifact, TSK_PHONE_NUMBER_TO)));
|
||||
sheetSet.put(new NodeProperty<>("Date", "Date", "Date",
|
||||
getAttributeDisplayString(artifact, TSK_DATETIME_START)));
|
||||
sheetSet.put(new NodeProperty<>("From", Bundle.MessageNode_Node_Property_From(), "",
|
||||
getAttributeDisplayString(artifact, TSK_PHONE_NUMBER_FROM))); //NON-NLS
|
||||
sheetSet.put(new NodeProperty<>("To", Bundle.MessageNode_Node_Property_To(), "",
|
||||
getAttributeDisplayString(artifact, TSK_PHONE_NUMBER_TO))); //NON-NLS
|
||||
sheetSet.put(new NodeProperty<>("Date", Bundle.MessageNode_Node_Property_Date(), "",
|
||||
getAttributeDisplayString(artifact, TSK_DATETIME_START))); //NON-NLS
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -144,7 +156,7 @@ final class RelationshipNode extends BlackboardArtifactNode {
|
||||
* @return The display string, or an empty string if there is no such
|
||||
* attribute or an an error.
|
||||
*/
|
||||
private static String getAttributeDisplayString(final BlackboardArtifact artifact, final ATTRIBUTE_TYPE attributeType) {
|
||||
private static String getAttributeDisplayString(final BlackboardArtifact artifact, final BlackboardAttribute.ATTRIBUTE_TYPE attributeType) {
|
||||
try {
|
||||
BlackboardAttribute attribute = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.fromID(attributeType.getTypeID())));
|
||||
if (attribute == null) {
|
||||
@ -156,7 +168,7 @@ final class RelationshipNode extends BlackboardArtifactNode {
|
||||
return attribute.getDisplayString();
|
||||
}
|
||||
} catch (TskCoreException tskCoreException) {
|
||||
logger.log(Level.WARNING, "Error getting attribute value.", tskCoreException);
|
||||
logger.log(Level.WARNING, "Error getting attribute value.", tskCoreException); //NON-NLS
|
||||
return "";
|
||||
}
|
||||
}
|
@ -0,0 +1,115 @@
|
||||
/*
|
||||
* 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.communications.relationships;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import org.openide.nodes.ChildFactory;
|
||||
import org.openide.nodes.Node;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.CommunicationsManager;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* ChildFactory that creates createKeys and nodes from a given selectionInfo for
|
||||
* only emails, call logs and messages.
|
||||
*
|
||||
*/
|
||||
final class MessagesChildNodeFactory extends ChildFactory<BlackboardArtifact> {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(MessagesChildNodeFactory.class.getName());
|
||||
|
||||
private SelectionInfo selectionInfo;
|
||||
|
||||
/**
|
||||
* Construct a new MessageChildNodeFactory from the currently selectionInfo
|
||||
*
|
||||
* @param selectionInfo SelectionInfo object for the currently selected
|
||||
* accounts
|
||||
*/
|
||||
MessagesChildNodeFactory(SelectionInfo selectionInfo) {
|
||||
this.selectionInfo = selectionInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the current instance of selectionInfo and calls the refresh method.
|
||||
*
|
||||
* @param selectionInfo New instance of the currently selected accounts
|
||||
*/
|
||||
public void refresh(SelectionInfo selectionInfo) {
|
||||
this.selectionInfo = selectionInfo;
|
||||
refresh(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a list of Keys (BlackboardArtifact) for only messages for the
|
||||
* currently selected accounts
|
||||
*
|
||||
* @param list List of BlackboardArtifact to populate
|
||||
*
|
||||
* @return True on success
|
||||
*/
|
||||
@Override
|
||||
protected boolean createKeys(List<BlackboardArtifact> list) {
|
||||
CommunicationsManager communicationManager;
|
||||
try {
|
||||
communicationManager = Case.getCurrentCaseThrows().getSleuthkitCase().getCommunicationsManager();
|
||||
} catch (NoCurrentCaseException | TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Failed to get communications manager from case.", ex); //NON-NLS
|
||||
return false;
|
||||
}
|
||||
|
||||
if(selectionInfo == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final Set<Content> relationshipSources;
|
||||
|
||||
try {
|
||||
relationshipSources = communicationManager.getRelationshipSources(selectionInfo.getAccountDevicesInstances(), selectionInfo.getCommunicationsFilter());
|
||||
|
||||
relationshipSources.stream().filter((content) -> (content instanceof BlackboardArtifact)).forEachOrdered((content) -> {
|
||||
|
||||
BlackboardArtifact bba = (BlackboardArtifact) content;
|
||||
BlackboardArtifact.ARTIFACT_TYPE fromID = BlackboardArtifact.ARTIFACT_TYPE.fromID(bba.getArtifactTypeID());
|
||||
|
||||
if (fromID == BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG
|
||||
|| fromID == BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG
|
||||
|| fromID == BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE) {
|
||||
list.add(bba);
|
||||
}
|
||||
});
|
||||
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Failed to get relationship sources.", ex); //NON-NLS
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Node createNodeForKey(BlackboardArtifact key) {
|
||||
return new MessageNode(key);
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<Form version="1.4" 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="outlineView" alignment="0" max="32767" attributes="0"/>
|
||||
<Component id="contentViewer" alignment="1" 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="outlineView" pref="300" max="32767" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="contentViewer" pref="500" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Component class="org.openide.explorer.view.OutlineView" name="outlineView">
|
||||
</Component>
|
||||
<Component class="org.sleuthkit.autopsy.contentviewers.MessageContentViewer" name="contentViewer">
|
||||
<AuxValues>
|
||||
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new MessageDataContent()"/>
|
||||
</AuxValues>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Form>
|
194
Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesViewer.java
Executable file
194
Core/src/org/sleuthkit/autopsy/communications/relationships/MessagesViewer.java
Executable file
@ -0,0 +1,194 @@
|
||||
/*
|
||||
* 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 obt ain 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.communications.relationships;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.KeyboardFocusManager;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.ListSelectionModel;
|
||||
import static javax.swing.SwingUtilities.isDescendingFrom;
|
||||
import org.netbeans.swing.outline.DefaultOutlineModel;
|
||||
import org.netbeans.swing.outline.Outline;
|
||||
import org.openide.explorer.ExplorerManager;
|
||||
import static org.openide.explorer.ExplorerUtils.createLookup;
|
||||
import org.openide.nodes.AbstractNode;
|
||||
import org.openide.nodes.Children;
|
||||
import org.openide.nodes.Node;
|
||||
import org.openide.util.Lookup;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.openide.util.lookup.ServiceProvider;
|
||||
import org.sleuthkit.autopsy.communications.ModifiableProxyLookup;
|
||||
import org.sleuthkit.autopsy.corecomponents.TableFilterNode;
|
||||
import org.sleuthkit.autopsy.directorytree.DataResultFilterNode;
|
||||
|
||||
/**
|
||||
* Visualation for the messages of the currently selected accounts.
|
||||
*/
|
||||
@ServiceProvider(service = RelationshipsViewer.class)
|
||||
public final class MessagesViewer extends JPanel implements RelationshipsViewer, ExplorerManager.Provider, Lookup.Provider {
|
||||
|
||||
private final ExplorerManager tableEM;
|
||||
private final Outline outline;
|
||||
private final ModifiableProxyLookup proxyLookup;
|
||||
private final PropertyChangeListener focusPropertyListener;
|
||||
private final MessagesChildNodeFactory nodeFactory;
|
||||
|
||||
@Messages({
|
||||
"MessageViewer_tabTitle=Messages",
|
||||
"MessageViewer_columnHeader_From=From",
|
||||
"MessageViewer_columnHeader_To=To",
|
||||
"MessageViewer_columnHeader_Date=Date",
|
||||
"MessageViewer_columnHeader_Subject=Subject",
|
||||
"MessageViewer_columnHeader_Attms=Attachments"
|
||||
})
|
||||
|
||||
/**
|
||||
* Visualation for the messages of the currently selected accounts.
|
||||
*/
|
||||
public MessagesViewer() {
|
||||
tableEM = new ExplorerManager();
|
||||
proxyLookup = new ModifiableProxyLookup(createLookup(tableEM, getActionMap()));
|
||||
nodeFactory = new MessagesChildNodeFactory(null);
|
||||
|
||||
// See org.sleuthkit.autopsy.timeline.TimeLineTopComponent for a detailed
|
||||
// explaination of focusPropertyListener
|
||||
focusPropertyListener = (final PropertyChangeEvent focusEvent) -> {
|
||||
if (focusEvent.getPropertyName().equalsIgnoreCase("focusOwner")) {
|
||||
final Component newFocusOwner = (Component) focusEvent.getNewValue();
|
||||
|
||||
if (newFocusOwner == null) {
|
||||
return;
|
||||
}
|
||||
if (isDescendingFrom(newFocusOwner, contentViewer)) {
|
||||
//if the focus owner is within the MessageContentViewer (the attachments table)
|
||||
proxyLookup.setNewLookups(createLookup(((MessageDataContent) contentViewer).getExplorerManager(), getActionMap()));
|
||||
} else if (isDescendingFrom(newFocusOwner, MessagesViewer.this)) {
|
||||
//... or if it is within the Results table.
|
||||
proxyLookup.setNewLookups(createLookup(tableEM, getActionMap()));
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
initComponents();
|
||||
|
||||
outline = outlineView.getOutline();
|
||||
outlineView.setPropertyColumns(
|
||||
"From", Bundle.MessageViewer_columnHeader_From(),
|
||||
"To", Bundle.MessageViewer_columnHeader_To(),
|
||||
"Date", Bundle.MessageViewer_columnHeader_Date(),
|
||||
"Subject", Bundle.MessageViewer_columnHeader_Subject(),
|
||||
"Attms", Bundle.MessageViewer_columnHeader_Attms(),
|
||||
"Type", "Type"
|
||||
);
|
||||
outline.setRootVisible(false);
|
||||
((DefaultOutlineModel) outline.getOutlineModel()).setNodesColumnLabel("Type");
|
||||
|
||||
tableEM.addPropertyChangeListener((PropertyChangeEvent evt) -> {
|
||||
if (evt.getPropertyName().equals(ExplorerManager.PROP_SELECTED_NODES)) {
|
||||
final Node[] nodes = tableEM.getSelectedNodes();
|
||||
|
||||
if (nodes != null && nodes.length == 1) {
|
||||
contentViewer.setNode(nodes[0]);
|
||||
}
|
||||
else {
|
||||
contentViewer.setNode(null);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
tableEM.setRootContext(new TableFilterNode(new DataResultFilterNode(new AbstractNode(Children.create(nodeFactory, true)), getExplorerManager()), true));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return Bundle.MessageViewer_tabTitle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JPanel getPanel() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelectionInfo(SelectionInfo info) {
|
||||
nodeFactory.refresh(info);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExplorerManager getExplorerManager() {
|
||||
return tableEM;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Lookup getLookup() {
|
||||
return proxyLookup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNotify() {
|
||||
super.addNotify();
|
||||
//add listener that maintains correct selection in the Global Actions Context
|
||||
KeyboardFocusManager.getCurrentKeyboardFocusManager()
|
||||
.addPropertyChangeListener("focusOwner", focusPropertyListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeNotify() {
|
||||
super.removeNotify();
|
||||
KeyboardFocusManager.getCurrentKeyboardFocusManager()
|
||||
.removePropertyChangeListener("focusOwner", focusPropertyListener);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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() {
|
||||
|
||||
outlineView = new org.openide.explorer.view.OutlineView();
|
||||
contentViewer = new MessageDataContent();
|
||||
|
||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
||||
this.setLayout(layout);
|
||||
layout.setHorizontalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(outlineView, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(contentViewer, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addComponent(outlineView, javax.swing.GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(contentViewer, javax.swing.GroupLayout.DEFAULT_SIZE, 500, Short.MAX_VALUE))
|
||||
);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private org.sleuthkit.autopsy.contentviewers.MessageContentViewer contentViewer;
|
||||
private org.openide.explorer.view.OutlineView outlineView;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
<?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,-45,0,0,1,-32"/>
|
||||
</AuxValues>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignCardLayout">
|
||||
<Property name="horizontalGap" type="int" value="5"/>
|
||||
<Property name="verticalGap" type="int" value="5"/>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Component class="org.openide.explorer.view.OutlineView" name="outlineView">
|
||||
<Properties>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[300, 400]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignCardLayout" value="org.netbeans.modules.form.compat2.layouts.DesignCardLayout$CardConstraintsDescription">
|
||||
<CardConstraints cardName="outlineCard"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Container class="javax.swing.JPanel" name="messagePanel">
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignCardLayout" value="org.netbeans.modules.form.compat2.layouts.DesignCardLayout$CardConstraintsDescription">
|
||||
<CardConstraints cardName="messageCard"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JLabel" name="messageLabel">
|
||||
<Properties>
|
||||
<Property name="horizontalAlignment" type="int" value="0"/>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/communications/relationships/Bundle.properties" key="OutlineViewPanel.messageLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="enabled" type="boolean" value="false"/>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
|
||||
<BorderConstraints direction="Center"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
</SubComponents>
|
||||
</Form>
|
@ -0,0 +1,132 @@
|
||||
/*
|
||||
* 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 obt ain 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.communications.relationships;
|
||||
|
||||
import java.awt.CardLayout;
|
||||
import org.openide.explorer.ExplorerManager;
|
||||
import static org.openide.explorer.ExplorerUtils.createLookup;
|
||||
import org.openide.explorer.view.OutlineView;
|
||||
import org.openide.nodes.Node;;
|
||||
import org.openide.util.Lookup;
|
||||
|
||||
/**
|
||||
* This class is a simple wrapper around a OutlineView with its own ExplorerManager.
|
||||
*
|
||||
* This panel has the added feature of being able to hide the OutlineView and show
|
||||
* a message.
|
||||
*
|
||||
*/
|
||||
public class OutlineViewPanel extends javax.swing.JPanel implements ExplorerManager.Provider, Lookup.Provider{
|
||||
|
||||
private final ExplorerManager tableEm;
|
||||
private final Lookup lookup;
|
||||
/**
|
||||
* Creates new form OutlineViewPanel
|
||||
*/
|
||||
public OutlineViewPanel() {
|
||||
tableEm = new ExplorerManager();
|
||||
lookup = createLookup(tableEm, getActionMap());
|
||||
|
||||
initComponents();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExplorerManager getExplorerManager() {
|
||||
return tableEm;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Lookup getLookup() {
|
||||
return lookup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide the OutlineView and replace with a panel with the given message.
|
||||
*
|
||||
* @param message String message to show on the panel.
|
||||
*/
|
||||
public void hideOutlineView(String message) {
|
||||
CardLayout layout = (CardLayout)this.getLayout();
|
||||
layout.show(this, "messageCard"); //NON-NLS
|
||||
messageLabel.setText(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides the message panel and shows the OutlineView.
|
||||
*/
|
||||
public void showOutlineView() {
|
||||
CardLayout layout = (CardLayout)this.getLayout();
|
||||
layout.show(this, "outlineCard"); //NON-NLS
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the OutlineView instance for ease of customization.
|
||||
*
|
||||
* @return Returns the OutlineView
|
||||
*/
|
||||
public OutlineView getOutlineView() {
|
||||
return outlineView;
|
||||
}
|
||||
|
||||
public void setNode(Node node) {
|
||||
tableEm.setRootContext(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEnabled(boolean enabled) {
|
||||
super.setEnabled(enabled);
|
||||
outlineView.setEnabled(enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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() {
|
||||
|
||||
outlineView = new org.openide.explorer.view.OutlineView();
|
||||
messagePanel = new javax.swing.JPanel();
|
||||
messageLabel = new javax.swing.JLabel();
|
||||
|
||||
setLayout(new java.awt.CardLayout(5, 5));
|
||||
|
||||
outlineView.setPreferredSize(new java.awt.Dimension(300, 400));
|
||||
add(outlineView, "outlineCard");
|
||||
|
||||
messagePanel.setLayout(new java.awt.BorderLayout());
|
||||
|
||||
messageLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
|
||||
org.openide.awt.Mnemonics.setLocalizedText(messageLabel, org.openide.util.NbBundle.getMessage(OutlineViewPanel.class, "OutlineViewPanel.messageLabel.text")); // NOI18N
|
||||
messageLabel.setEnabled(false);
|
||||
messagePanel.add(messageLabel, java.awt.BorderLayout.CENTER);
|
||||
|
||||
add(messagePanel, "messageCard");
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JLabel messageLabel;
|
||||
private javax.swing.JPanel messagePanel;
|
||||
private org.openide.explorer.view.OutlineView outlineView;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
|
||||
}
|
@ -5,7 +5,7 @@
|
||||
<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="false"/>
|
||||
<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"/>
|
||||
@ -16,40 +16,36 @@
|
||||
<Layout>
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="1" attributes="0">
|
||||
<EmptySpace min="-2" pref="0" max="-2" attributes="0"/>
|
||||
<Component id="splitPane" max="32767" attributes="0"/>
|
||||
<EmptySpace min="0" pref="400" max="32767" attributes="0"/>
|
||||
<Group type="103" rootIndex="1" groupAlignment="0" attributes="0">
|
||||
<Component id="scrollPane" alignment="1" max="32767" 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="0" max="-2" attributes="0"/>
|
||||
<Component id="splitPane" pref="1083" max="32767" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="0" max="-2" attributes="0"/>
|
||||
<EmptySpace min="0" pref="300" max="32767" attributes="0"/>
|
||||
<Group type="103" rootIndex="1" groupAlignment="0" attributes="0">
|
||||
<Component id="scrollPane" alignment="0" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Container class="javax.swing.JSplitPane" name="splitPane">
|
||||
<Container class="javax.swing.JScrollPane" name="scrollPane">
|
||||
<Properties>
|
||||
<Property name="dividerLocation" type="int" value="400"/>
|
||||
<Property name="dividerSize" type="int" value="10"/>
|
||||
<Property name="orientation" type="int" value="0"/>
|
||||
<Property name="resizeWeight" type="double" value="0.5"/>
|
||||
<Property name="verticalScrollBarPolicy" type="int" value="21"/>
|
||||
</Properties>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout"/>
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
|
||||
<SubComponents>
|
||||
<Component class="org.sleuthkit.autopsy.communications.MessageDataContent" name="messageDataContent">
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout$JSplitPaneConstraintsDescription">
|
||||
<JSplitPaneConstraints position="bottom"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Container class="javax.swing.JTabbedPane" name="tabPane">
|
||||
<Events>
|
||||
<EventHandler event="stateChanged" listener="javax.swing.event.ChangeListener" parameters="javax.swing.event.ChangeEvent" handler="tabPaneStateChanged"/>
|
||||
</Events>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout"/>
|
||||
</Container>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
</SubComponents>
|
@ -0,0 +1,132 @@
|
||||
/*
|
||||
* 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 obt ain 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.communications.relationships;
|
||||
|
||||
import java.awt.Component;
|
||||
import javax.swing.JPanel;
|
||||
import org.openide.util.Lookup;
|
||||
import org.sleuthkit.autopsy.communications.ModifiableProxyLookup;
|
||||
|
||||
/**
|
||||
* Displays the Relationship information for the currently selected accounts.
|
||||
*
|
||||
*/
|
||||
public final class RelationshipBrowser extends JPanel implements Lookup.Provider {
|
||||
|
||||
private SelectionInfo currentSelection;
|
||||
|
||||
private final MessagesViewer messagesViewer;
|
||||
private final ContactsViewer contactsViewer;
|
||||
private final SummaryViewer summaryViewer;
|
||||
private final MediaViewer mediaViewer;
|
||||
|
||||
private final ModifiableProxyLookup proxyLookup;
|
||||
|
||||
/**
|
||||
* Creates new form RelationshipBrowser
|
||||
*/
|
||||
public RelationshipBrowser() {
|
||||
messagesViewer = new MessagesViewer();
|
||||
contactsViewer = new ContactsViewer();
|
||||
summaryViewer = new SummaryViewer();
|
||||
mediaViewer = new MediaViewer();
|
||||
|
||||
proxyLookup = new ModifiableProxyLookup(messagesViewer.getLookup());
|
||||
|
||||
initComponents();
|
||||
|
||||
tabPane.add(summaryViewer.getDisplayName(), summaryViewer);
|
||||
tabPane.add(messagesViewer.getDisplayName(), messagesViewer);
|
||||
tabPane.add(contactsViewer.getDisplayName(), contactsViewer);
|
||||
tabPane.add(mediaViewer.getDisplayName(), mediaViewer);
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of currentSelection and passes the SelectionInfo onto the
|
||||
* currently selected\visible tab.
|
||||
*
|
||||
* @param info Currently selected account nodes
|
||||
*/
|
||||
public void setSelectionInfo(SelectionInfo info) {
|
||||
currentSelection = info;
|
||||
((RelationshipsViewer) tabPane.getSelectedComponent()).setSelectionInfo(info);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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() {
|
||||
|
||||
scrollPane = new javax.swing.JScrollPane();
|
||||
tabPane = new javax.swing.JTabbedPane();
|
||||
|
||||
scrollPane.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER);
|
||||
|
||||
tabPane.addChangeListener(new javax.swing.event.ChangeListener() {
|
||||
public void stateChanged(javax.swing.event.ChangeEvent evt) {
|
||||
tabPaneStateChanged(evt);
|
||||
}
|
||||
});
|
||||
scrollPane.setViewportView(tabPane);
|
||||
|
||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
||||
this.setLayout(layout);
|
||||
layout.setHorizontalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGap(0, 400, Short.MAX_VALUE)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(scrollPane, javax.swing.GroupLayout.Alignment.TRAILING))
|
||||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGap(0, 300, Short.MAX_VALUE)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(scrollPane))
|
||||
);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
private void tabPaneStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_tabPaneStateChanged
|
||||
if(currentSelection != null) {
|
||||
((RelationshipsViewer) tabPane.getSelectedComponent()).setSelectionInfo(currentSelection);
|
||||
}
|
||||
|
||||
Component selectedComponent = tabPane.getSelectedComponent();
|
||||
if(selectedComponent instanceof Lookup.Provider) {
|
||||
Lookup lookup = ((Lookup.Provider)selectedComponent).getLookup();
|
||||
proxyLookup.setNewLookups(lookup);
|
||||
}
|
||||
}//GEN-LAST:event_tabPaneStateChanged
|
||||
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JScrollPane scrollPane;
|
||||
private javax.swing.JTabbedPane tabPane;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
|
||||
@Override
|
||||
public Lookup getLookup() {
|
||||
return proxyLookup;
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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 obt ain 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.communications.relationships;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
import org.openide.util.Lookup;
|
||||
|
||||
/**
|
||||
* Interface for Controls wishing to appear in the RelationshipBrowser tabPane.
|
||||
*/
|
||||
public interface RelationshipsViewer extends Lookup.Provider {
|
||||
|
||||
/**
|
||||
* Returns the value to be displayed on the "tab"
|
||||
*
|
||||
* @return String display name
|
||||
*/
|
||||
public String getDisplayName();
|
||||
|
||||
/**
|
||||
* Returns the JPanel to be displayed in the RelationshipBrowser.
|
||||
*
|
||||
* @return JPanel to be displayed
|
||||
*/
|
||||
public JPanel getPanel();
|
||||
|
||||
/**
|
||||
* Sets current SelectionInfo allowing the panel to update accordingly.
|
||||
*
|
||||
* @param info SelectionInfo instance representing the currently selected
|
||||
* accounts
|
||||
*/
|
||||
public void setSelectionInfo(SelectionInfo info);
|
||||
}
|
185
Core/src/org/sleuthkit/autopsy/communications/relationships/SelectionInfo.java
Executable file
185
Core/src/org/sleuthkit/autopsy/communications/relationships/SelectionInfo.java
Executable file
@ -0,0 +1,185 @@
|
||||
/*
|
||||
* 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 obt ain 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.communications.relationships;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.datamodel.Account;
|
||||
import org.sleuthkit.datamodel.AccountDeviceInstance;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.CommunicationsFilter;
|
||||
import org.sleuthkit.datamodel.CommunicationsManager;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* Class to wrap the details of the current selection from the AccountBrowser or
|
||||
* VisualizationPane
|
||||
*/
|
||||
public final class SelectionInfo {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(SelectionInfo.class.getName());
|
||||
|
||||
private final Set<AccountDeviceInstance> accountDeviceInstances;
|
||||
private final CommunicationsFilter communicationFilter;
|
||||
private final Set<Account> accounts;
|
||||
|
||||
private Set<BlackboardArtifact> accountArtifacts = null;
|
||||
private SelectionSummary summary = null;
|
||||
|
||||
/**
|
||||
* Wraps the details of the currently selected accounts.
|
||||
*
|
||||
* @param accountDeviceInstances Selected accountDecivedInstances
|
||||
* @param communicationFilter Currently selected communications filters
|
||||
*/
|
||||
public SelectionInfo(Set<AccountDeviceInstance> accountDeviceInstances, CommunicationsFilter communicationFilter) {
|
||||
this.accountDeviceInstances = accountDeviceInstances;
|
||||
this.communicationFilter = communicationFilter;
|
||||
|
||||
accounts = new HashSet<>();
|
||||
accountDeviceInstances.forEach((instance) -> {
|
||||
accounts.add(instance.getAccount());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the currently selected accountDeviceInstances
|
||||
*
|
||||
* @return Set of AccountDeviceInstance
|
||||
*/
|
||||
public Set<AccountDeviceInstance> getAccountDevicesInstances() {
|
||||
return accountDeviceInstances;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the currently selected communications filters.
|
||||
*
|
||||
* @return Instance of CommunicationsFilter
|
||||
*/
|
||||
public CommunicationsFilter getCommunicationsFilter() {
|
||||
return communicationFilter;
|
||||
}
|
||||
|
||||
public Set<Account> getAccounts() {
|
||||
return accounts;
|
||||
}
|
||||
|
||||
public Set<BlackboardArtifact> getArtifacts() {
|
||||
if(accountArtifacts == null) {
|
||||
accountArtifacts = new HashSet<>();
|
||||
CommunicationsManager communicationManager;
|
||||
try {
|
||||
communicationManager = Case.getCurrentCaseThrows().getSleuthkitCase().getCommunicationsManager();
|
||||
} catch (NoCurrentCaseException | TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Failed to get communications manager from case.", ex); //NON-NLS
|
||||
return null;
|
||||
}
|
||||
|
||||
final Set<Content> relationshipSources;
|
||||
|
||||
try {
|
||||
relationshipSources = communicationManager.getRelationshipSources(getAccountDevicesInstances(), getCommunicationsFilter());
|
||||
|
||||
relationshipSources.stream().filter((content) -> (content instanceof BlackboardArtifact)).forEachOrdered((content) -> {
|
||||
accountArtifacts.add((BlackboardArtifact) content);
|
||||
});
|
||||
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Failed to get relationship sources.", ex); //NON-NLS
|
||||
}
|
||||
}
|
||||
|
||||
return accountArtifacts;
|
||||
}
|
||||
|
||||
public SelectionSummary getSummary() {
|
||||
if(summary == null) {
|
||||
summary = new SelectionSummary();
|
||||
}
|
||||
|
||||
return summary;
|
||||
}
|
||||
|
||||
final class SelectionSummary{
|
||||
int attachmentCnt;
|
||||
int messagesCnt;
|
||||
int emailCnt;
|
||||
int callLogCnt;
|
||||
int contactsCnt;
|
||||
|
||||
SelectionSummary() {
|
||||
getCounts();
|
||||
}
|
||||
|
||||
private void getCounts(){
|
||||
for(BlackboardArtifact artifact: getArtifacts()) {
|
||||
BlackboardArtifact.ARTIFACT_TYPE fromID = BlackboardArtifact.ARTIFACT_TYPE.fromID(artifact.getArtifactTypeID());
|
||||
if(null != fromID) switch (fromID) {
|
||||
case TSK_EMAIL_MSG:
|
||||
emailCnt++;
|
||||
break;
|
||||
case TSK_CALLLOG:
|
||||
callLogCnt++;
|
||||
break;
|
||||
case TSK_MESSAGE:
|
||||
messagesCnt++;
|
||||
break;
|
||||
case TSK_CONTACT:
|
||||
contactsCnt++;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
try{
|
||||
attachmentCnt+= artifact.getChildrenCount();
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.WARNING, String.format("Exception thrown "
|
||||
+ "from getChildrenCount artifactID: %d",
|
||||
artifact.getArtifactID()), ex); //NON-NLS
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int getAttachmentCnt() {
|
||||
return attachmentCnt;
|
||||
}
|
||||
|
||||
public int getMessagesCnt() {
|
||||
return messagesCnt;
|
||||
}
|
||||
|
||||
public int getEmailCnt() {
|
||||
return emailCnt;
|
||||
}
|
||||
|
||||
public int getCallLogCnt() {
|
||||
return callLogCnt;
|
||||
}
|
||||
|
||||
public int getContactsCnt() {
|
||||
return contactsCnt;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
215
Core/src/org/sleuthkit/autopsy/communications/relationships/SummaryViewer.form
Executable file
215
Core/src/org/sleuthkit/autopsy/communications/relationships/SummaryViewer.form
Executable file
@ -0,0 +1,215 @@
|
||||
<?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" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="countsPanel" max="32767" attributes="0"/>
|
||||
<Component id="fileReferencesPanel" alignment="0" pref="485" max="32767" attributes="0"/>
|
||||
<Component id="caseReferencesPanel" alignment="1" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace 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 max="-2" attributes="0"/>
|
||||
<Component id="countsPanel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="fileReferencesPanel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="caseReferencesPanel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Container class="javax.swing.JPanel" name="countsPanel">
|
||||
<Properties>
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
|
||||
<TitledBorder title="Counts">
|
||||
<ResourceString PropertyName="titleX" bundle="org/sleuthkit/autopsy/communications/relationships/Bundle.properties" key="SummaryViewer.countsPanel.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</TitledBorder>
|
||||
</Border>
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
<Layout>
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="attachmentsLabel" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="messagesLabel" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="callLogsLabel" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="contactsLabel" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="emailLabel" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace type="separate" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="emailDataLabel" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="contactsDataLabel" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="callLogsDataLabel" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="messagesDataLabel" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="attachmentsDataLabel" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="32767" 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="7" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="attachmentsLabel" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="attachmentsDataLabel" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="messagesLabel" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="messagesDataLabel" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="callLogsLabel" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="callLogsDataLabel" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="contactsLabel" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="contactsDataLabel" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="emailLabel" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="emailDataLabel" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JLabel" name="emailLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/communications/relationships/Bundle.properties" key="SummaryViewer.emailLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="contactsLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/communications/Bundle.properties" key="SummaryViewer.contactsLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="messagesLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/communications/relationships/Bundle.properties" key="SummaryViewer.messagesLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="callLogsLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/communications/relationships/Bundle.properties" key="SummaryViewer.callLogsLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="attachmentsLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/communications/relationships/Bundle.properties" key="SummaryViewer.attachmentsLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="attachmentsDataLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/communications/relationships/Bundle.properties" key="SummaryViewer.attachmentsDataLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="messagesDataLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/communications/relationships/Bundle.properties" key="SummaryViewer.messagesDataLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="callLogsDataLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/communications/relationships/Bundle.properties" key="SummaryViewer.callLogsDataLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="contactsDataLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/communications/relationships/Bundle.properties" key="SummaryViewer.contactsDataLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="emailDataLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/communications/relationships/Bundle.properties" key="SummaryViewer.emailDataLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
<Component class="org.sleuthkit.autopsy.communications.OutlineViewPanel" name="fileReferencesPanel">
|
||||
<Properties>
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
|
||||
<TitledBorder title="File References in Current Case">
|
||||
<ResourceString PropertyName="titleX" bundle="org/sleuthkit/autopsy/communications/relationships/Bundle.properties" key="SummaryViewer.fileReferencesPanel.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</TitledBorder>
|
||||
</Border>
|
||||
</Property>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[472, 300]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="org.sleuthkit.autopsy.communications.OutlineViewPanel" name="caseReferencesPanel">
|
||||
<Properties>
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
|
||||
<TitledBorder title="Other Occurrences">
|
||||
<ResourceString PropertyName="titleX" bundle="org/sleuthkit/autopsy/communications/relationships/Bundle.properties" key="SummaryViewer.caseReferencesPanel.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</TitledBorder>
|
||||
</Border>
|
||||
</Property>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[472, 300]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Form>
|
313
Core/src/org/sleuthkit/autopsy/communications/relationships/SummaryViewer.java
Executable file
313
Core/src/org/sleuthkit/autopsy/communications/relationships/SummaryViewer.java
Executable file
@ -0,0 +1,313 @@
|
||||
/*
|
||||
* 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 obt ain 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.communications.relationships;
|
||||
|
||||
import java.util.Set;
|
||||
import javax.swing.JPanel;
|
||||
import org.netbeans.swing.outline.DefaultOutlineModel;
|
||||
import org.netbeans.swing.outline.Outline;
|
||||
import org.openide.explorer.view.OutlineView;
|
||||
import org.openide.nodes.AbstractNode;
|
||||
import org.openide.nodes.Children;
|
||||
import org.openide.util.Lookup;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb;
|
||||
import org.sleuthkit.autopsy.communications.relationships.SelectionInfo.SelectionSummary;
|
||||
import org.sleuthkit.datamodel.Account;
|
||||
|
||||
/**
|
||||
* Account Summary View Panel. This panel shows a list of various counts related
|
||||
* to the currently selected account. As well has a panel showing a list of
|
||||
* cases and files that reference the account.
|
||||
*
|
||||
*/
|
||||
public class SummaryViewer extends javax.swing.JPanel implements RelationshipsViewer {
|
||||
|
||||
private final Lookup lookup;
|
||||
|
||||
@Messages({
|
||||
"SummaryViewer_TabTitle=Summary",
|
||||
"SummaryViewer_FileRefNameColumn_Title=Path",
|
||||
"SummaryViewer_CaseRefNameColumn_Title=Case Name",
|
||||
"SummaryViewer_CentralRepository_Message=<Enable Central Resposity to see Case References>",
|
||||
"SummaryViewer_Creation_Date_Title=Creation Date"
|
||||
})
|
||||
|
||||
/**
|
||||
* Creates new form SummaryViewer
|
||||
*/
|
||||
public SummaryViewer() {
|
||||
lookup = Lookup.getDefault();
|
||||
initComponents();
|
||||
|
||||
OutlineView outlineView = fileReferencesPanel.getOutlineView();
|
||||
Outline outline = outlineView.getOutline();
|
||||
|
||||
outline.setRootVisible(false);
|
||||
((DefaultOutlineModel) outline.getOutlineModel()).setNodesColumnLabel(Bundle.SummaryViewer_FileRefNameColumn_Title());
|
||||
|
||||
outlineView = caseReferencesPanel.getOutlineView();
|
||||
outline = outlineView.getOutline();
|
||||
outlineView.setPropertyColumns("creationDate", Bundle.SummaryViewer_Creation_Date_Title()); //NON-NLS
|
||||
|
||||
outline.setRootVisible(false);
|
||||
((DefaultOutlineModel) outline.getOutlineModel()).setNodesColumnLabel(Bundle.SummaryViewer_CaseRefNameColumn_Title());
|
||||
|
||||
clearControls();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return Bundle.SummaryViewer_TabTitle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JPanel getPanel() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelectionInfo(SelectionInfo info) {
|
||||
|
||||
if (!EamDb.isEnabled()) {
|
||||
caseReferencesPanel.hideOutlineView(Bundle.SummaryViewer_CentralRepository_Message());
|
||||
} else {
|
||||
caseReferencesPanel.showOutlineView();
|
||||
}
|
||||
|
||||
// Request is that the SummaryViewer only show information if one
|
||||
// account is selected
|
||||
if (info.getAccounts().size() != 1) {
|
||||
setEnabled(false);
|
||||
clearControls();
|
||||
|
||||
} else {
|
||||
SelectionSummary summaryDetails = info.getSummary();
|
||||
|
||||
attachmentsDataLabel.setText(Integer.toString(summaryDetails.getAttachmentCnt()));
|
||||
callLogsDataLabel.setText(Integer.toString(summaryDetails.getCallLogCnt()));
|
||||
contactsDataLabel.setText(Integer.toString(summaryDetails.getContactsCnt()));
|
||||
emailDataLabel.setText(Integer.toString(summaryDetails.getEmailCnt()));
|
||||
messagesDataLabel.setText(Integer.toString(summaryDetails.getMessagesCnt()));
|
||||
|
||||
fileReferencesPanel.setNode(new AbstractNode(Children.create(new AccountSourceContentChildNodeFactory(info.getAccounts()), true)));
|
||||
caseReferencesPanel.setNode(new AbstractNode(Children.create(new CorrelationCaseChildNodeFactory(info.getAccounts()), true)));
|
||||
|
||||
setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Lookup getLookup() {
|
||||
return lookup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether or not the text fields are enabled.
|
||||
*
|
||||
* @param enabled true if this component should be enabled, false otherwise
|
||||
*/
|
||||
@Override
|
||||
public void setEnabled(boolean enabled) {
|
||||
super.setEnabled(enabled);
|
||||
attachmentsLabel.setEnabled(enabled);
|
||||
callLogsLabel.setEnabled(enabled);
|
||||
contactsLabel.setEnabled(enabled);
|
||||
emailLabel.setEnabled(enabled);
|
||||
messagesLabel.setEnabled(enabled);
|
||||
caseReferencesPanel.setEnabled(enabled);
|
||||
fileReferencesPanel.setEnabled(enabled);
|
||||
countsPanel.setEnabled(enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the text fields and OutlookViews.
|
||||
*/
|
||||
private void clearControls() {
|
||||
attachmentsDataLabel.setText("");
|
||||
callLogsDataLabel.setText("");
|
||||
contactsDataLabel.setText("");
|
||||
emailDataLabel.setText("");
|
||||
messagesDataLabel.setText("");
|
||||
|
||||
fileReferencesPanel.setNode(new AbstractNode(Children.LEAF));
|
||||
caseReferencesPanel.setNode(new AbstractNode(Children.LEAF));
|
||||
}
|
||||
|
||||
/**
|
||||
* For the given accounts create a comma separated string of all of the
|
||||
* names (TypeSpecificID).
|
||||
*
|
||||
* @param accounts Set of selected accounts
|
||||
*
|
||||
* @return String listing the account names
|
||||
*/
|
||||
private String createAccountLabel(Set<Account> accounts) {
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
accounts.stream().map((account) -> {
|
||||
buffer.append(account.getTypeSpecificID());
|
||||
return account;
|
||||
}).forEachOrdered((_item) -> {
|
||||
buffer.append(", ");
|
||||
});
|
||||
|
||||
return buffer.toString().substring(0, buffer.length() - 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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() {
|
||||
|
||||
countsPanel = new javax.swing.JPanel();
|
||||
emailLabel = new javax.swing.JLabel();
|
||||
contactsLabel = new javax.swing.JLabel();
|
||||
messagesLabel = new javax.swing.JLabel();
|
||||
callLogsLabel = new javax.swing.JLabel();
|
||||
attachmentsLabel = new javax.swing.JLabel();
|
||||
attachmentsDataLabel = new javax.swing.JLabel();
|
||||
messagesDataLabel = new javax.swing.JLabel();
|
||||
callLogsDataLabel = new javax.swing.JLabel();
|
||||
contactsDataLabel = new javax.swing.JLabel();
|
||||
emailDataLabel = new javax.swing.JLabel();
|
||||
fileReferencesPanel = new org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel();
|
||||
caseReferencesPanel = new org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel();
|
||||
|
||||
countsPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(SummaryViewer.class, "SummaryViewer.countsPanel.border.title"))); // NOI18N
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(emailLabel, org.openide.util.NbBundle.getMessage(SummaryViewer.class, "SummaryViewer.emailLabel.text")); // NOI18N
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(contactsLabel, org.openide.util.NbBundle.getMessage(SummaryViewer.class, "SummaryViewer.contactsLabel.text")); // NOI18N
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(messagesLabel, org.openide.util.NbBundle.getMessage(SummaryViewer.class, "SummaryViewer.messagesLabel.text")); // NOI18N
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(callLogsLabel, org.openide.util.NbBundle.getMessage(SummaryViewer.class, "SummaryViewer.callLogsLabel.text")); // NOI18N
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(attachmentsLabel, org.openide.util.NbBundle.getMessage(SummaryViewer.class, "SummaryViewer.attachmentsLabel.text")); // NOI18N
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(attachmentsDataLabel, org.openide.util.NbBundle.getMessage(SummaryViewer.class, "SummaryViewer.attachmentsDataLabel.text")); // NOI18N
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(messagesDataLabel, org.openide.util.NbBundle.getMessage(SummaryViewer.class, "SummaryViewer.messagesDataLabel.text")); // NOI18N
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(callLogsDataLabel, org.openide.util.NbBundle.getMessage(SummaryViewer.class, "SummaryViewer.callLogsDataLabel.text")); // NOI18N
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(contactsDataLabel, org.openide.util.NbBundle.getMessage(SummaryViewer.class, "SummaryViewer.contactsDataLabel.text")); // NOI18N
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(emailDataLabel, org.openide.util.NbBundle.getMessage(SummaryViewer.class, "SummaryViewer.emailDataLabel.text")); // NOI18N
|
||||
|
||||
javax.swing.GroupLayout countsPanelLayout = new javax.swing.GroupLayout(countsPanel);
|
||||
countsPanel.setLayout(countsPanelLayout);
|
||||
countsPanelLayout.setHorizontalGroup(
|
||||
countsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(countsPanelLayout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addGroup(countsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(attachmentsLabel)
|
||||
.addComponent(messagesLabel)
|
||||
.addComponent(callLogsLabel)
|
||||
.addComponent(contactsLabel)
|
||||
.addComponent(emailLabel))
|
||||
.addGap(18, 18, 18)
|
||||
.addGroup(countsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(emailDataLabel)
|
||||
.addComponent(contactsDataLabel)
|
||||
.addComponent(callLogsDataLabel)
|
||||
.addComponent(messagesDataLabel)
|
||||
.addComponent(attachmentsDataLabel))
|
||||
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
);
|
||||
countsPanelLayout.setVerticalGroup(
|
||||
countsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(countsPanelLayout.createSequentialGroup()
|
||||
.addGap(7, 7, 7)
|
||||
.addGroup(countsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(attachmentsLabel)
|
||||
.addComponent(attachmentsDataLabel))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addGroup(countsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(messagesLabel)
|
||||
.addComponent(messagesDataLabel))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addGroup(countsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(callLogsLabel)
|
||||
.addComponent(callLogsDataLabel))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addGroup(countsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(contactsLabel)
|
||||
.addComponent(contactsDataLabel))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addGroup(countsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(emailLabel)
|
||||
.addComponent(emailDataLabel))
|
||||
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
);
|
||||
|
||||
fileReferencesPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(SummaryViewer.class, "SummaryViewer.fileReferencesPanel.border.title"))); // NOI18N
|
||||
fileReferencesPanel.setPreferredSize(new java.awt.Dimension(472, 300));
|
||||
|
||||
caseReferencesPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(SummaryViewer.class, "SummaryViewer.caseReferencesPanel.border.title"))); // NOI18N
|
||||
caseReferencesPanel.setPreferredSize(new java.awt.Dimension(472, 300));
|
||||
|
||||
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()
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(countsPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(fileReferencesPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 485, Short.MAX_VALUE)
|
||||
.addComponent(caseReferencesPanel, javax.swing.GroupLayout.Alignment.TRAILING, 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(countsPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(fileReferencesPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(caseReferencesPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JLabel attachmentsDataLabel;
|
||||
private javax.swing.JLabel attachmentsLabel;
|
||||
private javax.swing.JLabel callLogsDataLabel;
|
||||
private javax.swing.JLabel callLogsLabel;
|
||||
private org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel caseReferencesPanel;
|
||||
private javax.swing.JLabel contactsDataLabel;
|
||||
private javax.swing.JLabel contactsLabel;
|
||||
private javax.swing.JPanel countsPanel;
|
||||
private javax.swing.JLabel emailDataLabel;
|
||||
private javax.swing.JLabel emailLabel;
|
||||
private org.sleuthkit.autopsy.communications.relationships.OutlineViewPanel fileReferencesPanel;
|
||||
private javax.swing.JLabel messagesDataLabel;
|
||||
private javax.swing.JLabel messagesLabel;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
|
||||
}
|
@ -147,7 +147,7 @@ MediaViewImagePanel.rotationTextField.text=
|
||||
MediaViewImagePanel.rotateLeftButton.toolTipText=
|
||||
HtmlPanel.showImagesToggleButton.text=Show Images
|
||||
MediaPlayerPanel.audioSlider.toolTipText=
|
||||
MediaPlayerPanel.VolumeIcon.text=\ \ \ \ \ Volume
|
||||
MediaPlayerPanel.VolumeIcon.text=\ Volume
|
||||
MediaPlayerPanel.progressLabel.text=00:00:00/00:00:00
|
||||
MediaPlayerPanel.playButton.text=\u25ba
|
||||
MediaPlayerPanel.infoLabel.text=No Errors
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2018 Basis Technology Corp.
|
||||
* Copyright 2011-2019 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*s
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -36,6 +36,7 @@ import org.sleuthkit.datamodel.AbstractFile;
|
||||
class MediaFileViewer extends javax.swing.JPanel implements FileTypeViewer {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(MediaFileViewer.class.getName());
|
||||
private static final long serialVersionUID = 1L;
|
||||
private AbstractFile lastFile;
|
||||
//UI
|
||||
private MediaPlayerPanel mediaPlayerPanel;
|
||||
@ -48,7 +49,7 @@ class MediaFileViewer extends javax.swing.JPanel implements FileTypeViewer {
|
||||
/**
|
||||
* Creates a new MediaFileViewer.
|
||||
*/
|
||||
public MediaFileViewer() {
|
||||
MediaFileViewer() {
|
||||
|
||||
initComponents();
|
||||
|
||||
@ -69,8 +70,8 @@ class MediaFileViewer extends javax.swing.JPanel implements FileTypeViewer {
|
||||
|
||||
private void customizeComponents() {
|
||||
add(imagePanel, IMAGE_VIEWER_LAYER);
|
||||
|
||||
if(mediaPlayerPanel != null) {
|
||||
|
||||
if (mediaPlayerPanel != null) {
|
||||
add(mediaPlayerPanel, MEDIA_PLAYER_LAYER);
|
||||
}
|
||||
|
||||
@ -103,10 +104,10 @@ class MediaFileViewer extends javax.swing.JPanel implements FileTypeViewer {
|
||||
List<String> mimeTypes = new ArrayList<>();
|
||||
|
||||
mimeTypes.addAll(this.imagePanel.getSupportedMimeTypes());
|
||||
if(mediaPlayerPanel != null) {
|
||||
if (mediaPlayerPanel != null) {
|
||||
mimeTypes.addAll(this.mediaPlayerPanel.getSupportedMimeTypes());
|
||||
}
|
||||
|
||||
|
||||
return mimeTypes;
|
||||
}
|
||||
|
||||
|
@ -49,6 +49,10 @@ import javax.swing.JPanel;
|
||||
import org.controlsfx.control.MaskerPane;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.python.google.common.collect.Lists;
|
||||
import javafx.scene.Group;
|
||||
import javafx.scene.input.MouseEvent;
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.scene.shape.Rectangle;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.coreutils.ImageUtils;
|
||||
import org.sleuthkit.autopsy.datamodel.FileNode;
|
||||
@ -70,18 +74,20 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
|
||||
private final boolean fxInited;
|
||||
|
||||
private JFXPanel fxPanel;
|
||||
private Group imageGroup;
|
||||
private ImageTaggingTool tagger;
|
||||
private ImageView fxImageView;
|
||||
private ScrollPane scrollPane;
|
||||
private final ProgressBar progressBar = new ProgressBar();
|
||||
private final MaskerPane maskerPane = new MaskerPane();
|
||||
|
||||
|
||||
private double zoomRatio;
|
||||
private double rotation; // Can be 0, 90, 180, and 270.
|
||||
|
||||
|
||||
private static final double[] ZOOM_STEPS = {
|
||||
0.0625, 0.125, 0.25, 0.375, 0.5, 0.75,
|
||||
1, 1.5, 2, 2.5, 3, 4, 5, 6, 8, 10};
|
||||
|
||||
|
||||
private static final double MIN_ZOOM_RATIO = 0.0625; // 6.25%
|
||||
private static final double MAX_ZOOM_RATIO = 10.0; // 1000%
|
||||
|
||||
@ -115,11 +121,13 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
|
||||
|
||||
// build jfx ui (we could do this in FXML?)
|
||||
fxImageView = new ImageView(); // will hold image
|
||||
scrollPane = new ScrollPane(fxImageView); // scrolls and sizes imageview
|
||||
imageGroup = new Group();
|
||||
imageGroup.getChildren().add(fxImageView);
|
||||
scrollPane = new ScrollPane(imageGroup); // scrolls and sizes imageview
|
||||
scrollPane.getStyleClass().add("bg"); //NOI18N
|
||||
scrollPane.setVbarPolicy(ScrollBarPolicy.AS_NEEDED);
|
||||
scrollPane.setHbarPolicy(ScrollBarPolicy.AS_NEEDED);
|
||||
|
||||
|
||||
fxPanel = new JFXPanel(); // bridge jfx-swing
|
||||
Scene scene = new Scene(scrollPane); //root of jfx tree
|
||||
scene.getStylesheets().add(MediaViewImagePanel.class.getResource("MediaViewImagePanel.css").toExternalForm()); //NOI18N
|
||||
@ -146,9 +154,10 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
|
||||
Platform.runLater(() -> {
|
||||
fxImageView.setViewport(new Rectangle2D(0, 0, 0, 0));
|
||||
fxImageView.setImage(null);
|
||||
|
||||
tagger.defaultSettings();
|
||||
|
||||
scrollPane.setContent(null);
|
||||
scrollPane.setContent(fxImageView);
|
||||
scrollPane.setContent(imageGroup);
|
||||
});
|
||||
}
|
||||
|
||||
@ -160,7 +169,7 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
|
||||
* TODO: why is the name passed into the action constructor? it
|
||||
* means we duplicate this string all over the place -jm
|
||||
*/ new ExternalViewerAction(Bundle.MediaViewImagePanel_externalViewerButton_text(), new FileNode(file))
|
||||
.actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, "")) //Swing ActionEvent
|
||||
.actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, "")) //Swing ActionEvent
|
||||
);
|
||||
|
||||
final VBox errorNode = new VBox(10, new Label(errorMessage), externalViewerButton);
|
||||
@ -199,8 +208,11 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
|
||||
if (nonNull(fxImage)) {
|
||||
// We have a non-null image, so let's show it.
|
||||
fxImageView.setImage(fxImage);
|
||||
imageGroup.getChildren().remove(tagger);
|
||||
tagger = new ImageTaggingTool(fxImageView, Color.RED);
|
||||
imageGroup.getChildren().add(tagger);
|
||||
resetView();
|
||||
scrollPane.setContent(fxImageView);
|
||||
scrollPane.setContent(imageGroup);
|
||||
} else {
|
||||
showErrorNode(Bundle.MediaViewImagePanel_errorLabel_text(), file);
|
||||
}
|
||||
@ -410,7 +422,7 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
|
||||
|
||||
private void zoomInButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_zoomInButtonActionPerformed
|
||||
// Find the next zoom step.
|
||||
for (int i=0; i < ZOOM_STEPS.length; i++) {
|
||||
for (int i = 0; i < ZOOM_STEPS.length; i++) {
|
||||
if (zoomRatio < ZOOM_STEPS[i]) {
|
||||
zoomRatio = ZOOM_STEPS[i];
|
||||
break;
|
||||
@ -421,7 +433,7 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
|
||||
|
||||
private void zoomOutButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_zoomOutButtonActionPerformed
|
||||
// Find the next zoom step.
|
||||
for (int i=ZOOM_STEPS.length-1; i >= 0; i--) {
|
||||
for (int i = ZOOM_STEPS.length - 1; i >= 0; i--) {
|
||||
if (zoomRatio > ZOOM_STEPS[i]) {
|
||||
zoomRatio = ZOOM_STEPS[i];
|
||||
break;
|
||||
@ -450,12 +462,12 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
|
||||
private javax.swing.JButton zoomResetButton;
|
||||
private javax.swing.JTextField zoomTextField;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
|
||||
|
||||
/**
|
||||
* Reset the zoom and rotation values to their defaults. The zoom level gets
|
||||
* defaulted to the current size of the panel. The rotation will be set to
|
||||
* zero.
|
||||
*
|
||||
*
|
||||
* Note: This method will make a call to 'updateView()' after the values
|
||||
* have been reset.
|
||||
*/
|
||||
@ -464,28 +476,28 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
|
||||
if (image == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
double imageWidth = image.getWidth();
|
||||
double imageHeight = image.getHeight();
|
||||
double scrollPaneWidth = fxPanel.getWidth();
|
||||
double scrollPaneHeight = fxPanel.getHeight();
|
||||
double zoomRatioWidth = scrollPaneWidth / imageWidth;
|
||||
double zoomRatioHeight = scrollPaneHeight / imageHeight;
|
||||
|
||||
|
||||
// Use the smallest ratio size to fit the entire image in the view area.
|
||||
zoomRatio = zoomRatioWidth < zoomRatioHeight ? zoomRatioWidth : zoomRatioHeight;
|
||||
|
||||
|
||||
rotation = 0;
|
||||
|
||||
|
||||
scrollPane.setHvalue(0);
|
||||
scrollPane.setVvalue(0);
|
||||
|
||||
|
||||
updateView();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Update the image to use the current zoom and rotation values.
|
||||
*
|
||||
*
|
||||
* Note: For zoom levels less than 100%, special accomodations are made in
|
||||
* order to keep the image fully visible. This is because the viewport size
|
||||
* change occurs before any transforms execute, thus chopping off part of
|
||||
@ -498,39 +510,39 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
|
||||
if (image == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Image dimensions
|
||||
double imageWidth = image.getWidth();
|
||||
double imageHeight = image.getHeight();
|
||||
|
||||
|
||||
// Image dimensions with zooming applied
|
||||
double adjustedImageWidth = imageWidth * zoomRatio;
|
||||
double adjustedImageHeight = imageHeight * zoomRatio;
|
||||
|
||||
|
||||
// ImageView viewport dimensions
|
||||
double viewportWidth;
|
||||
double viewportHeight;
|
||||
|
||||
|
||||
// Panel dimensions
|
||||
double panelWidth = fxPanel.getWidth();
|
||||
double panelHeight = fxPanel.getHeight();
|
||||
|
||||
|
||||
// Coordinates to center the image on the panel
|
||||
double centerOffsetX = (panelWidth / 2) - (imageWidth / 2);
|
||||
double centerOffsetY = (panelHeight / 2) - (imageHeight / 2);
|
||||
|
||||
|
||||
// Coordinates to keep the image inside the left/top boundaries
|
||||
double leftOffsetX;
|
||||
double topOffsetY;
|
||||
|
||||
|
||||
// Scroll bar positions
|
||||
double scrollX = scrollPane.getHvalue();
|
||||
double scrollY = scrollPane.getVvalue();
|
||||
|
||||
|
||||
// Scroll bar position boundaries (work-around for viewport size bug)
|
||||
double maxScrollX;
|
||||
double maxScrollY;
|
||||
|
||||
|
||||
// Set viewport size and translation offsets.
|
||||
if ((rotation % 180) == 0) {
|
||||
// Rotation is 0 or 180.
|
||||
@ -549,7 +561,7 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
|
||||
maxScrollX = (adjustedImageHeight - panelWidth) / (imageWidth - panelWidth);
|
||||
maxScrollY = (adjustedImageWidth - panelHeight) / (imageHeight - panelHeight);
|
||||
}
|
||||
|
||||
|
||||
// Work around bug that truncates image if dimensions are too small.
|
||||
if (viewportWidth < imageWidth) {
|
||||
viewportWidth = imageWidth;
|
||||
@ -563,7 +575,7 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
|
||||
scrollY = maxScrollY;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Update the viewport size.
|
||||
fxImageView.setViewport(new Rectangle2D(
|
||||
0, 0, viewportWidth, viewportHeight));
|
||||
@ -589,9 +601,9 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
|
||||
// Add the transforms in reverse order of intended execution.
|
||||
// Note: They MUST be added in this order to ensure translate is
|
||||
// executed last.
|
||||
fxImageView.getTransforms().clear();
|
||||
fxImageView.getTransforms().addAll(translate, rotate, scale);
|
||||
|
||||
imageGroup.getTransforms().clear();
|
||||
imageGroup.getTransforms().addAll(translate, rotate, scale);
|
||||
|
||||
// Adjust scroll bar positions for view changes.
|
||||
if (viewportWidth > fxPanel.getWidth()) {
|
||||
scrollPane.setHvalue(scrollX);
|
||||
@ -599,11 +611,114 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan
|
||||
if (viewportHeight > fxPanel.getHeight()) {
|
||||
scrollPane.setVvalue(scrollY);
|
||||
}
|
||||
|
||||
|
||||
// Update all image controls to reflect the current values.
|
||||
zoomOutButton.setEnabled(zoomRatio > MIN_ZOOM_RATIO);
|
||||
zoomInButton.setEnabled(zoomRatio < MAX_ZOOM_RATIO);
|
||||
rotationTextField.setText((int) rotation + "°");
|
||||
zoomTextField.setText((Math.round(zoomRatio * 100.0)) + "%");
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables users to 'tag' a region of an image by clicking and dragging a
|
||||
* rectangle overtop.
|
||||
*/
|
||||
class ImageTaggingTool extends Rectangle {
|
||||
|
||||
private final double imageWidth;
|
||||
private final double imageHeight;
|
||||
private final double imageOriginX;
|
||||
private final double imageOriginY;
|
||||
|
||||
//Origin of the drag event.
|
||||
private double rectangleOriginX;
|
||||
private double rectangleOriginY;
|
||||
|
||||
//Rectangle lines should be 1.5% of the image. This level of thickness has
|
||||
//a good balance between visual acuity and loss of selection at the borders
|
||||
//of the image.
|
||||
private double lineThicknessAsPercent = 1.5;
|
||||
|
||||
/**
|
||||
* Adds tagging support to an image, where the 'tag' rectangle will be
|
||||
* the specified color.
|
||||
*
|
||||
* @param image Image to tag
|
||||
* @param color Color of the 'tag' rectangle
|
||||
*/
|
||||
private ImageTaggingTool(ImageView image, Color color) {
|
||||
defaultSettings();
|
||||
|
||||
imageWidth = image.getImage().getWidth();
|
||||
imageHeight = image.getImage().getHeight();
|
||||
imageOriginX = image.getX();
|
||||
imageOriginY = image.getY();
|
||||
|
||||
setStroke(color);
|
||||
setFill(color.deriveColor(0, 0, 0, 0));
|
||||
|
||||
//Calculate how many pixels the stroke width should be to guarentee
|
||||
//a consistent % of image consumed by the rectangle border.
|
||||
double min = Math.min(imageWidth, imageHeight);
|
||||
double lineThicknessPixels = min * lineThicknessAsPercent / 100.0;
|
||||
setStrokeWidth(lineThicknessPixels);
|
||||
setVisible(false);
|
||||
|
||||
//Create a rectangle by left clicking on the image
|
||||
image.setOnMousePressed((MouseEvent event) -> {
|
||||
if (event.isSecondaryButtonDown()) {
|
||||
return;
|
||||
}
|
||||
|
||||
//Reset box on new click.
|
||||
defaultSettings();
|
||||
|
||||
rectangleOriginX = event.getX();
|
||||
rectangleOriginY = event.getY();
|
||||
|
||||
setX(rectangleOriginX);
|
||||
setY(rectangleOriginY);
|
||||
});
|
||||
|
||||
//Adjust the rectangle by dragging the left mouse button
|
||||
image.setOnMouseDragged((MouseEvent event) -> {
|
||||
if (event.isSecondaryButtonDown()) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure the rectangle is contained within image boundaries and
|
||||
* that the line thickness is kept within bounds.
|
||||
*/
|
||||
double newX = Math.min(Math.max(event.getX(), imageOriginX)
|
||||
+ lineThicknessPixels / 2, imageWidth - lineThicknessPixels / 2);
|
||||
double newY = Math.min(Math.max(event.getY(), imageOriginY)
|
||||
+ lineThicknessPixels / 2, imageHeight - lineThicknessPixels / 2);
|
||||
|
||||
setVisible(true);
|
||||
double offsetX = newX - rectangleOriginX;
|
||||
if (offsetX < 0) {
|
||||
setX(newX);
|
||||
}
|
||||
setWidth(Math.abs(offsetX));
|
||||
|
||||
double offsetY = newY - rectangleOriginY;
|
||||
if (offsetY < 0) {
|
||||
setY(newY);
|
||||
}
|
||||
setHeight(Math.abs(offsetY));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the rectangle to default dimensions.
|
||||
*/
|
||||
public final void defaultSettings() {
|
||||
setX(0);
|
||||
setY(0);
|
||||
setWidth(0);
|
||||
setHeight(0);
|
||||
setVisible(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -467,6 +467,7 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont
|
||||
htmlPanel.reset();
|
||||
textbodyTextArea.setText("");
|
||||
msgbodyTabbedPane.setEnabled(false);
|
||||
drp.setNode(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -561,7 +562,7 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont
|
||||
msgbodyTabbedPane.setEnabledAt(ATTM_TAB_INDEX, numberOfAttachments > 0);
|
||||
msgbodyTabbedPane.setTitleAt(ATTM_TAB_INDEX, "Attachments (" + numberOfAttachments + ")");
|
||||
drp.setNode(new TableFilterNode(new DataResultFilterNode(new AbstractNode(
|
||||
new AttachmentsChildren(attachments)), null), true));
|
||||
new AttachmentsChildren(attachments))), true));
|
||||
}
|
||||
|
||||
private static String wrapInHtmlBody(String htmlText) {
|
||||
|
@ -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");
|
||||
@ -79,7 +79,7 @@ class PListViewer extends javax.swing.JPanel implements FileTypeViewer, Explorer
|
||||
/**
|
||||
* Creates new form PListViewer
|
||||
*/
|
||||
public PListViewer() {
|
||||
PListViewer() {
|
||||
|
||||
// Create an Outlineview and add to the panel
|
||||
outlineView = new org.openide.explorer.view.OutlineView();
|
||||
@ -193,16 +193,16 @@ class PListViewer extends javax.swing.JPanel implements FileTypeViewer, Explorer
|
||||
Case openCase;
|
||||
try {
|
||||
openCase = Case.getCurrentCaseThrows();
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
JOptionPane.showMessageDialog(this,
|
||||
"Failed to export plist file.",
|
||||
Bundle.PListViewer_ExportFailed_message(),
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
JOptionPane.showMessageDialog(this,
|
||||
"Failed to export plist file.",
|
||||
Bundle.PListViewer_ExportFailed_message(),
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
|
||||
logger.log(Level.SEVERE, "Exception while getting open case.", ex);
|
||||
return;
|
||||
logger.log(Level.SEVERE, "Exception while getting open case.", ex);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
final JFileChooser fileChooser = new JFileChooser();
|
||||
fileChooser.setCurrentDirectory(new File(openCase.getExportDirectory()));
|
||||
fileChooser.setFileFilter(new FileNameExtensionFilter("XML file", "xml"));
|
||||
@ -289,11 +289,11 @@ class PListViewer extends javax.swing.JPanel implements FileTypeViewer, Explorer
|
||||
// Read in and parse the file
|
||||
final byte[] plistFileBuf = new byte[(int) plistFile.getSize()];
|
||||
plistFile.read(plistFileBuf, 0, plistFile.getSize());
|
||||
final List<PropKeyValue> plist = parsePList(plistFileBuf);
|
||||
|
||||
final List<PropKeyValue> plist = parsePList(plistFileBuf);
|
||||
|
||||
return plist;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void done() {
|
||||
super.done();
|
||||
@ -301,28 +301,28 @@ class PListViewer extends javax.swing.JPanel implements FileTypeViewer, Explorer
|
||||
try {
|
||||
plist = get();
|
||||
setupTable(plist);
|
||||
|
||||
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
setColumnWidths();
|
||||
setColumnWidths();
|
||||
});
|
||||
} catch (InterruptedException ex) {
|
||||
logger.log(Level.SEVERE, "Interruption while parsing/dislaying plist file " + plistFile.getName(), ex);
|
||||
|
||||
JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
|
||||
ex.getMessage(),
|
||||
Bundle.PListViewer_processPlist_interruptedMessage(),
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
|
||||
|
||||
JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
|
||||
ex.getMessage(),
|
||||
Bundle.PListViewer_processPlist_interruptedMessage(),
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
|
||||
} catch (ExecutionException ex) {
|
||||
logger.log(Level.SEVERE, "Exception while parsing/dislaying plist file " + plistFile.getName(), ex);
|
||||
JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
|
||||
ex.getCause().getMessage(),
|
||||
Bundle.PListViewer_processPlist_errorMessage(),
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
|
||||
ex.getCause().getMessage(),
|
||||
Bundle.PListViewer_processPlist_errorMessage(),
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}.execute();
|
||||
}.execute();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -431,16 +431,16 @@ class PListViewer extends javax.swing.JPanel implements FileTypeViewer, Explorer
|
||||
* else is unexpected and will be ignored.
|
||||
*/
|
||||
if (rootDict instanceof NSArray) {
|
||||
for (int i=0; i < ((NSArray)rootDict).count(); i++) {
|
||||
final PropKeyValue pkv = parseProperty("", ((NSArray)rootDict).objectAtIndex(i));
|
||||
for (int i = 0; i < ((NSArray) rootDict).count(); i++) {
|
||||
final PropKeyValue pkv = parseProperty("", ((NSArray) rootDict).objectAtIndex(i));
|
||||
if (null != pkv) {
|
||||
plist.add(pkv);
|
||||
}
|
||||
}
|
||||
} else if (rootDict instanceof NSDictionary) {
|
||||
final String[] keys = ((NSDictionary)rootDict).allKeys();
|
||||
final String[] keys = ((NSDictionary) rootDict).allKeys();
|
||||
for (final String key : keys) {
|
||||
final PropKeyValue pkv = parseProperty(key, ((NSDictionary)rootDict).objectForKey(key));
|
||||
final PropKeyValue pkv = parseProperty(key, ((NSDictionary) rootDict).objectForKey(key));
|
||||
if (null != pkv) {
|
||||
plist.add(pkv);
|
||||
}
|
||||
@ -533,7 +533,7 @@ class PListViewer extends javax.swing.JPanel implements FileTypeViewer, Explorer
|
||||
.map(child -> new PropKeyValue(child))
|
||||
.toArray(PropKeyValue[]::new);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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");
|
||||
@ -74,7 +74,7 @@ class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
|
||||
/**
|
||||
* Constructs a file content viewer for SQLite database files.
|
||||
*/
|
||||
public SQLiteViewer() {
|
||||
SQLiteViewer() {
|
||||
initComponents();
|
||||
jTableDataPanel.add(selectedTableView, BorderLayout.CENTER);
|
||||
}
|
||||
@ -544,19 +544,19 @@ class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
|
||||
@Override
|
||||
public void accept(String columnName) {
|
||||
columnIndex++;
|
||||
|
||||
String csvString = columnName;
|
||||
//Format the value to adhere to the format of a CSV file
|
||||
if (columnIndex == 1) {
|
||||
columnName = "\"" + columnName + "\"";
|
||||
csvString = "\"" + csvString + "\"";
|
||||
} else {
|
||||
columnName = ",\"" + columnName + "\"";
|
||||
csvString = ",\"" + csvString + "\"";
|
||||
}
|
||||
if (columnIndex == totalColumnCount) {
|
||||
columnName += "\n";
|
||||
csvString += "\n";
|
||||
}
|
||||
|
||||
try {
|
||||
out.write(columnName.getBytes());
|
||||
out.write(csvString.getBytes());
|
||||
} catch (IOException ex) {
|
||||
/*
|
||||
* If we can no longer write to the output stream, toss a
|
||||
@ -613,7 +613,7 @@ class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
|
||||
*/
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
rowIndex = rowIndex % totalColumnCount;
|
||||
rowIndex %= totalColumnCount;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -3,13 +3,7 @@ Installer.closing.confirmationDialog.title=Ingest is Running
|
||||
# {0} - exception message
|
||||
Installer.closing.messageBox.caseCloseExceptionMessage=Error closing case: {0}
|
||||
OpenIDE-Module-Display-Category=Infrastructure
|
||||
OpenIDE-Module-Long-Description=\
|
||||
This is the core Autopsy module.\n\n\
|
||||
The module contains the core components needed for the bare application to run; the RCP platform, windowing GUI, sleuthkit bindings, datamodel / storage, explorer, result viewers, content viewers, ingest framework, reporting, and core tools, such as the file search.\n\n\
|
||||
The framework included in the module contains APIs for developing modules for ingest, viewers and reporting. \
|
||||
The modules can be deployed as Plugins using the Autopsy plugin installer.\n\
|
||||
This module should not be uninstalled - without it, Autopsy will not run.\n\n\
|
||||
For more information, see http://www.sleuthkit.org/autopsy/
|
||||
OpenIDE-Module-Long-Description=This is the core Autopsy module.\n\nThe module contains the core components needed for the bare application to run; the RCP platform, windowing GUI, sleuthkit bindings, datamodel / storage, explorer, result viewers, content viewers, ingest framework, reporting, and core tools, such as the file search.\n\nThe framework included in the module contains APIs for developing modules for ingest, viewers and reporting. The modules can be deployed as Plugins using the Autopsy plugin installer.\nThis module should not be uninstalled - without it, Autopsy will not run.\n\nFor more information, see http://www.sleuthkit.org/autopsy/
|
||||
OpenIDE-Module-Name=Autopsy-Core
|
||||
OpenIDE-Module-Short-Description=Autopsy Core Module
|
||||
org_sleuthkit_autopsy_core_update_center=http://sleuthkit.org/autopsy/updates.xml
|
||||
|
@ -56,9 +56,9 @@ DataContentViewerHex.totalPageLabel.text_1=100
|
||||
DataContentViewerHex.pageLabel2.text=Page
|
||||
|
||||
# Product Information panel
|
||||
LBL_Description=<div style=\"font-size: 12pt; font-family: Verdana, 'Verdana CE', Arial, 'Arial CE', 'Lucida Grande CE', lucida, 'Helvetica CE', sans-serif;\">\n <b>Product Version:</b> {0} ({9}) <br><b>Sleuth Kit Version:</b> {7} <br><b>Netbeans RCP Build:</b> {8} <br> <b>Java:</b> {1}; {2}<br> <b>System:</b> {3}; {4}; {5}<br><b>Userdir:</b> {6}</div>
|
||||
LBL_Description=<div style="font-size: 12pt; font-family: Verdana, 'Verdana CE', Arial, 'Arial CE', 'Lucida Grande CE', lucida, 'Helvetica CE', sans-serif;">\n <b>Product Version:</b> {0} ({9}) <br><b>Sleuth Kit Version:</b> {7} <br><b>Netbeans RCP Build:</b> {8} <br> <b>Java:</b> {1}; {2}<br> <b>System:</b> {3}; {4}; {5}<br><b>Userdir:</b> {6}</div>
|
||||
Format_OperatingSystem_Value={0} version {1} running on {2}
|
||||
LBL_Copyright=<div style\="font-size: 12pt; font-family: Verdana, 'Verdana CE', Arial, 'Arial CE', 'Lucida Grande CE', lucida, 'Helvetica CE', sans-serif; ">Autopsy™ is a digital forensics platform based on The Sleuth Kit™ and other tools. <br><ul><li>General Information: <a style\="color: \#1E2A60;" href\="http://www.sleuthkit.org">http://www.sleuthkit.org</a>.</li><li>Training: <a style\="color: \#1E2A60;" href\="http://www.basistech.com/autopsy-training">http://www.basistech.com/autopsy-training</a></li><li>Commercial Support: <a style\="color: \#1E2A60;" href\="http://www.basistech.com/digital-forensics/autopsy/support/">http://www.basistech.com/digital-forensics/autopsy/support/</a></li></ul>Copyright © 2003-2018. </div>
|
||||
LBL_Copyright=<div style="font-size: 12pt; font-family: Verdana, 'Verdana CE', Arial, 'Arial CE', 'Lucida Grande CE', lucida, 'Helvetica CE', sans-serif; ">Autopsy™ is a digital forensics platform based on The Sleuth Kit™ and other tools. <br><ul><li>General Information: <a style="color: #1E2A60;" href="http://www.sleuthkit.org">http://www.sleuthkit.org</a>.</li><li>Training: <a style="color: #1E2A60;" href="http://www.basistech.com/autopsy-training">http://www.basistech.com/autopsy-training</a></li><li>Commercial Support: <a style="color: #1E2A60;" href="http://www.basistech.com/digital-forensics/autopsy/support/">http://www.basistech.com/digital-forensics/autopsy/support/</a></li></ul>Copyright © 2003-2018. </div>
|
||||
SortChooser.dialogTitle=Choose Sort Criteria
|
||||
ThumbnailViewChildren.progress.cancelling=(Cancelling)
|
||||
# {0} - file name
|
||||
@ -88,7 +88,7 @@ DataResultViewerThumbnail.pageNextButton.text=
|
||||
DataResultViewerThumbnail.imagesLabel.text=Images:
|
||||
DataResultViewerThumbnail.imagesRangeLabel.text=-
|
||||
DataResultViewerThumbnail.pageNumLabel.text=-
|
||||
DataResultViewerThumbnail.filePathLabel.text=\ \ \
|
||||
DataResultViewerThumbnail.filePathLabel.text=\
|
||||
DataResultViewerThumbnail.goToPageLabel.text=Go to Page:
|
||||
DataResultViewerThumbnail.goToPageField.text=
|
||||
AdvancedConfigurationDialog.cancelButton.text=Cancel
|
||||
|
@ -386,7 +386,13 @@ public final class DataResultViewerThumbnail extends AbstractDataResultViewer {
|
||||
rootNodeChildren.cancelLoadingThumbnails();
|
||||
}
|
||||
try {
|
||||
if (givenNode != null) {
|
||||
// There is an issue with ThumbnailViewChildren
|
||||
// addNotify, that it's call to getChildren.getNodes() does not cause the
|
||||
// children nodes to be created. Adding a call to getChildren.getNodesCount()
|
||||
// here will assure that the children nodes are created particularly in the
|
||||
// case where the DataResultViewerThumbnail stands along from the
|
||||
// DataResultViewer. See DataResultViewer setNode for more information.
|
||||
if (givenNode != null && givenNode.getChildren().getNodesCount() > 0) {
|
||||
rootNode = (TableFilterNode) givenNode;
|
||||
/*
|
||||
* Wrap the given node in a ThumbnailViewChildren that will
|
||||
|
@ -23,9 +23,7 @@ PlatformUtil.getProcVmUsed.sigarNotInit.msg=Cannot get virt mem used, sigar not
|
||||
PlatformUtil.getProcVmUsed.gen.msg=Cannot get virt mem used, {0}
|
||||
PlatformUtil.getJvmMemInfo.usageText=JVM heap usage: {0}, JVM non-heap usage: {1}
|
||||
PlatformUtil.getPhysicalMemInfo.usageText=Physical memory usage (max, total, free): {0}, {1}, {2}
|
||||
PlatformUtil.getAllMemUsageInfo.usageText={0}\n\
|
||||
{1}\n\
|
||||
Process Virtual Memory: {2}
|
||||
PlatformUtil.getAllMemUsageInfo.usageText={0}\n{1}\nProcess Virtual Memory: {2}
|
||||
# {0} - file name
|
||||
ReadImageTask.mesageText=Reading image: {0}
|
||||
StringExtract.illegalStateException.cannotInit.msg=Unicode table not properly initialized, cannot instantiate StringExtract
|
||||
|
@ -258,10 +258,10 @@ ImageNode.getActions.viewInNewWin.text=View in New Window
|
||||
ImageNode.createSheet.name.name=Name
|
||||
ImageNode.createSheet.name.displayName=Name
|
||||
ImageNode.createSheet.name.desc=no description
|
||||
Installer.exception.tskVerStringNull.msg=Sleuth Kit JNI test call returned without error, but version string was null\!
|
||||
Installer.exception.taskVerStringBang.msg=Sleuth Kit JNI test call returned without error, but version string was ""\!
|
||||
Installer.tskLibErr.msg=Problem with Sleuth Kit JNI. Test call failed\!\n\nDetails: {0}
|
||||
Installer.tskLibErr.err=Fatal Error\!
|
||||
Installer.exception.tskVerStringNull.msg=Sleuth Kit JNI test call returned without error, but version string was null!
|
||||
Installer.exception.taskVerStringBang.msg=Sleuth Kit JNI test call returned without error, but version string was ""!
|
||||
Installer.tskLibErr.msg=Problem with Sleuth Kit JNI. Test call failed!\n\nDetails: {0}
|
||||
Installer.tskLibErr.err=Fatal Error!
|
||||
InterestingHits.interestingItems.text=INTERESTING ITEMS
|
||||
InterestingHits.displayName.text=Interesting Items
|
||||
InterestingHits.createSheet.name.name=Name
|
||||
|
@ -126,7 +126,20 @@ public class DataResultFilterNode extends FilterNode {
|
||||
static private final DisplayableItemNodeVisitor<List<Action>> getActionsDIV = new GetPopupActionsDisplayableItemNodeVisitor();
|
||||
private final DisplayableItemNodeVisitor<AbstractAction> getPreferredActionsDIV = new GetPreferredActionsDisplayableItemNodeVisitor();
|
||||
|
||||
// Assumptions are made in GetPreferredActionsDisplayableItemNodeVisitor that
|
||||
// sourceEm is the directory tree explorer manager.
|
||||
private final ExplorerManager sourceEm;
|
||||
|
||||
/**
|
||||
* Constructs a node used to wrap another node before passing it to the
|
||||
* result viewers. The wrapper node defines the actions associated with the
|
||||
* wrapped node and may filter out some of its children.
|
||||
*
|
||||
* @param node The node to wrap.
|
||||
*/
|
||||
public DataResultFilterNode(Node node) {
|
||||
this(node, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a node used to wrap another node before passing it to the
|
||||
@ -635,6 +648,9 @@ public class DataResultFilterNode extends FilterNode {
|
||||
// is a DirectoryTreeFilterNode that wraps the dataModelNode. We need
|
||||
// to set that wrapped node as the selection and root context of the
|
||||
// directory tree explorer manager (sourceEm)
|
||||
if(sourceEm == null) {
|
||||
return null;
|
||||
}
|
||||
final Node currentSelectionInDirectoryTree = sourceEm.getSelectedNodes()[0];
|
||||
|
||||
return new AbstractAction() {
|
||||
@ -675,6 +691,9 @@ public class DataResultFilterNode extends FilterNode {
|
||||
* @return
|
||||
*/
|
||||
private AbstractAction openParent(AbstractNode node) {
|
||||
if(sourceEm == null) {
|
||||
return null;
|
||||
}
|
||||
// @@@ Why do we ignore node?
|
||||
Node[] selectedFilterNodes = sourceEm.getSelectedNodes();
|
||||
Node selectedFilterNode = selectedFilterNodes[0];
|
||||
|
@ -14,7 +14,7 @@ KnownStatusSearchPanel.knownCheckBox.text=Known Status:
|
||||
KnownStatusSearchPanel.knownBadOptionCheckBox.text=Notable
|
||||
KnownStatusSearchPanel.knownOptionCheckBox.text=Known (NSRL or other)
|
||||
KnownStatusSearchPanel.unknownOptionCheckBox.text=Unknown
|
||||
DateSearchFilter.noneSelectedMsg.text=At least one date type must be selected\!
|
||||
DateSearchFilter.noneSelectedMsg.text=At least one date type must be selected!
|
||||
DateSearchPanel.dateCheckBox.text=Date:
|
||||
DateSearchPanel.jLabel4.text=Timezone:
|
||||
DateSearchPanel.jLabel3.text=*The date format is mm/dd/yyyy
|
||||
@ -56,7 +56,7 @@ FileSearchPanel.search.results.details=Large number of matches may impact perfor
|
||||
FileSearchPanel.search.exception.noFilterSelected.msg=At least one filter must be selected.
|
||||
FileSearchPanel.search.validationErr.msg=Validation Error: {0}
|
||||
FileSearchPanel.emptyWhereClause.text=Invalid options, nothing to show.
|
||||
KnownStatusSearchFilter.noneSelectedMsg.text=At least one known status must be selected\!
|
||||
KnownStatusSearchFilter.noneSelectedMsg.text=At least one known status must be selected!
|
||||
NameSearchFilter.emptyNameMsg.text=Must enter something for name search.
|
||||
SearchNode.getName.text=Search Result
|
||||
SizeSearchPanel.sizeCompareComboBox.equalTo=equal to
|
||||
|
@ -140,7 +140,7 @@ IngestJob.cancelReason.outOfDiskSpace.text=Out of disk space
|
||||
IngestJob.cancelReason.servicesDown.text=Services Down
|
||||
IngestJob.cancelReason.caseClosed.text=Case closed
|
||||
IngestJobSettingsPanel.globalSettingsButton.text=Global Settings
|
||||
gest
|
||||
gest=
|
||||
IngestJobSettingsPanel.globalSettingsButton.actionCommand=Advanced
|
||||
IngestJobSettingsPanel.globalSettingsButton.text=Global Settings
|
||||
IngestJobSettingsPanel.pastJobsButton.text=History
|
||||
|
@ -11,12 +11,7 @@ ExtractArchiveWithPasswordAction.progress.text=Unpacking contents of archive: {0
|
||||
ExtractArchiveWithPasswordAction.prompt.text=Enter Password
|
||||
ExtractArchiveWithPasswordAction.prompt.title=Enter Password
|
||||
OpenIDE-Module-Display-Category=Ingest Module
|
||||
OpenIDE-Module-Long-Description=\
|
||||
Embedded File Extraction Ingest Module\n\nThe Embedded File Extraction Ingest Module processes document files (such as doc, docx, ppt, pptx, xls, xlsx) and archive files (such as zip and others archive types supported by the 7zip extractor).\n\
|
||||
Contents of these files are extracted and the derived files are added back to the current ingest to be processed by the configured ingest modules.\n\
|
||||
If the derived file happens to be an archive file, it will be re-processed by the 7zip extractor - the extractor will process archive files N-levels deep.\n\n\
|
||||
The extracted files are navigable in the directory tree.\n\n\
|
||||
The module is supported on Windows, Linux and Mac operating systems.
|
||||
OpenIDE-Module-Long-Description=Embedded File Extraction Ingest Module\n\nThe Embedded File Extraction Ingest Module processes document files (such as doc, docx, ppt, pptx, xls, xlsx) and archive files (such as zip and others archive types supported by the 7zip extractor).\nContents of these files are extracted and the derived files are added back to the current ingest to be processed by the configured ingest modules.\nIf the derived file happens to be an archive file, it will be re-processed by the 7zip extractor - the extractor will process archive files N-levels deep.\n\nThe extracted files are navigable in the directory tree.\n\nThe module is supported on Windows, Linux and Mac operating systems.
|
||||
OpenIDE-Module-Name=Embedded File Extraction
|
||||
OpenIDE-Module-Short-Description=Embedded File Extraction Ingest Module
|
||||
EmbeddedFileExtractorIngestModule.SevenZipContentReadStream.seek.exception.invalidOrigin=Invalid seek origin: {0}
|
||||
|
@ -1,9 +1,7 @@
|
||||
CannotRunFileTypeDetection=Cannot run file type detection.
|
||||
ExifParserFileIngestModule.indexError.message=Failed to index EXIF Metadata artifact for keyword search.
|
||||
OpenIDE-Module-Display-Category=Ingest Module
|
||||
OpenIDE-Module-Long-Description=\
|
||||
Exif metadata ingest module. \n\n\
|
||||
The ingest module analyzes image files, extracts Exif information and posts the Exif data as results.
|
||||
OpenIDE-Module-Long-Description=Exif metadata ingest module. \n\nThe ingest module analyzes image files, extracts Exif information and posts the Exif data as results.
|
||||
OpenIDE-Module-Name=ExifParser
|
||||
OpenIDE-Module-Short-Description=Exif metadata ingest module
|
||||
ExifParserFileIngestModule.moduleName.text=Exif Parser
|
||||
|
@ -36,27 +36,27 @@ FileExtMismatchSettingsPanel.jLabel1.text=File Types:
|
||||
FileExtMismatchSettingsPanel.newExtButton.text=New Extension
|
||||
FileExtMismatchSettingsPanel.newMimePrompt.message=Add a new MIME file type:
|
||||
FileExtMismatchSettingsPanel.newMimePrompt.title=New MIME
|
||||
FileExtMismatchSettingsPanel.newMimePrompt.emptyMime.message=MIME type text is empty\!
|
||||
FileExtMismatchSettingsPanel.newMimePrompt.emptyMime.message=MIME type text is empty!
|
||||
FileExtMismatchSettingsPanel.newMimePrompt.emptyMime.title=Empty type
|
||||
FileExtMismatchSettingsPanel.newMimePrompt.mimeTypeNotSupported.message=MIME type not supported\!
|
||||
FileExtMismatchSettingsPanel.newMimePrompt.mimeTypeNotSupported.message=MIME type not supported!
|
||||
FileExtMismatchSettingsPanel.newMimePrompt.mimeTypeNotSupported.title=Type not supported
|
||||
FileExtMismatchSettingsPanel.newMimePrompt.mimeTypeExists.message=MIME type already exists\!
|
||||
FileExtMismatchSettingsPanel.newMimePrompt.mimeTypeExists.message=MIME type already exists!
|
||||
FileExtMismatchSettingsPanel.newMimePrompt.mimeTypeExists.title=Type already exists
|
||||
FileExtMismatchSettingsPanel.newMimePrompt.mimeTypeNotDetectable.message=MIME type is not detectable by this module.
|
||||
FileExtMismatchSettingsPanel.newMimePrompt.mimeTypeNotDetectable.title=Type not detectable
|
||||
FileExtMismatchSettingsPanel.removeTypeButton.noneSelected.message=No MIME type selected\!
|
||||
FileExtMismatchSettingsPanel.removeTypeButton.noneSelected.message=No MIME type selected!
|
||||
FileExtMismatchSettingsPanel.removeTypeButton.noneSelected.title=No type selected
|
||||
FileExtMismatchSettingsPanel.newExtPrompt.message=Add an allowed extension:
|
||||
FileExtMismatchSettingsPanel.newExtPrompt.title=New allowed extension
|
||||
FileExtMismatchSettingsPanel.newExtPrompt.empty.message=Extension text is empty\!
|
||||
FileExtMismatchSettingsPanel.newExtPrompt.empty.message=Extension text is empty!
|
||||
FileExtMismatchSettingsPanel.newExtPrompt.empty.title=Extension text empty
|
||||
FileExtMismatchSettingsPanel.newExtPrompt.noMimeType.message=No MIME type selected\!
|
||||
FileExtMismatchSettingsPanel.newExtPrompt.noMimeType.message=No MIME type selected!
|
||||
FileExtMismatchSettingsPanel.newExtPrompt.noMimeType.title=No MIME type selected
|
||||
FileExtMismatchSettingsPanel.newExtPrompt.extExists.message=Extension already exists\!
|
||||
FileExtMismatchSettingsPanel.newExtPrompt.extExists.message=Extension already exists!
|
||||
FileExtMismatchSettingsPanel.newExtPrompt.extExists.title=Extension already exists
|
||||
FileExtMismatchSettingsPanel.removeExtButton.noneSelected.message=No extension selected\!
|
||||
FileExtMismatchSettingsPanel.removeExtButton.noneSelected.message=No extension selected!
|
||||
FileExtMismatchSettingsPanel.removeExtButton.noneSelected.title=No extension selected
|
||||
FileExtMismatchSettingsPanel.removeExtButton.noMimeTypeSelected.message=No MIME type selected\!
|
||||
FileExtMismatchSettingsPanel.removeExtButton.noMimeTypeSelected.message=No MIME type selected!
|
||||
FileExtMismatchSettingsPanel.removeExtButton.noMimeTypeSelected.title=No MIME type selected
|
||||
FileExtMismatchSettingsPanel.removeTypeButton.toolTipText=
|
||||
FileExtMismatchModuleSettingsPanel.checkAllRadioButton.text=Check all file types
|
||||
|
@ -40,10 +40,7 @@ ImportCentralRepoDbProgressDialog.errorParsingFile.message=Error parsing hash se
|
||||
ImportCentralRepoDbProgressDialog.linesProcessed.message=\ hashes processed
|
||||
ImportCentralRepoDbProgressDialog.title.text=Central Repository Import Progress
|
||||
OpenIDE-Module-Display-Category=Ingest Module
|
||||
OpenIDE-Module-Long-Description=\
|
||||
Hash Set ingest module. \n\n\
|
||||
The ingest module analyzes files in the disk image and marks them as "known" (based on NSRL hashset lookup for "known" files) and "bad / interesting" (based on one or more hash sets supplied by the user).\n\n\
|
||||
The module also contains additional non-ingest tools that are integrated in the GUI, such as file lookup by hash and hash set configuration.
|
||||
OpenIDE-Module-Long-Description=Hash Set ingest module. \n\nThe ingest module analyzes files in the disk image and marks them as "known" (based on NSRL hashset lookup for "known" files) and "bad / interesting" (based on one or more hash sets supplied by the user).\n\nThe module also contains additional non-ingest tools that are integrated in the GUI, such as file lookup by hash and hash set configuration.
|
||||
OpenIDE-Module-Name=HashDatabases
|
||||
OptionsCategory_Name_HashDatabase=Hash Sets
|
||||
OptionsCategory_Keywords_HashDatabase=Hash Sets
|
||||
@ -172,10 +169,7 @@ HashDbSearchThread.name.searching=Searching
|
||||
HashDbSearchThread.noMoreFilesWithMD5Msg=No other files with the same MD5 hash were found.
|
||||
ModalNoButtons.indexingDbsTitle=Indexing hash sets
|
||||
ModalNoButtons.indexingDbTitle=Indexing hash set
|
||||
ModalNoButtons.exitHashDbIndexingMsg=You are about to exit out of indexing your hash sets. \n\
|
||||
The generated index will be left unusable. If you choose to continue,\n\
|
||||
please delete the corresponding -md5.idx file in the hash folder.\n\
|
||||
Exit indexing?
|
||||
ModalNoButtons.exitHashDbIndexingMsg=You are about to exit out of indexing your hash sets. \nThe generated index will be left unusable. If you choose to continue,\nplease delete the corresponding -md5.idx file in the hash folder.\nExit indexing?
|
||||
ModalNoButtons.dlgTitle.unfinishedIndexing=Unfinished Indexing
|
||||
ModalNoButtons.indexThis.currentlyIndexing1Db=Currently indexing 1 hash set
|
||||
ModalNoButtons.indexThese.currentlyIndexing1OfNDbs=Currently indexing 1 of {0}
|
||||
|
@ -163,6 +163,8 @@ final class ContactAnalyzer {
|
||||
data1 = resultSet.getString("data1"); //NON-NLS
|
||||
mimetype = resultSet.getString("mimetype"); //NON-NLS
|
||||
if (name.equals(oldName) == false) {
|
||||
bba = file.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT);
|
||||
attributes = new ArrayList<>();
|
||||
attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME, moduleName, name));
|
||||
}
|
||||
if (mimetype.equals("vnd.android.cursor.item/phone_v2")) { //NON-NLS
|
||||
@ -170,6 +172,12 @@ final class ContactAnalyzer {
|
||||
} else {
|
||||
attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL, moduleName, data1));
|
||||
}
|
||||
|
||||
// TODO: If this code comes back to life, add code to create the account
|
||||
// and relationship between the phone numbers & emails. Also
|
||||
// investigate if the mimetype "vnd.android.cursor.item/phone_v2"
|
||||
// makes sense in an ios word
|
||||
|
||||
oldName = name;
|
||||
|
||||
bba.addAttributes(attributes);
|
||||
|
@ -81,8 +81,8 @@ FilesSetRulePanel.nameTextField.text=
|
||||
FilesSetRulePanel.ruleNameLabel.text=Rule Name (Optional):
|
||||
FilesSetRulePanel.messages.emptyNameCondition=You must specify a name pattern for this rule.
|
||||
FilesSetRulePanel.messages.invalidNameRegex=The name regular expression is not valid:\n\n{0}
|
||||
FilesSetRulePanel.messages.invalidCharInName=The name cannot contain \\, /, :, *, ?, \", <, or > unless it is a regular expression.
|
||||
FilesSetRulePanel.messages.invalidCharInPath=The path cannot contain \\, :, *, ?, \", <, or > unless it is a regular expression.
|
||||
FilesSetRulePanel.messages.invalidCharInName=The name cannot contain \\, /, :, *, ?, ", <, or > unless it is a regular expression.
|
||||
FilesSetRulePanel.messages.invalidCharInPath=The path cannot contain \\, :, *, ?, ", <, or > unless it is a regular expression.
|
||||
FilesSetRulePanel.messages.invalidPathRegex=The path regular expression is not valid:\n\n{0}
|
||||
FilesSetDefsPanel.doFileSetsDialog.duplicateRuleSet.text=Rule set with name {0} already exists.
|
||||
FilesSetRulePanel.pathSeparatorInfoLabel.text=Use / as path separator
|
||||
|
@ -21,7 +21,7 @@ PhotoRecIngestModule.complete.totalParsetime=Total Parsing Time:
|
||||
PhotoRecIngestModule.complete.photoRecResults=PhotoRec Results
|
||||
PhotoRecIngestModule.NotEnoughDiskSpace.detail.msg=PhotoRec error processing {0} with {1} Not enough space on primary disk to save unallocated space.
|
||||
PhotoRecIngestModule.cancelledByUser=PhotoRec cancelled by user.
|
||||
PhotoRecIngestModule.error.exitValue=PhotoRec carver returned error exit value \= {0} when scanning {1}
|
||||
PhotoRecIngestModule.error.exitValue=PhotoRec carver returned error exit value = {0} when scanning {1}
|
||||
PhotoRecIngestModule.error.msg=Error processing {0} with PhotoRec carver.
|
||||
PhotoRecIngestModule.complete.numberOfErrors=Number of Errors while Carving:
|
||||
PhotoRecCarverIngestJobSettingsPanel.detectionSettingsLabel.text=PhotoRec Settings
|
||||
|
@ -1,15 +1,15 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013-2018 Basis Technology Corp.
|
||||
*
|
||||
* Copyright 2013-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.
|
||||
@ -18,12 +18,15 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.modules.stix;
|
||||
|
||||
import com.williballenthin.rejistry.RegistryHiveFile;
|
||||
import com.williballenthin.rejistry.RegistryKey;
|
||||
import com.williballenthin.rejistry.RegistryParseException;
|
||||
import com.williballenthin.rejistry.RegistryValue;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.autopsy.datamodel.ContentUtils;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.io.IOException;
|
||||
@ -31,10 +34,8 @@ import java.io.UnsupportedEncodingException;
|
||||
import java.io.File;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.regex.Matcher;
|
||||
|
||||
import org.mitre.cybox.objects.WindowsRegistryKey;
|
||||
import org.mitre.cybox.common_2.ConditionTypeEnum;
|
||||
import com.williballenthin.rejistry.*;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
|
||||
/**
|
||||
@ -43,9 +44,9 @@ import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
class EvalRegistryObj extends EvaluatableObject {
|
||||
|
||||
private final WindowsRegistryKey obj;
|
||||
private final List<RegistryFileInfo> regFiles = new ArrayList<RegistryFileInfo>();
|
||||
private final List<RegistryFileInfo> regFiles = new ArrayList<>();
|
||||
|
||||
public EvalRegistryObj(WindowsRegistryKey a_obj, String a_id, String a_spacing, List<RegistryFileInfo> a_regFiles) {
|
||||
EvalRegistryObj(WindowsRegistryKey a_obj, String a_id, String a_spacing, List<RegistryFileInfo> a_regFiles) {
|
||||
obj = a_obj;
|
||||
id = a_id;
|
||||
spacing = a_spacing;
|
||||
@ -80,7 +81,7 @@ class EvalRegistryObj extends EvaluatableObject {
|
||||
setUnsupportedFieldWarnings();
|
||||
|
||||
// Make a list of hives to test
|
||||
List<RegistryFileInfo> hiveList = new ArrayList<RegistryFileInfo>();
|
||||
List<RegistryFileInfo> hiveList = new ArrayList<>();
|
||||
if (obj.getHive() == null) {
|
||||
// If the hive field is missing, add everything
|
||||
hiveList.addAll(regFiles);
|
||||
@ -88,9 +89,9 @@ class EvalRegistryObj extends EvaluatableObject {
|
||||
// If the hive name is HKEY_LOCAL_MACHINE, add the ones from the config directory.
|
||||
// Otherwise, add the others
|
||||
for (RegistryFileInfo regFile : regFiles) {
|
||||
if (regFile.abstractFile.getParentPath() != null) {
|
||||
if (regFile.getAbstractFile().getParentPath() != null) {
|
||||
Pattern pattern = Pattern.compile("system32", Pattern.CASE_INSENSITIVE);
|
||||
Matcher matcher = pattern.matcher(regFile.abstractFile.getParentPath());
|
||||
Matcher matcher = pattern.matcher(regFile.getAbstractFile().getParentPath());
|
||||
if (matcher.find()) {
|
||||
// Looking for system files and found one, so add it to the list
|
||||
if (obj.getHive().getValue().toString().equalsIgnoreCase("HKEY_LOCAL_MACHINE")) { //NON-NLS
|
||||
@ -112,7 +113,7 @@ class EvalRegistryObj extends EvaluatableObject {
|
||||
Pattern pattern = Pattern.compile("Temp.STIX." + stixHiveName, Pattern.CASE_INSENSITIVE);
|
||||
|
||||
for (RegistryFileInfo hive : regFiles) {
|
||||
Matcher matcher = pattern.matcher(hive.tempFileName);
|
||||
Matcher matcher = pattern.matcher(hive.getTempFileName());
|
||||
if (matcher.find()) {
|
||||
hiveList.add(hive);
|
||||
}
|
||||
@ -163,7 +164,7 @@ class EvalRegistryObj extends EvaluatableObject {
|
||||
*/
|
||||
private ObservableResult testRegistryFile(RegistryFileInfo a_regInfo) {
|
||||
try {
|
||||
RegistryKey root = openRegistry(a_regInfo.tempFileName);
|
||||
RegistryKey root = openRegistry(a_regInfo.getTempFileName());
|
||||
RegistryKey result = findKey(root, obj.getKey().getValue().toString());
|
||||
|
||||
if (result == null) {
|
||||
@ -192,8 +193,8 @@ class EvalRegistryObj extends EvaluatableObject {
|
||||
|
||||
if ((obj.getValues() == null) || (obj.getValues().getValues().isEmpty())) {
|
||||
// No values to test
|
||||
List<StixArtifactData> artData = new ArrayList<StixArtifactData>();
|
||||
artData.add(new StixArtifactData(a_regInfo.abstractFile.getId(), id, "Registry")); //NON-NLS
|
||||
List<StixArtifactData> artData = new ArrayList<>();
|
||||
artData.add(new StixArtifactData(a_regInfo.getAbstractFile().getId(), id, "Registry")); //NON-NLS
|
||||
return new ObservableResult(id, "RegistryObject: Found key " + obj.getKey().getValue(), //NON-NLS
|
||||
spacing, ObservableResult.ObservableState.TRUE, artData);
|
||||
}
|
||||
@ -262,8 +263,8 @@ class EvalRegistryObj extends EvaluatableObject {
|
||||
|
||||
if (nameSuccess && valueSuccess) {
|
||||
// Found a match for all values
|
||||
List<StixArtifactData> artData = new ArrayList<StixArtifactData>();
|
||||
artData.add(new StixArtifactData(a_regInfo.abstractFile.getId(), id, "Registry")); //NON-NLS
|
||||
List<StixArtifactData> artData = new ArrayList<>();
|
||||
artData.add(new StixArtifactData(a_regInfo.getAbstractFile().getId(), id, "Registry")); //NON-NLS
|
||||
return new ObservableResult(id, "RegistryObject: Found key " + obj.getKey().getValue() //NON-NLS
|
||||
+ " and value " + stixRegValue.getName().getValue().toString() //NON-NLS
|
||||
+ " = " + stixRegValue.getData().getValue().toString(),
|
||||
@ -343,13 +344,13 @@ class EvalRegistryObj extends EvaluatableObject {
|
||||
List<AbstractFile> regFilesAbstract = findRegistryFiles();
|
||||
|
||||
// List to hold all the extracted file names plus their abstract file
|
||||
List<RegistryFileInfo> regFilesLocal = new ArrayList<RegistryFileInfo>();
|
||||
List<RegistryFileInfo> regFilesLocal = new ArrayList<>();
|
||||
|
||||
// Make the temp directory
|
||||
String tmpDir;
|
||||
try {
|
||||
tmpDir = Case.getCurrentCaseThrows().getTempDirectory() + File.separator + "STIX"; //NON-NLS
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
tmpDir = Case.getCurrentCaseThrows().getTempDirectory() + File.separator + "STIX"; //NON-NLS
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
throw new TskCoreException(ex.getLocalizedMessage());
|
||||
}
|
||||
File dir = new File(tmpDir);
|
||||
@ -382,11 +383,11 @@ class EvalRegistryObj extends EvaluatableObject {
|
||||
* RecentActivity
|
||||
*/
|
||||
private static List<AbstractFile> findRegistryFiles() throws TskCoreException {
|
||||
List<AbstractFile> registryFiles = new ArrayList<AbstractFile>();
|
||||
List<AbstractFile> registryFiles = new ArrayList<>();
|
||||
Case openCase;
|
||||
try {
|
||||
openCase = Case.getCurrentCaseThrows();
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
throw new TskCoreException(ex.getLocalizedMessage());
|
||||
}
|
||||
org.sleuthkit.autopsy.casemodule.services.FileManager fileManager = openCase.getServices().getFileManager();
|
||||
@ -413,7 +414,7 @@ class EvalRegistryObj extends EvaluatableObject {
|
||||
}
|
||||
|
||||
private void setUnsupportedFieldWarnings() {
|
||||
List<String> fieldNames = new ArrayList<String>();
|
||||
List<String> fieldNames = new ArrayList<>();
|
||||
|
||||
if (obj.getNumberValues() != null) {
|
||||
fieldNames.add("Number_Values"); //NON-NLS
|
||||
@ -462,5 +463,23 @@ class EvalRegistryObj extends EvaluatableObject {
|
||||
tempFileName = a_tempFileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the AbstractFile for this RegistryFileInfo
|
||||
*
|
||||
* @return the abstractFile
|
||||
*/
|
||||
AbstractFile getAbstractFile() {
|
||||
return abstractFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Temporary file name for this RegistryFileInfo
|
||||
*
|
||||
* @return the tempFileName
|
||||
*/
|
||||
String getTempFileName() {
|
||||
return tempFileName;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -99,7 +99,7 @@ FileReportDataTypes.path.text=Full Path
|
||||
FileReportText.getName.text=Files - Text
|
||||
FileReportText.getDesc.text=A delimited text file containing information about individual files in the case.
|
||||
ReportBodyFile.progress.querying=Querying files...
|
||||
ReportBodyFile.ingestWarning.text=Warning, this report was run before ingest services completed\!
|
||||
ReportBodyFile.ingestWarning.text=Warning, this report was run before ingest services completed!
|
||||
ReportBodyFile.progress.loading=Loading files...
|
||||
ReportBodyFile.progress.processing=Now processing {0}...
|
||||
ReportBodyFile.getName.text=TSK Body File
|
||||
@ -241,13 +241,13 @@ ReportHTML.getName.text=HTML Report
|
||||
ReportHTML.getDesc.text=A report about results and tagged items in HTML format.
|
||||
ReportHTML.writeIndex.title=for case {0}
|
||||
ReportHTML.writeIndex.noFrames.msg=Your browser is not compatible with our frame setup.
|
||||
ReportHTML.writeIndex.noFrames.seeNav=Please see <a href\="content\nav.html">the navigation page</a> for artifact links,
|
||||
ReportHTML.writeIndex.seeSum=and <a href\="content\summary.html">the summary page</a> for a case summary.
|
||||
ReportHTML.writeIndex.noFrames.seeNav=Please see <a href="content\nav.html">the navigation page</a> for artifact links,
|
||||
ReportHTML.writeIndex.seeSum=and <a href="contentsummary.html">the summary page</a> for a case summary.
|
||||
ReportHTML.writeNav.title=Report Navigation
|
||||
ReportHTML.writeNav.h1=Report Navigation
|
||||
ReportHTML.writeNav.summary=Case Summary
|
||||
ReportHTML.writeSum.title=Case Summary
|
||||
ReportHTML.writeSum.warningMsg=<span>Warning, this report was run before ingest services completed\!</span>
|
||||
ReportHTML.writeSum.warningMsg=<span>Warning, this report was run before ingest services completed!</span>
|
||||
#
|
||||
# autopsy/test/scripts/regression.py._html_report_diff() uses reportGenOn.text, caseName, caseNum,
|
||||
# examiner as a regex signature to skip report.html and summary.html
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2018 Basis Technology Corp.
|
||||
* Copyright 2011-2019 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -22,7 +22,9 @@ import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import net.htmlparser.jericho.Attributes;
|
||||
import net.htmlparser.jericho.Config;
|
||||
@ -71,7 +73,7 @@ final class HtmlTextExtractor implements TextExtractor {
|
||||
/**
|
||||
* Determines if this content type is supported by this extractor.
|
||||
*
|
||||
* @param content Content instance to be analyzed
|
||||
* @param content Content instance to be analyzed
|
||||
* @param detectedFormat Mimetype of content instance
|
||||
*
|
||||
* @return flag indicating support
|
||||
@ -84,27 +86,21 @@ final class HtmlTextExtractor implements TextExtractor {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reader that will iterate over the text of an HTML document.
|
||||
*
|
||||
* @param content Html document source
|
||||
*
|
||||
* @return A reader instance containing the document source text
|
||||
*
|
||||
* @throws TextExtractorException
|
||||
* Get the metadata as a key -> value map. HTML metadata will include
|
||||
* scripts, links, images, comments, and misc attributes.
|
||||
*
|
||||
* @return Map containing metadata key -> value pairs.
|
||||
*/
|
||||
@Override
|
||||
public Reader getReader() throws InitReaderException {
|
||||
//TODO JIRA-4467, there is only harm in excluding HTML documents greater
|
||||
//than 50MB due to our troubled approach of extraction.
|
||||
ReadContentInputStream stream = new ReadContentInputStream(file);
|
||||
|
||||
//Parse the stream with Jericho and put the results in a Reader
|
||||
public Map<String, String> getMetadata() {
|
||||
Map<String, String> metadataMap = new HashMap<>();
|
||||
try {
|
||||
StringBuilder scripts = new StringBuilder();
|
||||
StringBuilder links = new StringBuilder();
|
||||
StringBuilder images = new StringBuilder();
|
||||
StringBuilder comments = new StringBuilder();
|
||||
StringBuilder others = new StringBuilder();
|
||||
ReadContentInputStream stream = new ReadContentInputStream(file);
|
||||
StringBuilder scripts = new StringBuilder("\n");
|
||||
StringBuilder links = new StringBuilder("\n");
|
||||
StringBuilder images = new StringBuilder("\n");
|
||||
StringBuilder comments = new StringBuilder("\n");
|
||||
StringBuilder others = new StringBuilder("\n");
|
||||
int numScripts = 0;
|
||||
int numLinks = 0;
|
||||
int numImages = 0;
|
||||
@ -113,17 +109,8 @@ final class HtmlTextExtractor implements TextExtractor {
|
||||
|
||||
Source source = new Source(stream);
|
||||
source.fullSequentialParse();
|
||||
Renderer renderer = source.getRenderer();
|
||||
renderer.setNewLine("\n");
|
||||
renderer.setIncludeHyperlinkURLs(false);
|
||||
renderer.setDecorateFontStyles(false);
|
||||
renderer.setIncludeAlternateText(false);
|
||||
|
||||
String text = renderer.toString();
|
||||
// Get all the tags in the source
|
||||
List<StartTag> tags = source.getAllStartTags();
|
||||
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
for (StartTag tag : tags) {
|
||||
if (tag.getName().equals("script")) { //NON-NLS
|
||||
// If the <script> tag has attributes
|
||||
@ -164,30 +151,54 @@ final class HtmlTextExtractor implements TextExtractor {
|
||||
}
|
||||
}
|
||||
}
|
||||
stringBuilder.append(text).append("\n\n");
|
||||
stringBuilder.append("----------NONVISIBLE TEXT----------\n\n"); //NON-NLS
|
||||
|
||||
if (numScripts > 0) {
|
||||
stringBuilder.append("---Scripts---\n"); //NON-NLS
|
||||
stringBuilder.append(scripts).append("\n");
|
||||
metadataMap.put("Scripts", scripts.toString());
|
||||
}
|
||||
if (numLinks > 0) {
|
||||
stringBuilder.append("---Links---\n"); //NON-NLS
|
||||
stringBuilder.append(links).append("\n");
|
||||
metadataMap.put("Links", links.toString());
|
||||
}
|
||||
if (numImages > 0) {
|
||||
stringBuilder.append("---Images---\n"); //NON-NLS
|
||||
stringBuilder.append(images).append("\n");
|
||||
metadataMap.put("Images", images.toString());
|
||||
}
|
||||
if (numComments > 0) {
|
||||
stringBuilder.append("---Comments---\n"); //NON-NLS
|
||||
stringBuilder.append(comments).append("\n");
|
||||
metadataMap.put("Comments", comments.toString());
|
||||
}
|
||||
if (numOthers > 0) {
|
||||
stringBuilder.append("---Others---\n"); //NON-NLS
|
||||
stringBuilder.append(others).append("\n");
|
||||
metadataMap.put("Others", others.toString());
|
||||
}
|
||||
// All done, now make it a reader
|
||||
return new StringReader(stringBuilder.toString());
|
||||
} catch (IOException ex) {
|
||||
logger.log(Level.WARNING, "Error extracting HTML metadata from content.", ex);
|
||||
}
|
||||
|
||||
return metadataMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reader that will iterate over the text of an HTML document.
|
||||
*
|
||||
* @param content Html document source
|
||||
*
|
||||
* @return A reader instance containing the document source text
|
||||
*
|
||||
* @throws TextExtractorException
|
||||
*/
|
||||
@Override
|
||||
public Reader getReader() throws InitReaderException {
|
||||
//TODO JIRA-4467, there is only harm in excluding HTML documents greater
|
||||
//than 50MB due to our troubled approach of extraction.
|
||||
ReadContentInputStream stream = new ReadContentInputStream(file);
|
||||
|
||||
//Parse the stream with Jericho and put the results in a Reader
|
||||
try {
|
||||
Source source = new Source(stream);
|
||||
source.fullSequentialParse();
|
||||
Renderer renderer = source.getRenderer();
|
||||
renderer.setNewLine("\n");
|
||||
renderer.setIncludeHyperlinkURLs(false);
|
||||
renderer.setDecorateFontStyles(false);
|
||||
renderer.setIncludeAlternateText(false);
|
||||
return new StringReader(renderer.toString());
|
||||
} catch (IOException ex) {
|
||||
logger.log(Level.WARNING, "Error extracting HTML from content.", ex);
|
||||
throw new InitReaderException("Error extracting HTML from content.", ex);
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-18 Basis Technology Corp.
|
||||
* Copyright 2011-19 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -19,6 +19,8 @@
|
||||
package org.sleuthkit.autopsy.textextractors;
|
||||
|
||||
import java.io.Reader;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import org.openide.util.Lookup;
|
||||
|
||||
/**
|
||||
@ -61,6 +63,15 @@ public interface TextExtractor {
|
||||
default void setExtractionSettings(Lookup context) {
|
||||
//no-op by default
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves content metadata, if any.
|
||||
*
|
||||
* @return Metadata as key -> value map
|
||||
*/
|
||||
default Map<String, String> getMetadata() {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* System level exception for reader initialization.
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2018 Basis Technology Corp.
|
||||
* Copyright 2011-2019 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -29,8 +29,10 @@ import java.io.InputStream;
|
||||
import java.io.PushbackReader;
|
||||
import java.io.Reader;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
@ -40,8 +42,8 @@ import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import org.apache.tika.Tika;
|
||||
import org.apache.tika.exception.TikaException;
|
||||
import org.apache.tika.metadata.Metadata;
|
||||
import org.apache.tika.parser.AutoDetectParser;
|
||||
import org.apache.tika.parser.ParseContext;
|
||||
@ -65,6 +67,10 @@ import org.sleuthkit.autopsy.datamodel.ContentUtils;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.ReadContentInputStream;
|
||||
import org.xml.sax.ContentHandler;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
/**
|
||||
* Extracts text from Tika supported content. Protects against Tika parser hangs
|
||||
@ -136,7 +142,8 @@ final class TikaTextExtractor implements TextExtractor {
|
||||
private static final File TESSERACT_PATH = locateTesseractExecutable();
|
||||
private String languagePacks = formatLanguagePacks(PlatformUtil.getOcrLanguagePacks());
|
||||
private static final String TESSERACT_OUTPUT_FILE_NAME = "tess_output"; //NON-NLS
|
||||
|
||||
private Map<String, String> metadataMap;
|
||||
|
||||
private ProcessTerminator processTerminator;
|
||||
|
||||
private static final List<String> TIKA_SUPPORTED_TYPES
|
||||
@ -151,8 +158,8 @@ final class TikaTextExtractor implements TextExtractor {
|
||||
|
||||
/**
|
||||
* If Tesseract has been installed and is set to be used through
|
||||
* configuration, then ocr is enabled. OCR can only currently be run on
|
||||
* 64 bit Windows OS.
|
||||
* configuration, then ocr is enabled. OCR can only currently be run on 64
|
||||
* bit Windows OS.
|
||||
*
|
||||
* @return Flag indicating if OCR is set to be used.
|
||||
*/
|
||||
@ -201,7 +208,7 @@ final class TikaTextExtractor implements TextExtractor {
|
||||
TesseractOCRConfig ocrConfig = new TesseractOCRConfig();
|
||||
String tesseractFolder = TESSERACT_PATH.getParent();
|
||||
ocrConfig.setTesseractPath(tesseractFolder);
|
||||
|
||||
|
||||
ocrConfig.setLanguage(languagePacks);
|
||||
ocrConfig.setTessdataPath(PlatformUtil.getOcrLanguagePacksPath());
|
||||
parseContext.set(TesseractOCRConfig.class, ocrConfig);
|
||||
@ -233,9 +240,16 @@ final class TikaTextExtractor implements TextExtractor {
|
||||
+ "Tika returned empty reader for " + content);
|
||||
}
|
||||
pushbackReader.unread(read);
|
||||
//concatenate parsed content and meta data into a single reader.
|
||||
CharSource metaDataCharSource = getMetaDataCharSource(metadata);
|
||||
return CharSource.concat(new ReaderCharSource(pushbackReader), metaDataCharSource).openStream();
|
||||
|
||||
//Save the metadata if it has not been fetched already.
|
||||
if (metadataMap == null) {
|
||||
metadataMap = new HashMap<>();
|
||||
for (String mtdtKey : metadata.names()) {
|
||||
metadataMap.put(mtdtKey, metadata.get(mtdtKey));
|
||||
}
|
||||
}
|
||||
|
||||
return new ReaderCharSource(pushbackReader).openStream();
|
||||
} catch (TimeoutException te) {
|
||||
final String msg = NbBundle.getMessage(this.getClass(),
|
||||
"AbstractFileTikaTextExtract.index.tikaParseTimeout.text",
|
||||
@ -273,7 +287,7 @@ final class TikaTextExtractor implements TextExtractor {
|
||||
File outputFile = null;
|
||||
try {
|
||||
String tempDirectory = Case.getCurrentCaseThrows().getTempDirectory();
|
||||
|
||||
|
||||
//Appending file id makes the name unique
|
||||
String tempFileName = FileUtil.escapeFileName(file.getId() + file.getName());
|
||||
inputFile = Paths.get(tempDirectory, tempFileName).toFile();
|
||||
@ -314,7 +328,7 @@ final class TikaTextExtractor implements TextExtractor {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Wraps the creation of a TikaReader into a Future so that it can be
|
||||
* cancelled.
|
||||
@ -403,20 +417,33 @@ final class TikaTextExtractor implements TextExtractor {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a CharSource that wraps a formated representation of the given
|
||||
* Metadata.
|
||||
* Get the content metadata, if any.
|
||||
*
|
||||
* @param metadata The Metadata to wrap as a CharSource
|
||||
*
|
||||
* @return A CharSource for the given MetaData
|
||||
* @return Metadata as a name -> value map
|
||||
*/
|
||||
static private CharSource getMetaDataCharSource(Metadata metadata) {
|
||||
return CharSource.wrap(
|
||||
new StringBuilder("\n\n------------------------------METADATA------------------------------\n\n")
|
||||
.append(Stream.of(metadata.names()).sorted()
|
||||
.map(key -> key + ": " + metadata.get(key))
|
||||
.collect(Collectors.joining("\n"))
|
||||
));
|
||||
@Override
|
||||
public Map<String, String> getMetadata() {
|
||||
if (metadataMap != null) {
|
||||
return ImmutableMap.copyOf(metadataMap);
|
||||
}
|
||||
|
||||
try {
|
||||
metadataMap = new HashMap<>();
|
||||
InputStream stream = new ReadContentInputStream(content);
|
||||
ContentHandler doNothingContentHandler = new DefaultHandler();
|
||||
Metadata mtdt = new Metadata();
|
||||
parser.parse(stream, doNothingContentHandler, mtdt);
|
||||
for (String mtdtKey : mtdt.names()) {
|
||||
metadataMap.put(mtdtKey, mtdt.get(mtdtKey));
|
||||
}
|
||||
} catch (IOException | SAXException | TikaException ex) {
|
||||
AUTOPSY_LOGGER.log(Level.WARNING, String.format("Error getting metadata for file [id=%d] %s, see Tika log for details...", //NON-NLS
|
||||
content.getId(), content.getName()));
|
||||
TIKA_LOGGER.log(Level.WARNING, "Exception: Unable to get metadata for " //NON-NLS
|
||||
+ "content" + content.getId() + ": " + content.getName(), ex); //NON-NLS
|
||||
}
|
||||
|
||||
return metadataMap;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -426,11 +453,11 @@ final class TikaTextExtractor implements TextExtractor {
|
||||
*/
|
||||
@Override
|
||||
public boolean isSupported() {
|
||||
if(!(content instanceof AbstractFile)) {
|
||||
if (!(content instanceof AbstractFile)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String detectedType = ((AbstractFile)content).getMIMEType();
|
||||
|
||||
String detectedType = ((AbstractFile) content).getMIMEType();
|
||||
if (detectedType == null
|
||||
|| BINARY_MIME_TYPES.contains(detectedType) //any binary unstructured blobs (string extraction will be used)
|
||||
|| ARCHIVE_MIME_TYPES.contains(detectedType)
|
||||
@ -439,7 +466,7 @@ final class TikaTextExtractor implements TextExtractor {
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
return TIKA_SUPPORTED_TYPES.contains(detectedType);
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/*
|
||||
/*=
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013-15 Basis Technology Corp.
|
||||
@ -14,8 +14,8 @@
|
||||
* 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.
|
||||
*/
|
||||
*=limitations under the License.
|
||||
*/=
|
||||
|
||||
AbstractTimelineChart.defaultTooltip.text=Drag the mouse to select a time interval to zoom into.\nRight-click for more actions.
|
||||
HistoryToolBar.historyLabel.text=History
|
||||
|
@ -141,6 +141,7 @@ class ContactAnalyzer(general.AndroidComponentAnalyzer):
|
||||
name = resultSet.getString("display_name")
|
||||
data1 = resultSet.getString("data1") # the phone number or email
|
||||
mimetype = resultSet.getString("mimetype") # either phone or email
|
||||
attributes = ArrayList()
|
||||
if name != oldName:
|
||||
artifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT)
|
||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME, general.MODULE_NAME, name))
|
||||
|
@ -24,6 +24,7 @@ KeywordSearchIngestModule.init.badInitMsg=Keyword search server was not properly
|
||||
KeywordSearchIngestModule.init.exception.errConnToSolr.msg=Error connecting to SOLR server: {0}.
|
||||
# {0} - Reason for not starting Solr
|
||||
KeywordSearchIngestModule.init.tryStopSolrMsg={0}<br />Please try stopping Java Solr processes if any exist and restart the application.
|
||||
KeywordSearchIngestModule.metadataTitle=METADATA
|
||||
KeywordSearchIngestModule.noOpenCase.errMsg=No open case available.
|
||||
KeywordSearchIngestModule.startUp.noOpenCore.msg=The index could not be opened or does not exist.
|
||||
# {0} - schema version number
|
||||
|
@ -123,15 +123,13 @@ class Ingester {
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the given TextExtractor to extract text from the given source. The
|
||||
* text will be chunked and each chunk passed to Solr to add to the index.
|
||||
* Read and chunk the source text for indexing in Solr.
|
||||
*
|
||||
*
|
||||
* @param <A> The type of the Appendix provider that provides
|
||||
* additional text to append to the final chunk.
|
||||
* @param <T> A subclass of SleuthkitVisibleItem.
|
||||
* @param extractor The TextExtractor that will be used to extract text from
|
||||
* the given source.
|
||||
* @param Reader The reader containing extracted text.
|
||||
* @param source The source from which text will be extracted, chunked,
|
||||
* and indexed.
|
||||
* @param context The ingest job context that can be used to cancel this
|
||||
|
@ -19,12 +19,15 @@
|
||||
package org.sleuthkit.autopsy.keywordsearch;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.io.CharSource;
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
import org.openide.util.Lookup;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
@ -170,8 +173,8 @@ public final class KeywordSearchIngestModule implements FileIngestModule {
|
||||
* for final statistics at the end of the job.
|
||||
*
|
||||
* @param ingestJobId id of ingest job
|
||||
* @param fileId id of file
|
||||
* @param status ingest status of the file
|
||||
* @param fileId id of file
|
||||
* @param status ingest status of the file
|
||||
*/
|
||||
private static void putIngestStatus(long ingestJobId, long fileId, IngestStatus status) {
|
||||
synchronized (ingestStatus) {
|
||||
@ -469,15 +472,14 @@ public final class KeywordSearchIngestModule implements FileIngestModule {
|
||||
* streaming) from the file Divide the file into chunks and index the
|
||||
* chunks
|
||||
*
|
||||
* @param aFile file to extract strings from, divide into
|
||||
* chunks and index
|
||||
* @param detectedFormat mime-type detected, or null if none detected
|
||||
* @param aFile file to extract strings from, divide into chunks and
|
||||
* index
|
||||
*
|
||||
* @return true if the file was text_ingested, false otherwise
|
||||
*
|
||||
* @throws IngesterException exception thrown if indexing failed
|
||||
*/
|
||||
private boolean extractTextAndIndex(AbstractFile aFile, String detectedFormat) throws IngesterException {
|
||||
private boolean extractTextAndIndex(AbstractFile aFile) throws IngesterException {
|
||||
ImageConfig imageConfig = new ImageConfig();
|
||||
imageConfig.setOCREnabled(KeywordSearchSettings.getOcrOption());
|
||||
ProcessTerminator terminator = () -> context.fileIngestIsCancelled();
|
||||
@ -485,20 +487,59 @@ public final class KeywordSearchIngestModule implements FileIngestModule {
|
||||
|
||||
try {
|
||||
TextExtractor extractor = TextExtractorFactory.getExtractor(aFile, extractionContext);
|
||||
Reader extractedTextReader = extractor.getReader();
|
||||
Reader fileText = extractor.getReader();
|
||||
|
||||
Reader finalReader;
|
||||
try {
|
||||
Map<String, String> metadata = extractor.getMetadata();
|
||||
CharSource formattedMetadata = getMetaDataCharSource(metadata);
|
||||
//Append the metadata to end of the file text
|
||||
finalReader = CharSource.concat(new CharSource() {
|
||||
//Wrap fileText reader for concatenation
|
||||
@Override
|
||||
public Reader openStream() throws IOException {
|
||||
return fileText;
|
||||
}
|
||||
}, formattedMetadata).openStream();
|
||||
} catch (IOException ex) {
|
||||
logger.log(Level.WARNING, String.format("Could not format extracted metadata for file %s [id=%d]",
|
||||
aFile.getName(), aFile.getId()), ex);
|
||||
//Just send file text.
|
||||
finalReader = fileText;
|
||||
}
|
||||
//divide into chunks and index
|
||||
return Ingester.getDefault().indexText(extractedTextReader, aFile.getId(), aFile.getName(), aFile, context);
|
||||
return Ingester.getDefault().indexText(finalReader, aFile.getId(), aFile.getName(), aFile, context);
|
||||
} catch (TextExtractorFactory.NoTextExtractorFound | TextExtractor.InitReaderException ex) {
|
||||
//No text extractor found... run the default instead
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pretty print the text extractor metadata.
|
||||
*
|
||||
* @param metadata The Metadata map to wrap as a CharSource
|
||||
*
|
||||
* @return A CharSource for the given Metadata
|
||||
*/
|
||||
@NbBundle.Messages({
|
||||
"KeywordSearchIngestModule.metadataTitle=METADATA"
|
||||
})
|
||||
private CharSource getMetaDataCharSource(Map<String, String> metadata) {
|
||||
return CharSource.wrap(new StringBuilder(
|
||||
String.format("\n\n------------------------------%s------------------------------\n\n",
|
||||
Bundle.KeywordSearchIngestModule_metadataTitle()))
|
||||
.append(metadata.entrySet().stream().sorted(Map.Entry.comparingByKey())
|
||||
.map(entry -> entry.getKey() + ": " + entry.getValue())
|
||||
.collect(Collectors.joining("\n"))
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract strings using heuristics from the file and add to index.
|
||||
*
|
||||
* @param aFile file to extract strings from, divide into chunks and
|
||||
* index
|
||||
* index
|
||||
*
|
||||
* @return true if the file was text_ingested, false otherwise
|
||||
*/
|
||||
@ -527,9 +568,9 @@ public final class KeywordSearchIngestModule implements FileIngestModule {
|
||||
/**
|
||||
* Adds the file to the index. Detects file type, calls extractors, etc.
|
||||
*
|
||||
* @param aFile File to analyze
|
||||
* @param aFile File to analyze
|
||||
* @param indexContent False if only metadata should be text_ingested.
|
||||
* True if content and metadata should be index.
|
||||
* True if content and metadata should be index.
|
||||
*/
|
||||
private void indexFile(AbstractFile aFile, boolean indexContent) {
|
||||
//logger.log(Level.INFO, "Processing AbstractFile: " + abstractFile.getName());
|
||||
@ -595,7 +636,7 @@ public final class KeywordSearchIngestModule implements FileIngestModule {
|
||||
extractStringsAndIndex(aFile);
|
||||
return;
|
||||
}
|
||||
if (!extractTextAndIndex(aFile, fileType)) {
|
||||
if (!extractTextAndIndex(aFile)) {
|
||||
// Text extractor not found for file. Extract string only.
|
||||
putIngestStatus(jobId, aFile.getId(), IngestStatus.SKIPPED_ERROR_TEXTEXTRACT);
|
||||
} else {
|
||||
|
@ -1,5 +1,5 @@
|
||||
#Updated by build script
|
||||
#Tue, 26 Feb 2019 14:37:44 -0500
|
||||
#Wed, 08 May 2019 21:37:02 -0400
|
||||
LBL_splash_window_title=Starting Autopsy
|
||||
SPLASH_HEIGHT=314
|
||||
SPLASH_WIDTH=538
|
||||
@ -8,4 +8,4 @@ SplashRunningTextBounds=0,289,538,18
|
||||
SplashRunningTextColor=0x0
|
||||
SplashRunningTextFontSize=19
|
||||
|
||||
currentVersion=Autopsy 4.10.0
|
||||
currentVersion=Autopsy 4.11.0
|
||||
|
@ -1,4 +1,4 @@
|
||||
#Updated by build script
|
||||
#Tue, 26 Feb 2019 14:37:44 -0500
|
||||
CTL_MainWindow_Title=Autopsy 4.10.0
|
||||
CTL_MainWindow_Title_No_Project=Autopsy 4.10.0
|
||||
#Wed, 08 May 2019 21:37:02 -0400
|
||||
CTL_MainWindow_Title=Autopsy 4.11.0
|
||||
CTL_MainWindow_Title_No_Project=Autopsy 4.11.0
|
||||
|
@ -193,7 +193,7 @@ final class VcardParser {
|
||||
}
|
||||
}
|
||||
}
|
||||
ThunderbirdMboxFileIngestModule.addArtifactAttribute(name, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME_PERSON, attributes);
|
||||
ThunderbirdMboxFileIngestModule.addArtifactAttribute(name, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME, attributes);
|
||||
|
||||
for (Telephone telephone : vcard.getTelephoneNumbers()) {
|
||||
addPhoneAttributes(telephone, abstractFile, attributes);
|
||||
@ -412,7 +412,7 @@ final class VcardParser {
|
||||
type.getValue().toUpperCase().replaceAll("\\s+","").split(","));
|
||||
|
||||
for (String splitType : splitTelephoneTypes) {
|
||||
String attributeTypeName = "TSK_PHONE_" + splitType;
|
||||
String attributeTypeName = "TSK_PHONE_NUMBER_" + splitType;
|
||||
try {
|
||||
BlackboardAttribute.Type attributeType = tskCase.getAttributeType(attributeTypeName);
|
||||
if (attributeType == null) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user