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.JScrollPane;
44 import javax.swing.SwingWorker;
45 import org.apache.commons.lang.StringUtils;
46 import org.openide.util.NbBundle;
47 import org.openide.util.lookup.ServiceProvider;
70 @ServiceProvider(service = ArtifactContentViewer.class)
74 private static final long serialVersionUID = 1L;
76 private GridBagLayout m_gridBagLayout =
new GridBagLayout();
77 private GridBagConstraints m_constraints =
new GridBagConstraints();
85 private List<BlackboardAttribute> phoneNumList =
new ArrayList<>();
86 private List<BlackboardAttribute> emailList =
new ArrayList<>();
87 private List<BlackboardAttribute> nameList =
new ArrayList<>();
88 private List<BlackboardAttribute> otherList =
new ArrayList<>();
89 private List<BlackboardAttribute> accountAttributesList =
new ArrayList<>();
91 private final static String DEFAULT_IMAGE_PATH =
"/org/sleuthkit/autopsy/images/defaultContact.png";
95 private final List<CentralRepoAccount> contactUniqueAccountsList =
new ArrayList<>();
99 private final Map<Persona, ArrayList<CentralRepoAccount>> contactUniquePersonasMap =
new HashMap<>();
117 @SuppressWarnings(
"unchecked")
119 private
void initComponents() {
122 setLayout(
new java.awt.GridBagLayout());
130 if (artifact == null) {
135 extractArtifactData(artifact);
136 }
catch (TskCoreException ex) {
137 logger.log(Level.SEVERE, String.format(
"Error getting attributes for artifact (artifact_id=%d, obj_id=%d)", artifact.getArtifactID(), artifact.getObjectID()), ex);
143 this.setLayout(this.m_gridBagLayout);
151 return new JScrollPane(
this, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
156 return (artifact != null)
157 && (artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT.getTypeID());
168 this.contactArtifact = artifact;
170 phoneNumList =
new ArrayList<>();
171 emailList =
new ArrayList<>();
172 nameList =
new ArrayList<>();
173 otherList =
new ArrayList<>();
174 accountAttributesList =
new ArrayList<>();
177 for (BlackboardAttribute bba : contactArtifact.getAttributes()) {
178 if (bba.getAttributeType().getTypeName().startsWith(
"TSK_PHONE")) {
179 phoneNumList.add(bba);
180 accountAttributesList.add(bba);
181 }
else if (bba.getAttributeType().getTypeName().startsWith(
"TSK_EMAIL")) {
183 accountAttributesList.add(bba);
184 }
else if (bba.getAttributeType().getTypeName().startsWith(
"TSK_NAME")) {
188 if (bba.getAttributeType().getTypeName().equalsIgnoreCase(
"TSK_ID")) {
189 accountAttributesList.add(bba);
194 datasourceName = contactArtifact.getDataSource().getName();
203 updateContactDetails();
209 initiatePersonasSearch();
217 "ContactArtifactViewer_phones_header=Phone",
218 "ContactArtifactViewer_emails_header=Email",
219 "ContactArtifactViewer_others_header=Other",})
223 updateContactImage(m_gridBagLayout, m_constraints);
224 updateContactName(m_gridBagLayout, m_constraints);
227 updateContactMethodSection(phoneNumList, Bundle.ContactArtifactViewer_phones_header(), m_gridBagLayout, m_constraints);
228 updateContactMethodSection(emailList, Bundle.ContactArtifactViewer_emails_header(), m_gridBagLayout, m_constraints);
229 updateContactMethodSection(otherList, Bundle.ContactArtifactViewer_others_header(), m_gridBagLayout, m_constraints);
240 "ContactArtifactViewer.contactImage.text=",})
241 private void updateContactImage(GridBagLayout contactPanelLayout, GridBagConstraints contactPanelConstraints) {
243 Insets savedInsets = contactPanelConstraints.insets;
244 contactPanelConstraints.gridy = 0;
245 contactPanelConstraints.gridx = 0;
246 contactPanelConstraints.insets =
new Insets(0, 0, 0, 0);
248 javax.swing.JLabel contactImage =
new javax.swing.JLabel();
249 contactImage.setIcon(getImageFromArtifact(contactArtifact));
250 contactImage.setText(Bundle.ContactArtifactViewer_contactImage_text());
253 CommunicationArtifactViewerHelper.addComponent(
this, contactPanelLayout, contactPanelConstraints, contactImage);
254 CommunicationArtifactViewerHelper.addLineEndGlue(
this, contactPanelLayout, contactPanelConstraints);
255 contactPanelConstraints.gridy++;
257 contactPanelConstraints.insets = savedInsets;
268 "ContactArtifactViewer_contactname_unknown=Unknown",})
269 private void updateContactName(GridBagLayout contactPanelLayout, GridBagConstraints contactPanelConstraints) {
271 boolean foundName =
false;
272 for (BlackboardAttribute bba : this.nameList) {
273 if (StringUtils.isEmpty(bba.getValueString()) ==
false) {
274 contactName = bba.getDisplayString();
276 CommunicationArtifactViewerHelper.addHeader(
this, contactPanelLayout, contactPanelConstraints, contactName);
281 if (foundName ==
false) {
282 CommunicationArtifactViewerHelper.addHeader(
this, contactPanelLayout, contactPanelConstraints, Bundle.ContactArtifactViewer_contactname_unknown());
296 private void updateContactMethodSection(List<BlackboardAttribute> sectionAttributesList, String sectionHeader, GridBagLayout contactPanelLayout, GridBagConstraints contactPanelConstraints) {
299 if (sectionAttributesList.isEmpty()) {
303 CommunicationArtifactViewerHelper.addHeader(
this, contactPanelLayout, contactPanelConstraints, sectionHeader);
304 for (BlackboardAttribute bba : sectionAttributesList) {
305 CommunicationArtifactViewerHelper.addKey(
this, contactPanelLayout, contactPanelConstraints, bba.getAttributeType().getDisplayName());
306 CommunicationArtifactViewerHelper.addValue(
this, contactPanelLayout, contactPanelConstraints, bba.getDisplayString());
314 "ContactArtifactViewer_heading_Source=Source",
315 "ContactArtifactViewer_label_datasource=Data Source",})
317 CommunicationArtifactViewerHelper.addHeader(
this, this.m_gridBagLayout, m_constraints, Bundle.ContactArtifactViewer_heading_Source());
318 CommunicationArtifactViewerHelper.addKey(
this, m_gridBagLayout, m_constraints, Bundle.ContactArtifactViewer_label_datasource());
319 CommunicationArtifactViewerHelper.addValue(
this, m_gridBagLayout, m_constraints, datasourceName);
328 "ContactArtifactViewer_persona_header=Persona",
329 "ContactArtifactViewer_persona_searching=Searching...",
330 "ContactArtifactViewer_cr_disabled_message=Enable Central Repository to view, create and edit personas.",
331 "ContactArtifactViewer_persona_unknown=Unknown"
336 JLabel personaHeader = CommunicationArtifactViewerHelper.addHeader(
this, m_gridBagLayout, m_constraints, Bundle.ContactArtifactViewer_persona_header());
338 m_constraints.gridy++;
342 ? Bundle.ContactArtifactViewer_persona_searching()
343 : Bundle.ContactArtifactViewer_persona_unknown();
345 this.personaSearchStatusLabel =
new javax.swing.JLabel();
346 personaSearchStatusLabel.setText(personaStatusLabelText);
348 m_constraints.gridx = 0;
350 CommunicationArtifactViewerHelper.addComponent(
this, m_gridBagLayout, m_constraints, personaSearchStatusLabel);
355 personaSearchTask.execute();
357 personaHeader.setEnabled(
false);
358 personaSearchStatusLabel.setEnabled(
false);
360 CommunicationArtifactViewerHelper.addBlankLine(
this, m_gridBagLayout, m_constraints);
361 m_constraints.gridy++;
362 CommunicationArtifactViewerHelper.addMessageRow(
this, m_gridBagLayout, m_constraints, Bundle.ContactArtifactViewer_cr_disabled_message());
363 m_constraints.gridy++;
365 CommunicationArtifactViewerHelper.addPageEndGlue(
this, m_gridBagLayout, this.m_constraints);
376 this.
remove(personaSearchStatusLabel);
378 m_constraints.gridx = 0;
379 if (contactUniquePersonasMap.isEmpty()) {
381 showPersona(null, 0, Collections.emptyList(), this.m_gridBagLayout, this.m_constraints);
383 int matchCounter = 0;
384 for (Map.Entry<
Persona, ArrayList<CentralRepoAccount>> entry : contactUniquePersonasMap.entrySet()) {
385 List<CentralRepoAccount> missingAccounts =
new ArrayList<>();
386 ArrayList<CentralRepoAccount> personaAccounts = entry.getValue();
391 if (personaAccounts.contains(account) ==
false) {
392 missingAccounts.add(account);
396 showPersona(entry.getKey(), matchCounter, missingAccounts, m_gridBagLayout, m_constraints);
397 m_constraints.gridy += 2;
402 CommunicationArtifactViewerHelper.addPageEndGlue(
this, m_gridBagLayout, this.m_constraints);
405 this.setLayout(this.m_gridBagLayout);
423 "ContactArtifactViewer_persona_label=Persona ",
424 "ContactArtifactViewer_persona_no_match=No matches found",
425 "ContactArtifactViewer_persona_button_view=View",
426 "ContactArtifactViewer_persona_button_new=Create",
427 "ContactArtifactViewer_persona_match_num=Match ",
428 "ContactArtifactViewer_missing_account_label=Missing contact account",
429 "ContactArtifactViewer_found_all_accounts_label=All accounts found."
431 private void showPersona(
Persona persona,
int matchNumber, List<CentralRepoAccount> missingAccountsList, GridBagLayout gridBagLayout, GridBagConstraints constraints) {
434 Insets savedInsets = constraints.insets;
437 Insets extraIndentInsets =
new java.awt.Insets(0, 2 * CommunicationArtifactViewerHelper.LEFT_INSET, 0, 0);
440 constraints.gridx = 0;
441 javax.swing.JLabel matchNumberLabel = CommunicationArtifactViewerHelper.addKey(
this, gridBagLayout, constraints, String.format(
"%s %d", Bundle.ContactArtifactViewer_persona_match_num(), matchNumber));
443 javax.swing.JLabel personaNameLabel =
new javax.swing.JLabel();
444 javax.swing.JButton personaButton =
new javax.swing.JButton();
447 String personaButtonText;
448 ActionListener personaButtonListener;
449 if (persona != null) {
450 personaName = persona.
getName();
451 personaButtonText = Bundle.ContactArtifactViewer_persona_button_view();
454 matchNumberLabel.setVisible(
false);
455 personaName = Bundle.ContactArtifactViewer_persona_no_match();
456 personaButtonText = Bundle.ContactArtifactViewer_persona_button_new();
462 personaNameLabel.setText(personaName);
463 gridBagLayout.setConstraints(personaNameLabel, constraints);
464 CommunicationArtifactViewerHelper.addComponent(
this, gridBagLayout, constraints, personaNameLabel);
470 personaButton.setText(personaButtonText);
471 personaButton.addActionListener(personaButtonListener);
474 personaButton.setMargin(
new Insets(0, 5, 0, 5));
475 gridBagLayout.setConstraints(personaButton, constraints);
476 CommunicationArtifactViewerHelper.addComponent(
this, gridBagLayout, constraints, personaButton);
477 CommunicationArtifactViewerHelper.addLineEndGlue(
this, gridBagLayout, constraints);
479 constraints.insets = savedInsets;
482 if (persona != null) {
483 if (missingAccountsList.isEmpty()) {
485 constraints.gridx = 1;
488 javax.swing.JLabel accountsStatus =
new javax.swing.JLabel(Bundle.ContactArtifactViewer_found_all_accounts_label());
489 constraints.insets = extraIndentInsets;
490 CommunicationArtifactViewerHelper.addComponent(
this, gridBagLayout, constraints, accountsStatus);
491 constraints.insets = savedInsets;
493 CommunicationArtifactViewerHelper.addLineEndGlue(
this, gridBagLayout, constraints);
498 constraints.gridx = 0;
502 constraints.insets = extraIndentInsets;
503 CommunicationArtifactViewerHelper.addKeyAtCol(
this, gridBagLayout, constraints, Bundle.ContactArtifactViewer_missing_account_label(), 1);
504 constraints.insets = savedInsets;
506 CommunicationArtifactViewerHelper.addValueAtCol(
this, gridBagLayout, constraints, missingAccount.getIdentifier(), 2);
512 constraints.insets = savedInsets;
520 contactArtifact = null;
522 datasourceName = null;
524 contactUniqueAccountsList.clear();
525 contactUniquePersonasMap.clear();
527 phoneNumList.clear();
531 accountAttributesList.clear();
533 if (personaSearchTask != null) {
534 personaSearchTask.cancel(Boolean.TRUE);
535 personaSearchTask = null;
540 this.setLayout(null);
542 m_gridBagLayout =
new GridBagLayout();
543 m_constraints =
new GridBagConstraints();
545 m_constraints.anchor = GridBagConstraints.FIRST_LINE_START;
546 m_constraints.gridy = 0;
547 m_constraints.gridx = 0;
548 m_constraints.weighty = 0.0;
549 m_constraints.weightx = 0.0;
550 m_constraints.insets =
new java.awt.Insets(0, CommunicationArtifactViewerHelper.LEFT_INSET, 0, 0);
551 m_constraints.fill = GridBagConstraints.NONE;
564 ImageIcon imageIcon = defaultImage;
566 if (artifact == null) {
570 BlackboardArtifact.ARTIFACT_TYPE artifactType = BlackboardArtifact.ARTIFACT_TYPE.fromID(artifact.getArtifactTypeID());
571 if (artifactType != BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT) {
576 for (Content content : artifact.getChildren()) {
577 if (content instanceof AbstractFile) {
578 AbstractFile file = (AbstractFile) content;
581 BufferedImage image = ImageIO.read(
new File(file.getLocalAbsPath()));
582 imageIcon =
new ImageIcon(image);
584 }
catch (IOException ex) {
591 }
catch (TskCoreException ex) {
592 logger.log(Level.WARNING, String.format(
"Unable to load image for contact: %d", artifact.getId()), ex);
605 private final List<CentralRepoAccount> uniqueAccountsList =
new ArrayList<>();
614 this.artifact = artifact;
618 protected Map<Persona, ArrayList<CentralRepoAccount>>
doInBackground() throws Exception {
620 Map<Persona, ArrayList<CentralRepoAccount>> uniquePersonas =
new HashMap<>();
623 List<Account> contactAccountsList = commManager.getAccountsRelatedToArtifact(artifact);
625 for (Account account : contactAccountsList) {
627 return new HashMap<>();
631 if (!account.getAccountType().equals(Account.Type.DEVICE)) {
635 if (crAccount != null && uniqueAccountsList.contains(crAccount) ==
false) {
636 uniqueAccountsList.add(crAccount);
641 if (personaAccounts != null && !personaAccounts.isEmpty()) {
643 Collection<Persona> personas
647 .collect(Collectors.toList());
650 for (
Persona persona : personas) {
651 if (uniquePersonas.containsKey(persona) ==
false) {
655 .collect(Collectors.toList());
657 ArrayList<CentralRepoAccount> personaAccountsList =
new ArrayList<>(accounts);
658 uniquePersonas.put(persona, personaAccountsList);
664 return uniquePersonas;
670 Map<Persona, ArrayList<CentralRepoAccount>> personasMap;
672 personasMap = super.get();
674 if (this.isCancelled()) {
678 contactUniquePersonasMap.clear();
679 contactUniquePersonasMap.putAll(personasMap);
680 contactUniqueAccountsList.clear();
681 contactUniqueAccountsList.addAll(uniqueAccountsList);
685 }
catch (CancellationException ex) {
686 logger.log(Level.INFO,
"Persona searching was canceled.");
687 }
catch (InterruptedException ex) {
688 logger.log(Level.INFO,
"Persona searching was interrupted.");
689 }
catch (ExecutionException ex) {
690 logger.log(Level.SEVERE,
"Fatal error during Persona search.", ex);
712 this.personaNameLabel = personaNameLabel;
713 this.personaActionButton = personaActionButton;
722 return personaNameLabel;
731 return personaActionButton;
749 this.personaUIComponents = personaUIComponents;
750 this.parentComponent = parentComponent;
754 "ContactArtifactViewer_persona_account_justification=Account found in Contact artifact"
766 if (contactName != null) {
794 this.persona = persona;
795 this.parentComponent = parentComponent;
810 private final Component parentComponent;
811 private final PersonaUIComponents personaUIComponents;
818 PersonaCreateCallbackImpl(Component parentComponent, PersonaUIComponents personaUIComponents) {
819 this.parentComponent = parentComponent;
820 this.personaUIComponents = personaUIComponents;
824 public void callback(Persona persona) {
826 if (persona != null) {
829 personaUIComponents.getPersonaNameLabel().setText(persona.getName());
830 personaUIComponents.getPersonaActionButton().setText(Bundle.ContactArtifactViewer_persona_button_view());
833 for (ActionListener act : personaButton.getActionListeners()) {
834 personaButton.removeActionListener(act);
836 personaButton.addActionListener(
new ViewPersonaButtonListener(parentComponent, persona));
840 personaButton.getParent().revalidate();
841 personaButton.getParent().repaint();
848 class PersonaViewCallbackImpl
implements PersonaDetailsDialogCallback {
851 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)
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)