mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-12 16:06:15 +00:00
Added contact information to cvt tooltips and MessageContentViewer
This commit is contained in:
parent
972f736a9d
commit
c151a58974
@ -61,6 +61,7 @@ DefaultArtifactContentViewer.copyMenuItem.text=Copy
|
|||||||
DefaultArtifactContentViewer.selectAllMenuItem.text=Select All
|
DefaultArtifactContentViewer.selectAllMenuItem.text=Select All
|
||||||
MessageAccountPanel_button_create_label=Create
|
MessageAccountPanel_button_create_label=Create
|
||||||
MessageAccountPanel_button_view_label=View
|
MessageAccountPanel_button_view_label=View
|
||||||
|
MessageAccountPanel_contact_label=Contact:
|
||||||
MessageAccountPanel_no_matches=No matches found.
|
MessageAccountPanel_no_matches=No matches found.
|
||||||
MessageAccountPanel_persona_label=Persona:
|
MessageAccountPanel_persona_label=Persona:
|
||||||
MessageAccountPanel_unknown_label=Unknown
|
MessageAccountPanel_unknown_label=Unknown
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.sleuthkit.autopsy.contentviewers.artifactviewers;
|
package org.sleuthkit.autopsy.contentviewers.artifactviewers;
|
||||||
|
|
||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
@ -39,6 +38,7 @@ import javax.swing.SwingUtilities;
|
|||||||
import javax.swing.SwingWorker;
|
import javax.swing.SwingWorker;
|
||||||
import org.openide.util.NbBundle.Messages;
|
import org.openide.util.NbBundle.Messages;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
|
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository;
|
||||||
import org.sleuthkit.autopsy.centralrepository.datamodel.Persona;
|
import org.sleuthkit.autopsy.centralrepository.datamodel.Persona;
|
||||||
import org.sleuthkit.autopsy.centralrepository.datamodel.PersonaAccount;
|
import org.sleuthkit.autopsy.centralrepository.datamodel.PersonaAccount;
|
||||||
import org.sleuthkit.autopsy.centralrepository.persona.PersonaDetailsDialog;
|
import org.sleuthkit.autopsy.centralrepository.persona.PersonaDetailsDialog;
|
||||||
@ -46,8 +46,10 @@ import org.sleuthkit.autopsy.centralrepository.persona.PersonaDetailsDialogCallb
|
|||||||
import org.sleuthkit.autopsy.centralrepository.persona.PersonaDetailsMode;
|
import org.sleuthkit.autopsy.centralrepository.persona.PersonaDetailsMode;
|
||||||
import org.sleuthkit.autopsy.centralrepository.persona.PersonaDetailsPanel;
|
import org.sleuthkit.autopsy.centralrepository.persona.PersonaDetailsPanel;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
|
import org.sleuthkit.autopsy.guiutils.ContactCache;
|
||||||
import org.sleuthkit.datamodel.Account;
|
import org.sleuthkit.datamodel.Account;
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||||
|
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||||
import org.sleuthkit.datamodel.CommunicationsManager;
|
import org.sleuthkit.datamodel.CommunicationsManager;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
|
||||||
@ -113,13 +115,24 @@ final class MessageAccountPanel extends JPanel {
|
|||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
Collection<PersonaAccount> personAccounts = PersonaAccount.getPersonaAccountsForAccount(account);
|
List<BlackboardArtifact> contactList = ContactCache.getContacts(account);
|
||||||
if (personAccounts != null && !personAccounts.isEmpty()) {
|
BlackboardArtifact contact = null;
|
||||||
for (PersonaAccount personaAccount : PersonaAccount.getPersonaAccountsForAccount(account)) {
|
|
||||||
dataList.add(new AccountContainer(account, personaAccount));
|
if (contactList != null && !contactList.isEmpty()) {
|
||||||
|
contact = contactList.get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CentralRepository.isEnabled()) {
|
||||||
|
Collection<PersonaAccount> personAccounts = PersonaAccount.getPersonaAccountsForAccount(account);
|
||||||
|
if (personAccounts != null && !personAccounts.isEmpty()) {
|
||||||
|
for (PersonaAccount personaAccount : PersonaAccount.getPersonaAccountsForAccount(account)) {
|
||||||
|
dataList.add(new AccountContainer(account, personaAccount, contact));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dataList.add(new AccountContainer(account, null, contact));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
dataList.add(new AccountContainer(account, null));
|
dataList.add(new AccountContainer(account, null, contact));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,8 +140,7 @@ final class MessageAccountPanel extends JPanel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Messages({
|
@Messages({
|
||||||
"MessageAccountPanel_no_matches=No matches found.",
|
"MessageAccountPanel_no_matches=No matches found.",})
|
||||||
})
|
|
||||||
@Override
|
@Override
|
||||||
protected void done() {
|
protected void done() {
|
||||||
try {
|
try {
|
||||||
@ -199,6 +211,7 @@ final class MessageAccountPanel extends JPanel {
|
|||||||
for (AccountContainer o : data) {
|
for (AccountContainer o : data) {
|
||||||
group.addGap(5)
|
group.addGap(5)
|
||||||
.addComponent(o.getAccountLabel())
|
.addComponent(o.getAccountLabel())
|
||||||
|
.addGroup(o.getContactLineVerticalGroup(layout))
|
||||||
.addGroup(o.getPersonLineVerticalGroup(layout));
|
.addGroup(o.getPersonLineVerticalGroup(layout));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -234,6 +247,7 @@ final class MessageAccountPanel extends JPanel {
|
|||||||
group.addGap(10);
|
group.addGap(10);
|
||||||
for (AccountContainer o : data) {
|
for (AccountContainer o : data) {
|
||||||
pgroup.addGroup(o.getPersonaSequentialGroup(layout));
|
pgroup.addGroup(o.getPersonaSequentialGroup(layout));
|
||||||
|
pgroup.addGroup(o.getContactSequentialGroup(layout));
|
||||||
}
|
}
|
||||||
group.addGap(10)
|
group.addGap(10)
|
||||||
.addGroup(pgroup)
|
.addGroup(pgroup)
|
||||||
@ -253,10 +267,13 @@ final class MessageAccountPanel extends JPanel {
|
|||||||
|
|
||||||
private final Account account;
|
private final Account account;
|
||||||
private Persona persona = null;
|
private Persona persona = null;
|
||||||
|
private final String contactName;
|
||||||
|
|
||||||
private JLabel accountLabel;
|
private JLabel accountLabel;
|
||||||
private JLabel personaHeader;
|
private JLabel personaHeader;
|
||||||
private JLabel personaDisplayName;
|
private JLabel personaDisplayName;
|
||||||
|
private JLabel contactHeader;
|
||||||
|
private JLabel contactDisplayName;
|
||||||
private JButton button;
|
private JButton button;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -265,16 +282,22 @@ final class MessageAccountPanel extends JPanel {
|
|||||||
* @param account
|
* @param account
|
||||||
* @param personaAccount
|
* @param personaAccount
|
||||||
*/
|
*/
|
||||||
AccountContainer(Account account, PersonaAccount personaAccount) {
|
AccountContainer(Account account, PersonaAccount personaAccount, BlackboardArtifact contactArtifact) throws TskCoreException {
|
||||||
|
if (contactArtifact != null && contactArtifact.getArtifactTypeID() != BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT.getTypeID()) {
|
||||||
|
throw new IllegalArgumentException("Failed to create AccountContainer object, passed in artifact was not a TSK_CONTACT");
|
||||||
|
}
|
||||||
|
|
||||||
this.account = account;
|
this.account = account;
|
||||||
this.persona = personaAccount != null ? personaAccount.getPersona() : null;
|
this.persona = personaAccount != null ? personaAccount.getPersona() : null;
|
||||||
|
this.contactName = getNameFromContactArtifact(contactArtifact);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Messages({
|
@Messages({
|
||||||
"MessageAccountPanel_persona_label=Persona:",
|
"MessageAccountPanel_persona_label=Persona:",
|
||||||
"MessageAccountPanel_unknown_label=Unknown",
|
"MessageAccountPanel_unknown_label=Unknown",
|
||||||
"MessageAccountPanel_button_view_label=View",
|
"MessageAccountPanel_button_view_label=View",
|
||||||
"MessageAccountPanel_button_create_label=Create"
|
"MessageAccountPanel_button_create_label=Create",
|
||||||
|
"MessageAccountPanel_contact_label=Contact:"
|
||||||
})
|
})
|
||||||
/**
|
/**
|
||||||
* Swing components will not be initialized until this method is called.
|
* Swing components will not be initialized until this method is called.
|
||||||
@ -282,16 +305,29 @@ final class MessageAccountPanel extends JPanel {
|
|||||||
private void initalizeSwingControls() {
|
private void initalizeSwingControls() {
|
||||||
accountLabel = new JLabel();
|
accountLabel = new JLabel();
|
||||||
personaHeader = new JLabel(Bundle.MessageAccountPanel_persona_label());
|
personaHeader = new JLabel(Bundle.MessageAccountPanel_persona_label());
|
||||||
|
contactHeader = new JLabel(Bundle.MessageAccountPanel_contact_label());
|
||||||
personaDisplayName = new JLabel();
|
personaDisplayName = new JLabel();
|
||||||
|
contactDisplayName = new JLabel();
|
||||||
button = new JButton();
|
button = new JButton();
|
||||||
button.addActionListener(new PersonaButtonListener(this));
|
button.addActionListener(new PersonaButtonListener(this));
|
||||||
|
|
||||||
accountLabel.setText(account.getTypeSpecificID());
|
accountLabel.setText(account.getTypeSpecificID());
|
||||||
|
contactDisplayName.setText(contactName);
|
||||||
personaDisplayName.setText(persona != null ? persona.getName() : Bundle.MessageAccountPanel_unknown_label());
|
personaDisplayName.setText(persona != null ? persona.getName() : Bundle.MessageAccountPanel_unknown_label());
|
||||||
button.setText(persona != null ? Bundle.MessageAccountPanel_button_view_label() : Bundle.MessageAccountPanel_button_create_label());
|
button.setText(persona != null ? Bundle.MessageAccountPanel_button_view_label() : Bundle.MessageAccountPanel_button_create_label());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getNameFromContactArtifact(BlackboardArtifact contactArtifact) throws TskCoreException {
|
||||||
|
if (contactArtifact != null) {
|
||||||
|
BlackboardAttribute attribute = contactArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME));
|
||||||
|
if (attribute != null) {
|
||||||
|
return attribute.getValueString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Bundle.MessageAccountPanel_unknown_label();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets a new persona for this object and update the controls.
|
* Sets a new persona for this object and update the controls.
|
||||||
*
|
*
|
||||||
@ -365,6 +401,17 @@ final class MessageAccountPanel extends JPanel {
|
|||||||
|
|
||||||
return group;
|
return group;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private SequentialGroup getContactSequentialGroup(GroupLayout layout) {
|
||||||
|
SequentialGroup group = layout.createSequentialGroup();
|
||||||
|
|
||||||
|
group
|
||||||
|
.addComponent(contactHeader)
|
||||||
|
.addPreferredGap(ComponentPlacement.RELATED)
|
||||||
|
.addComponent(contactDisplayName);
|
||||||
|
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates the vertical layout code for the persona line.
|
* Generates the vertical layout code for the persona line.
|
||||||
@ -379,6 +426,12 @@ final class MessageAccountPanel extends JPanel {
|
|||||||
.addComponent(personaDisplayName)
|
.addComponent(personaDisplayName)
|
||||||
.addComponent(button);
|
.addComponent(button);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ParallelGroup getContactLineVerticalGroup(GroupLayout layout) {
|
||||||
|
return layout.createParallelGroup(Alignment.BASELINE)
|
||||||
|
.addComponent(contactHeader)
|
||||||
|
.addComponent(contactDisplayName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -447,10 +447,8 @@ public class MessageArtifactViewer extends javax.swing.JPanel implements Artifac
|
|||||||
resetComponent();
|
resetComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
msgbodyTabbedPane.setEnabledAt(ACCT_TAB_INDEX, CentralRepository.isEnabled());
|
msgbodyTabbedPane.setEnabledAt(ACCT_TAB_INDEX, true);
|
||||||
if(CentralRepository.isEnabled()) {
|
accountsPanel.setArtifact(artifact);
|
||||||
accountsPanel.setArtifact(artifact);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
160
Core/src/org/sleuthkit/autopsy/guiutils/ContactCache.java
Executable file
160
Core/src/org/sleuthkit/autopsy/guiutils/ContactCache.java
Executable file
@ -0,0 +1,160 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2020 Basis Technology Corp.
|
||||||
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.sleuthkit.autopsy.guiutils;
|
||||||
|
|
||||||
|
import com.google.common.cache.CacheBuilder;
|
||||||
|
import com.google.common.cache.CacheLoader;
|
||||||
|
import com.google.common.cache.LoadingCache;
|
||||||
|
import java.beans.PropertyChangeListener;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.EnumSet;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
|
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||||
|
import static org.sleuthkit.autopsy.ingest.IngestManager.IngestModuleEvent.DATA_ADDED;
|
||||||
|
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
|
||||||
|
import org.sleuthkit.datamodel.Account;
|
||||||
|
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||||
|
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||||
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A singleton cache of the Contact artifacts for accounts. The map of account
|
||||||
|
* unique ids to list of contact artifacts is stored in a LoadingCache which
|
||||||
|
* expires after 10 of non-use.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public final class ContactCache {
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(ContactCache.class.getName());
|
||||||
|
|
||||||
|
private static ContactCache instance;
|
||||||
|
|
||||||
|
private final LoadingCache<String, Map<String, List<BlackboardArtifact>>> accountMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the list of Contacts for the given Account.
|
||||||
|
*
|
||||||
|
* @param account Account instance.
|
||||||
|
*
|
||||||
|
* @return List of TSK_CONTACT artifacts that references the given Account.
|
||||||
|
* An empty list is returned if no contacts are found.
|
||||||
|
*
|
||||||
|
* @throws ExecutionException
|
||||||
|
*/
|
||||||
|
public static synchronized List<BlackboardArtifact> getContacts(Account account) throws ExecutionException {
|
||||||
|
return getInstance().accountMap.get("realMap").get(account.getTypeSpecificID());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Force the cache to invalidate all entries.
|
||||||
|
*/
|
||||||
|
static synchronized void invalidateCache() {
|
||||||
|
getInstance().accountMap.invalidateAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a new instance.
|
||||||
|
*/
|
||||||
|
private ContactCache() {
|
||||||
|
|
||||||
|
accountMap = CacheBuilder.newBuilder().expireAfterAccess(10, TimeUnit.MINUTES).build(
|
||||||
|
new CacheLoader<String, Map<String, List<BlackboardArtifact>>>() {
|
||||||
|
@Override
|
||||||
|
public Map<String, List<BlackboardArtifact>> load(String key) {
|
||||||
|
try {
|
||||||
|
return buildMap();
|
||||||
|
} catch (SQLException | TskCoreException ex) {
|
||||||
|
logger.log(Level.WARNING, "Failed to build account to contact map", ex);
|
||||||
|
}
|
||||||
|
return new HashMap<>(); // Return an empty map if there is an exception to avoid NPE and continual trying.
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
PropertyChangeListener ingestListener = pce -> {
|
||||||
|
String eventType = pce.getPropertyName();
|
||||||
|
if (eventType.equals(DATA_ADDED.toString())) {
|
||||||
|
ModuleDataEvent eventData = (ModuleDataEvent) pce.getOldValue();
|
||||||
|
if (eventData.getBlackboardArtifactType().getTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT.getTypeID()) {
|
||||||
|
invalidateCache();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
IngestManager.getInstance().addIngestModuleEventListener(EnumSet.of(DATA_ADDED), ingestListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the singleton instance of the cache object.
|
||||||
|
*
|
||||||
|
* @return AccountCache instance.
|
||||||
|
*/
|
||||||
|
private static synchronized ContactCache getInstance() {
|
||||||
|
if (instance == null) {
|
||||||
|
instance = new ContactCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds the map of account IDs to contacts that reference them.
|
||||||
|
*
|
||||||
|
* @return A map of account IDs to contact artifacts.
|
||||||
|
*
|
||||||
|
* @throws TskCoreException
|
||||||
|
* @throws SQLException
|
||||||
|
*/
|
||||||
|
private Map<String, List<BlackboardArtifact>> buildMap() throws TskCoreException, SQLException {
|
||||||
|
Map<String, List<BlackboardArtifact>> acctMap = new HashMap<>();
|
||||||
|
List<BlackboardArtifact> contactList = Case.getCurrentCase().getSleuthkitCase().getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT);
|
||||||
|
|
||||||
|
for(BlackboardArtifact contactArtifact: contactList) {
|
||||||
|
List<BlackboardAttribute> contactAttributes = contactArtifact.getAttributes();
|
||||||
|
for(BlackboardAttribute attribute: contactAttributes) {
|
||||||
|
String typeName = attribute.getAttributeType().getTypeName();
|
||||||
|
|
||||||
|
if(typeName.startsWith("TSK_EMAIL")
|
||||||
|
|| typeName.startsWith("TSK_PHONE")
|
||||||
|
|| typeName.startsWith("TSK_NAME")
|
||||||
|
|| typeName.startsWith("TSK_ID")) {
|
||||||
|
String accountID = attribute.getValueString();
|
||||||
|
List<BlackboardArtifact> artifactList = acctMap.get(accountID);
|
||||||
|
if(artifactList == null) {
|
||||||
|
artifactList = new ArrayList<>();
|
||||||
|
acctMap.put(accountID, artifactList);
|
||||||
|
}
|
||||||
|
if(!artifactList.contains(contactArtifact)) {
|
||||||
|
artifactList.add(contactArtifact);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return acctMap;
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user