19 package org.sleuthkit.autopsy.contentviewers.artifactviewers;
21 import java.awt.Component;
22 import java.awt.GridBagConstraints;
23 import java.awt.GridBagLayout;
24 import java.awt.Insets;
25 import java.awt.event.ActionListener;
26 import java.awt.image.BufferedImage;
28 import java.io.IOException;
29 import java.util.ArrayList;
30 import java.util.Collection;
31 import java.util.Collections;
32 import java.util.HashMap;
33 import java.util.List;
35 import java.util.concurrent.CancellationException;
36 import java.util.concurrent.ExecutionException;
37 import java.util.logging.Level;
38 import java.util.stream.Collectors;
39 import javax.imageio.ImageIO;
40 import javax.swing.ImageIcon;
41 import javax.swing.JButton;
42 import javax.swing.JLabel;
43 import javax.swing.JOptionPane;
44 import javax.swing.JScrollPane;
45 import javax.swing.SwingWorker;
46 import org.apache.commons.lang.StringUtils;
47 import org.openide.util.NbBundle;
48 import org.openide.util.lookup.ServiceProvider;
71 @ServiceProvider(service = ArtifactContentViewer.class)
75 private static final long serialVersionUID = 1L;
77 private GridBagLayout m_gridBagLayout =
new GridBagLayout();
78 private GridBagConstraints m_constraints =
new GridBagConstraints();
86 private List<BlackboardAttribute> phoneNumList =
new ArrayList<>();
87 private List<BlackboardAttribute> emailList =
new ArrayList<>();
88 private List<BlackboardAttribute> nameList =
new ArrayList<>();
89 private List<BlackboardAttribute> otherList =
new ArrayList<>();
90 private List<BlackboardAttribute> accountAttributesList =
new ArrayList<>();
92 private final static String DEFAULT_IMAGE_PATH =
"/org/sleuthkit/autopsy/images/defaultContact.png";
96 private final List<CentralRepoAccount> contactUniqueAccountsList =
new ArrayList<>();
100 private final Map<Persona, ArrayList<CentralRepoAccount>> contactUniquePersonasMap =
new HashMap<>();
118 @SuppressWarnings(
"unchecked")
120 private
void initComponents() {
123 setLayout(
new java.awt.GridBagLayout());
131 if (artifact == null) {
136 extractArtifactData(artifact);
137 }
catch (TskCoreException ex) {
138 logger.log(Level.SEVERE, String.format(
"Error getting attributes for artifact (artifact_id=%d, obj_id=%d)", artifact.getArtifactID(), artifact.getObjectID()), ex);
144 this.setLayout(this.m_gridBagLayout);
152 return new JScrollPane(
this, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
157 return (artifact != null)
158 && (artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT.getTypeID());
169 this.contactArtifact = artifact;
171 phoneNumList =
new ArrayList<>();
172 emailList =
new ArrayList<>();
173 nameList =
new ArrayList<>();
174 otherList =
new ArrayList<>();
175 accountAttributesList =
new ArrayList<>();
178 for (BlackboardAttribute bba : contactArtifact.getAttributes()) {
179 if (bba.getAttributeType().getTypeName().startsWith(
"TSK_PHONE")) {
180 phoneNumList.add(bba);
181 accountAttributesList.add(bba);
182 }
else if (bba.getAttributeType().getTypeName().startsWith(
"TSK_EMAIL")) {
184 accountAttributesList.add(bba);
185 }
else if (bba.getAttributeType().getTypeName().startsWith(
"TSK_NAME")) {
189 if (bba.getAttributeType().getTypeName().equalsIgnoreCase(
"TSK_ID")) {
190 accountAttributesList.add(bba);
195 datasourceName = contactArtifact.getDataSource().getName();
204 updateContactDetails();
210 initiatePersonasSearch();
218 "ContactArtifactViewer_phones_header=Phone",
219 "ContactArtifactViewer_emails_header=Email",
220 "ContactArtifactViewer_others_header=Other",})
224 updateContactImage(m_gridBagLayout, m_constraints);
225 updateContactName(m_gridBagLayout, m_constraints);
228 updateContactMethodSection(phoneNumList, Bundle.ContactArtifactViewer_phones_header(), m_gridBagLayout, m_constraints);
229 updateContactMethodSection(emailList, Bundle.ContactArtifactViewer_emails_header(), m_gridBagLayout, m_constraints);
230 updateContactMethodSection(otherList, Bundle.ContactArtifactViewer_others_header(), m_gridBagLayout, m_constraints);
241 "ContactArtifactViewer.contactImage.text=",})
242 private void updateContactImage(GridBagLayout contactPanelLayout, GridBagConstraints contactPanelConstraints) {
244 Insets savedInsets = contactPanelConstraints.insets;
245 contactPanelConstraints.gridy = 0;
246 contactPanelConstraints.gridx = 0;
247 contactPanelConstraints.insets =
new Insets(0, 0, 0, 0);
249 javax.swing.JLabel contactImage =
new javax.swing.JLabel();
250 contactImage.setIcon(getImageFromArtifact(contactArtifact));
251 contactImage.setText(Bundle.ContactArtifactViewer_contactImage_text());
254 CommunicationArtifactViewerHelper.addComponent(
this, contactPanelLayout, contactPanelConstraints, contactImage);
255 CommunicationArtifactViewerHelper.addLineEndGlue(
this, contactPanelLayout, contactPanelConstraints);
256 contactPanelConstraints.gridy++;
258 contactPanelConstraints.insets = savedInsets;
269 "ContactArtifactViewer_contactname_unknown=Unknown",})
270 private void updateContactName(GridBagLayout contactPanelLayout, GridBagConstraints contactPanelConstraints) {
272 boolean foundName =
false;
273 for (BlackboardAttribute bba : this.nameList) {
274 if (StringUtils.isEmpty(bba.getValueString()) ==
false) {
275 contactName = bba.getDisplayString();
277 CommunicationArtifactViewerHelper.addHeader(
this, contactPanelLayout, contactPanelConstraints, contactName);
282 if (foundName ==
false) {
283 CommunicationArtifactViewerHelper.addHeader(
this, contactPanelLayout, contactPanelConstraints, Bundle.ContactArtifactViewer_contactname_unknown());
297 private void updateContactMethodSection(List<BlackboardAttribute> sectionAttributesList, String sectionHeader, GridBagLayout contactPanelLayout, GridBagConstraints contactPanelConstraints) {
300 if (sectionAttributesList.isEmpty()) {
304 CommunicationArtifactViewerHelper.addHeader(
this, contactPanelLayout, contactPanelConstraints, sectionHeader);
305 for (BlackboardAttribute bba : sectionAttributesList) {
306 CommunicationArtifactViewerHelper.addKey(
this, contactPanelLayout, contactPanelConstraints, bba.getAttributeType().getDisplayName());
307 CommunicationArtifactViewerHelper.addValue(
this, contactPanelLayout, contactPanelConstraints, bba.getDisplayString());
315 "ContactArtifactViewer_heading_Source=Source",
316 "ContactArtifactViewer_label_datasource=Data Source",})
318 CommunicationArtifactViewerHelper.addHeader(
this, this.m_gridBagLayout, m_constraints, Bundle.ContactArtifactViewer_heading_Source());
319 CommunicationArtifactViewerHelper.addKey(
this, m_gridBagLayout, m_constraints, Bundle.ContactArtifactViewer_label_datasource());
320 CommunicationArtifactViewerHelper.addValue(
this, m_gridBagLayout, m_constraints, datasourceName);
329 "ContactArtifactViewer_persona_header=Persona",
330 "ContactArtifactViewer_persona_searching=Searching...",
331 "ContactArtifactViewer_cr_disabled_message=Enable Central Repository to view, create and edit personas.",
332 "ContactArtifactViewer_persona_unknown=Unknown"
337 JLabel personaHeader = CommunicationArtifactViewerHelper.addHeader(
this, m_gridBagLayout, m_constraints, Bundle.ContactArtifactViewer_persona_header());
339 m_constraints.gridy++;
343 ? Bundle.ContactArtifactViewer_persona_searching()
344 : Bundle.ContactArtifactViewer_persona_unknown();
346 this.personaSearchStatusLabel =
new javax.swing.JLabel();
347 personaSearchStatusLabel.setText(personaStatusLabelText);
349 m_constraints.gridx = 0;
351 CommunicationArtifactViewerHelper.addComponent(
this, m_gridBagLayout, m_constraints, personaSearchStatusLabel);
356 personaSearchTask.execute();
358 personaHeader.setEnabled(
false);
359 personaSearchStatusLabel.setEnabled(
false);
361 CommunicationArtifactViewerHelper.addBlankLine(
this, m_gridBagLayout, m_constraints);
362 m_constraints.gridy++;
363 CommunicationArtifactViewerHelper.addMessageRow(
this, m_gridBagLayout, m_constraints, Bundle.ContactArtifactViewer_cr_disabled_message());
364 m_constraints.gridy++;
366 CommunicationArtifactViewerHelper.addPageEndGlue(
this, m_gridBagLayout, this.m_constraints);
377 this.
remove(personaSearchStatusLabel);
379 m_constraints.gridx = 0;
380 if (contactUniquePersonasMap.isEmpty()) {
382 showPersona(null, 0, Collections.emptyList(), this.m_gridBagLayout, this.m_constraints);
384 int matchCounter = 0;
385 for (Map.Entry<
Persona, ArrayList<CentralRepoAccount>> entry : contactUniquePersonasMap.entrySet()) {
386 List<CentralRepoAccount> missingAccounts =
new ArrayList<>();
387 ArrayList<CentralRepoAccount> personaAccounts = entry.getValue();
392 if (personaAccounts.contains(account) ==
false) {
393 missingAccounts.add(account);
397 showPersona(entry.getKey(), matchCounter, missingAccounts, m_gridBagLayout, m_constraints);
398 m_constraints.gridy += 2;
403 CommunicationArtifactViewerHelper.addPageEndGlue(
this, m_gridBagLayout, this.m_constraints);
406 this.setLayout(this.m_gridBagLayout);
424 "ContactArtifactViewer_persona_label=Persona ",
425 "ContactArtifactViewer_persona_no_match=No matches found",
426 "ContactArtifactViewer_persona_button_view=View",
427 "ContactArtifactViewer_persona_button_new=Create",
428 "ContactArtifactViewer_persona_match_num=Match ",
429 "ContactArtifactViewer_missing_account_label=Missing contact account",
430 "ContactArtifactViewer_found_all_accounts_label=All accounts found."
432 private void showPersona(
Persona persona,
int matchNumber, List<CentralRepoAccount> missingAccountsList, GridBagLayout gridBagLayout, GridBagConstraints constraints) {
435 Insets savedInsets = constraints.insets;
438 Insets extraIndentInsets =
new java.awt.Insets(0, 2 * CommunicationArtifactViewerHelper.LEFT_INSET, 0, 0);
441 constraints.gridx = 0;
442 javax.swing.JLabel matchNumberLabel = CommunicationArtifactViewerHelper.addKey(
this, gridBagLayout, constraints, String.format(
"%s %d", Bundle.ContactArtifactViewer_persona_match_num(), matchNumber));
444 javax.swing.JLabel personaNameLabel =
new javax.swing.JLabel();
445 javax.swing.JButton personaButton =
new javax.swing.JButton();
448 String personaButtonText;
449 ActionListener personaButtonListener;
450 if (persona != null) {
451 personaName = persona.
getName();
452 personaButtonText = Bundle.ContactArtifactViewer_persona_button_view();
455 matchNumberLabel.setVisible(
false);
456 personaName = Bundle.ContactArtifactViewer_persona_no_match();
457 personaButtonText = Bundle.ContactArtifactViewer_persona_button_new();
463 personaNameLabel.setText(personaName);
464 gridBagLayout.setConstraints(personaNameLabel, constraints);
465 CommunicationArtifactViewerHelper.addComponent(
this, gridBagLayout, constraints, personaNameLabel);
471 personaButton.setText(personaButtonText);
472 personaButton.addActionListener(personaButtonListener);
475 personaButton.setMargin(
new Insets(0, 5, 0, 5));
476 gridBagLayout.setConstraints(personaButton, constraints);
477 CommunicationArtifactViewerHelper.addComponent(
this, gridBagLayout, constraints, personaButton);
478 CommunicationArtifactViewerHelper.addLineEndGlue(
this, gridBagLayout, constraints);
480 constraints.insets = savedInsets;
483 if (persona != null) {
484 if (missingAccountsList.isEmpty()) {
486 constraints.gridx = 1;
489 javax.swing.JLabel accountsStatus =
new javax.swing.JLabel(Bundle.ContactArtifactViewer_found_all_accounts_label());
490 constraints.insets = extraIndentInsets;
491 CommunicationArtifactViewerHelper.addComponent(
this, gridBagLayout, constraints, accountsStatus);
492 constraints.insets = savedInsets;
494 CommunicationArtifactViewerHelper.addLineEndGlue(
this, gridBagLayout, constraints);
499 constraints.gridx = 0;
503 constraints.insets = extraIndentInsets;
504 CommunicationArtifactViewerHelper.addKeyAtCol(
this, gridBagLayout, constraints, Bundle.ContactArtifactViewer_missing_account_label(), 1);
505 constraints.insets = savedInsets;
507 CommunicationArtifactViewerHelper.addValueAtCol(
this, gridBagLayout, constraints, missingAccount.getIdentifier(), 2);
513 constraints.insets = savedInsets;
521 contactArtifact = null;
523 datasourceName = null;
525 contactUniqueAccountsList.clear();
526 contactUniquePersonasMap.clear();
528 phoneNumList.clear();
532 accountAttributesList.clear();
534 if (personaSearchTask != null) {
535 personaSearchTask.cancel(Boolean.TRUE);
536 personaSearchTask = null;
541 this.setLayout(null);
543 m_gridBagLayout =
new GridBagLayout();
544 m_constraints =
new GridBagConstraints();
546 m_constraints.anchor = GridBagConstraints.FIRST_LINE_START;
547 m_constraints.gridy = 0;
548 m_constraints.gridx = 0;
549 m_constraints.weighty = 0.0;
550 m_constraints.weightx = 0.0;
551 m_constraints.insets =
new java.awt.Insets(0, CommunicationArtifactViewerHelper.LEFT_INSET, 0, 0);
552 m_constraints.fill = GridBagConstraints.NONE;
565 ImageIcon imageIcon = defaultImage;
567 if (artifact == null) {
571 BlackboardArtifact.ARTIFACT_TYPE artifactType = BlackboardArtifact.ARTIFACT_TYPE.fromID(artifact.getArtifactTypeID());
572 if (artifactType != BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT) {
577 for (Content content : artifact.getChildren()) {
578 if (content instanceof AbstractFile) {
579 AbstractFile file = (AbstractFile) content;
582 BufferedImage image = ImageIO.read(
new File(file.getLocalAbsPath()));
583 imageIcon =
new ImageIcon(image);
585 }
catch (IOException ex) {
592 }
catch (TskCoreException ex) {
593 logger.log(Level.WARNING, String.format(
"Unable to load image for contact: %d", artifact.getId()), ex);
606 private final List<CentralRepoAccount> uniqueAccountsList =
new ArrayList<>();
615 this.artifact = artifact;
619 protected Map<Persona, ArrayList<CentralRepoAccount>>
doInBackground() throws Exception {
621 Map<Persona, ArrayList<CentralRepoAccount>> uniquePersonas =
new HashMap<>();
624 List<Account> contactAccountsList = commManager.getAccountsRelatedToArtifact(artifact);
626 for (Account account : contactAccountsList) {
628 return new HashMap<>();
632 if (!account.getAccountType().equals(Account.Type.DEVICE)) {
636 if (crAccount != null && uniqueAccountsList.contains(crAccount) ==
false) {
637 uniqueAccountsList.add(crAccount);
642 if (personaAccounts != null && !personaAccounts.isEmpty()) {
644 Collection<Persona> personas
648 .collect(Collectors.toList());
651 for (
Persona persona : personas) {
652 if (uniquePersonas.containsKey(persona) ==
false) {
656 .collect(Collectors.toList());
658 ArrayList<CentralRepoAccount> personaAccountsList =
new ArrayList<>(accounts);
659 uniquePersonas.put(persona, personaAccountsList);
665 return uniquePersonas;
671 Map<Persona, ArrayList<CentralRepoAccount>> personasMap;
673 personasMap = super.get();
675 if (this.isCancelled()) {
679 contactUniquePersonasMap.clear();
680 contactUniquePersonasMap.putAll(personasMap);
681 contactUniqueAccountsList.clear();
682 contactUniqueAccountsList.addAll(uniqueAccountsList);
686 }
catch (CancellationException ex) {
687 logger.log(Level.INFO,
"Persona searching was canceled.");
688 }
catch (InterruptedException ex) {
689 logger.log(Level.INFO,
"Persona searching was interrupted.");
690 }
catch (ExecutionException ex) {
691 logger.log(Level.SEVERE,
"Fatal error during Persona search.", ex);
713 this.personaNameLabel = personaNameLabel;
714 this.personaActionButton = personaActionButton;
723 return personaNameLabel;
732 return personaActionButton;
750 this.personaUIComponents = personaUIComponents;
751 this.parentComponent = parentComponent;
755 "ContactArtifactViewer_persona_account_justification=Account found in Contact artifact",
756 "# {0} - accountIdentifer",
757 "ContactArtifactViewer_id_not_found_in_cr=Unable to find account(s) associated with contact {0} in the Central Repository."
769 if (contactName != null) {
778 if(contactName != null && contactUniqueAccountsList.isEmpty()) {
801 this.persona = persona;
802 this.parentComponent = parentComponent;
817 private final Component parentComponent;
818 private final PersonaUIComponents personaUIComponents;
825 PersonaCreateCallbackImpl(Component parentComponent, PersonaUIComponents personaUIComponents) {
826 this.parentComponent = parentComponent;
827 this.personaUIComponents = personaUIComponents;
831 public void callback(Persona persona) {
833 if (persona != null) {
836 personaUIComponents.getPersonaNameLabel().setText(persona.getName());
837 personaUIComponents.getPersonaActionButton().setText(Bundle.ContactArtifactViewer_persona_button_view());
840 for (ActionListener act : personaButton.getActionListeners()) {
841 personaButton.removeActionListener(act);
843 personaButton.addActionListener(
new ViewPersonaButtonListener(parentComponent, persona));
847 personaButton.getParent().revalidate();
848 personaButton.getParent().repaint();
855 class PersonaViewCallbackImpl
implements PersonaDetailsDialogCallback {
858 public void callback(Persona persona) {
boolean addAccount(CentralRepoAccount account, String justification, Persona.Confidence confidence)
JButton getPersonaActionButton()
static Collection< PersonaAccount > getPersonaAccountsForAccount(long accountId)
void actionPerformed(java.awt.event.ActionEvent evt)
void setStartupPopupMessage(String message)
Collection< PersonaAccount > getPersonaAccounts()
void showPersona(Persona persona, int matchNumber, List< CentralRepoAccount > missingAccountsList, GridBagLayout gridBagLayout, GridBagConstraints constraints)
CentralRepoAccount getAccount(CentralRepoAccount.CentralRepoAccountType crAccountType, String accountUniqueID)
final ImageIcon defaultImage
final JButton personaActionButton
void updateContactName(GridBagLayout contactPanelLayout, GridBagConstraints contactPanelConstraints)
void updateContactImage(GridBagLayout contactPanelLayout, GridBagConstraints contactPanelConstraints)
PersonaDetailsPanel getDetailsPanel()
void initiatePersonasSearch()
Map< Persona, ArrayList< CentralRepoAccount > > doInBackground()
final PersonaUIComponents personaUIComponents
JLabel personaSearchStatusLabel
void updateContactDetails()
void updateContactMethodSection(List< BlackboardAttribute > sectionAttributesList, String sectionHeader, GridBagLayout contactPanelLayout, GridBagConstraints contactPanelConstraints)
void actionPerformed(java.awt.event.ActionEvent evt)
final BlackboardArtifact artifact
BlackboardArtifact contactArtifact
SleuthkitCase getSleuthkitCase()
void setPersonaName(String name)
static Case getCurrentCase()
synchronized static Logger getLogger(String name)
final JLabel personaNameLabel
CentralRepoAccount getAccount()
final Component parentComponent
ContactPersonaSearcherTask personaSearchTask
boolean isSupported(BlackboardArtifact artifact)
CentralRepoAccountType getAccountTypeByName(String accountTypeName)
static CentralRepository getInstance()
final Component parentComponent
ImageIcon getImageFromArtifact(BlackboardArtifact artifact)
static boolean isEnabled()
void setArtifact(BlackboardArtifact artifact)
JLabel getPersonaNameLabel()
void extractArtifactData(BlackboardArtifact artifact)