Autopsy  4.17.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
MessageAccountPanel.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2020 Basis Technology Corp.
5  * Contact: carrier <at> sleuthkit <dot> org
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 package org.sleuthkit.autopsy.contentviewers.artifactviewers;
20 
21 import java.awt.Dimension;
22 import java.awt.Toolkit;
23 import java.awt.datatransfer.StringSelection;
24 import java.awt.event.ActionEvent;
25 import java.awt.event.ActionListener;
26 import java.awt.event.MouseAdapter;
27 import java.awt.event.MouseEvent;
28 import java.util.ArrayList;
29 import java.util.Collection;
30 import java.util.List;
31 import java.util.concurrent.CancellationException;
32 import java.util.concurrent.ExecutionException;
33 import java.util.logging.Level;
34 import javax.swing.GroupLayout;
35 import javax.swing.GroupLayout.Alignment;
36 import javax.swing.GroupLayout.ParallelGroup;
37 import javax.swing.GroupLayout.SequentialGroup;
38 import javax.swing.JButton;
39 import javax.swing.JLabel;
40 import javax.swing.JMenuItem;
41 import javax.swing.JPanel;
42 import javax.swing.JPopupMenu;
43 import javax.swing.JTextPane;
44 import javax.swing.LayoutStyle.ComponentPlacement;
45 import javax.swing.SwingUtilities;
46 import javax.swing.SwingWorker;
47 import org.openide.util.NbBundle;
48 import org.openide.util.NbBundle.Messages;
61 import org.sleuthkit.datamodel.Account;
62 import org.sleuthkit.datamodel.BlackboardArtifact;
63 import org.sleuthkit.datamodel.BlackboardAttribute;
64 import org.sleuthkit.datamodel.CommunicationsManager;
65 import org.sleuthkit.datamodel.InvalidAccountIDException;
66 import org.sleuthkit.datamodel.DataSource;
67 import org.sleuthkit.datamodel.TskCoreException;
68 
73 final class MessageAccountPanel extends JPanel {
74 
75  private static final long serialVersionUID = 1L;
76  private final static Logger logger = Logger.getLogger(MessageAccountPanel.class.getName());
77 
78  private AccountFetcher currentFetcher = null;
79 
87  void setArtifact(BlackboardArtifact artifact) {
88  removeAll();
89  setLayout(null);
90  repaint();
91 
92  if (artifact == null) {
93  return;
94  }
95 
96  if (currentFetcher != null && !currentFetcher.isDone()) {
97  currentFetcher.cancel(true);
98  }
99 
100  currentFetcher = new AccountFetcher(artifact);
101  currentFetcher.execute();
102  }
103 
107  class AccountFetcher extends SwingWorker<List<AccountContainer>, Void> {
108 
109  private final BlackboardArtifact artifact;
110 
116  AccountFetcher(BlackboardArtifact artifact) {
117  this.artifact = artifact;
118  }
119 
120  @Override
121  protected List<AccountContainer> doInBackground() throws Exception {
122  List<AccountContainer> dataList = new ArrayList<>();
123 
124  CommunicationsManager commManager = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager();
125  List<Account> accountList = commManager.getAccountsRelatedToArtifact(artifact);
126  for (Account account : accountList) {
127  if (isCancelled()) {
128  return new ArrayList<>();
129  }
130 
131  if (!((DataSource) (artifact.getDataSource())).getDeviceId().equals(account.getTypeSpecificID())) {
132  List<BlackboardArtifact> contactList = ContactCache.getContacts(account);
133  BlackboardArtifact contact = null;
134 
135  if (contactList != null && !contactList.isEmpty()) {
136  contact = contactList.get(0);
137  }
138 
139  if (CentralRepository.isEnabled()) {
140  Collection<PersonaAccount> personAccounts = PersonaAccount.getPersonaAccountsForAccount(account);
141  if (personAccounts != null && !personAccounts.isEmpty()) {
142  for (PersonaAccount personaAccount : PersonaAccount.getPersonaAccountsForAccount(account)) {
143  dataList.add(new AccountContainer(account, personaAccount, contact));
144  }
145  } else {
146  dataList.add(new AccountContainer(account, null, contact));
147  }
148  } else {
149  dataList.add(new AccountContainer(account, null, contact));
150  }
151  }
152  }
153 
154  return dataList;
155  }
156 
157  @Messages({
158  "MessageAccountPanel_no_matches=No matches found.",})
159  @Override
160  protected void done() {
161  try {
162  List<AccountContainer> dataList = get();
163 
164  if (!dataList.isEmpty()) {
165  dataList.forEach(container -> {
166  container.initalizeSwingControls();
167  });
168 
169  GroupLayout layout = new GroupLayout(MessageAccountPanel.this);
170  layout.setHorizontalGroup(
171  layout.createParallelGroup(Alignment.LEADING)
172  .addGroup(layout.createSequentialGroup()
173  .addContainerGap()
174  .addGroup(getMainHorizontalGroup(layout, dataList))
175  .addContainerGap(158, Short.MAX_VALUE)));
176 
177  layout.setVerticalGroup(getMainVerticalGroup(layout, dataList));
178  setLayout(layout);
179  repaint();
180  } else {
181  // No match found, display a message.
182  JPanel messagePanel = new javax.swing.JPanel();
183  JLabel messageLabel = new javax.swing.JLabel();
184 
185  messagePanel.setLayout(new java.awt.BorderLayout());
186 
187  messageLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
188  messageLabel.setText(Bundle.MessageAccountPanel_no_matches());
189  messageLabel.setEnabled(false);
190  messagePanel.add(messageLabel, java.awt.BorderLayout.CENTER);
191 
192  setLayout(new javax.swing.OverlayLayout(MessageAccountPanel.this));
193 
194  add(messagePanel);
195  repaint();
196  }
197  } catch (CancellationException ex) {
198  logger.log(Level.INFO, "MessageAccoutPanel thread cancelled", ex);
199  } catch (InterruptedException | ExecutionException ex) {
200  logger.log(Level.WARNING, "Failed to get account list for MessageAccountPanel", ex);
201  }
202  }
203 
210  private ParallelGroup getMainHorizontalGroup(GroupLayout layout, List<AccountContainer> data) {
211  ParallelGroup group = layout.createParallelGroup(Alignment.LEADING);
212  for (AccountContainer o : data) {
213  group.addComponent(o.getAccountLabel());
214  }
215  group.addGroup(getPersonaHorizontalGroup(layout, data));
216  return group;
217  }
218 
224  private ParallelGroup getMainVerticalGroup(GroupLayout layout, List<AccountContainer> data) {
225  SequentialGroup group = layout.createSequentialGroup();
226  for (AccountContainer o : data) {
227  group.addGap(5)
228  .addComponent(o.getAccountLabel())
229  .addGroup(o.getContactLineVerticalGroup(layout))
230  .addGroup(o.getPersonLineVerticalGroup(layout));
231  }
232 
233  group.addContainerGap(83, Short.MAX_VALUE);
234 
235  return layout.createParallelGroup().addGroup(group);
236 
237  }
238 
245  private ParallelGroup getButtonGroup(GroupLayout layout, List<AccountContainer> data) {
246  ParallelGroup group = layout.createParallelGroup(Alignment.LEADING);
247  for (AccountContainer o : data) {
248  group.addComponent(o.getButton());
249  }
250 
251  return group;
252  }
253 
259  private SequentialGroup getPersonaHorizontalGroup(GroupLayout layout, List<AccountContainer> data) {
260  SequentialGroup group = layout.createSequentialGroup();
261  ParallelGroup pgroup = layout.createParallelGroup(Alignment.LEADING);
262  group.addGap(10);
263  for (AccountContainer o : data) {
264  pgroup.addGroup(o.getPersonaSequentialGroup(layout));
265  pgroup.addGroup(o.getContactSequentialGroup(layout));
266  }
267  group.addGap(10)
268  .addGroup(pgroup)
269  .addPreferredGap(ComponentPlacement.RELATED)
270  .addGroup(getButtonGroup(layout, data));
271 
272  return group;
273  }
274 
275  }
276 
281  private class AccountContainer {
282 
283  private final Account account;
284  private Persona persona = null;
285  private final String contactName;
286 
287  private JTextPane accountLabel;
288  private JLabel personaHeader;
289  private JTextPane personaDisplayName;
290  private JLabel contactHeader;
291  private JTextPane contactDisplayName;
292  private JButton button;
293 
294  private JMenuItem contactCopyMenuItem;
295  private JMenuItem personaCopyMenuItem;
296  private JMenuItem accountCopyMenuItem;
297  JPopupMenu contactPopupMenu = new JPopupMenu();
298  JPopupMenu personaPopupMenu = new JPopupMenu();
299  JPopupMenu accountPopupMenu = new JPopupMenu();
300 
307  AccountContainer(Account account, PersonaAccount personaAccount, BlackboardArtifact contactArtifact) throws TskCoreException {
308  if (contactArtifact != null && contactArtifact.getArtifactTypeID() != BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT.getTypeID()) {
309  throw new IllegalArgumentException("Failed to create AccountContainer object, passed in artifact was not a TSK_CONTACT");
310  }
311 
312  this.account = account;
313  this.persona = personaAccount != null ? personaAccount.getPersona() : null;
314  this.contactName = getNameFromContactArtifact(contactArtifact);
315  }
316 
317  @Messages({
318  "MessageAccountPanel_persona_label=Persona:",
319  "MessageAccountPanel_unknown_label=Unknown",
320  "MessageAccountPanel_button_view_label=View",
321  "MessageAccountPanel_button_create_label=Create",
322  "MessageAccountPanel_contact_label=Contact:",
323  "MessageAccountPanel_copy_label=Copy"
324  })
328  private void initalizeSwingControls() {
329  accountLabel = new JTextPane();
330  accountLabel.setEditable(false);
331  accountLabel.setOpaque(false);
332  personaHeader = new JLabel(Bundle.MessageAccountPanel_persona_label());
333  contactHeader = new JLabel(Bundle.MessageAccountPanel_contact_label());
334  personaDisplayName = new JTextPane();
335  personaDisplayName.setOpaque(false);
336  personaDisplayName.setEditable(false);
337  personaDisplayName.setPreferredSize(new Dimension(100, 26));
338  personaDisplayName.setMaximumSize(new Dimension(100, 26));
339  contactDisplayName = new JTextPane();
340  contactDisplayName.setOpaque(false);
341  contactDisplayName.setEditable(false);
342  contactDisplayName.setPreferredSize(new Dimension(100, 26));
343  button = new JButton();
344  button.addActionListener(new PersonaButtonListener(this));
345 
346  accountLabel.setText(account.getTypeSpecificID());
347  contactDisplayName.setText(contactName);
348  personaDisplayName.setText(persona != null ? persona.getName() : Bundle.MessageAccountPanel_unknown_label());
349 
350  //This is a bit of a hack to size the JTextPane correctly, but it gets the job done.
351  personaDisplayName.setMaximumSize((new JLabel(personaDisplayName.getText()).getMaximumSize()));
352  contactDisplayName.setMaximumSize((new JLabel(contactDisplayName.getText()).getMaximumSize()));
353  accountLabel.setMaximumSize((new JLabel(accountLabel.getText()).getMaximumSize()));
354 
355  button.setText(persona != null ? Bundle.MessageAccountPanel_button_view_label() : Bundle.MessageAccountPanel_button_create_label());
356 
358  }
359 
363  private void initalizePopupMenus() {
364  contactCopyMenuItem = new JMenuItem(Bundle.MessageAccountPanel_copy_label());
365  personaCopyMenuItem = new JMenuItem(Bundle.MessageAccountPanel_copy_label());
366  accountCopyMenuItem = new JMenuItem(Bundle.MessageAccountPanel_copy_label());
367  personaPopupMenu.add(personaCopyMenuItem);
368  contactPopupMenu.add(contactCopyMenuItem);
369  accountPopupMenu.add(accountCopyMenuItem);
370 
371  personaDisplayName.addMouseListener(new MouseAdapter() {
372  @Override
373  public void mouseClicked(MouseEvent evt) {
374  if (SwingUtilities.isRightMouseButton(evt)) {
375  personaPopupMenu.show(personaDisplayName, evt.getX(), evt.getY());
376  }
377  }
378  });
379 
380  personaCopyMenuItem.addActionListener(new ActionListener() {
381  @Override
382  public void actionPerformed(ActionEvent e) {
383  Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(personaDisplayName.getText()), null);
384  }
385  });
386 
387  contactDisplayName.addMouseListener(new MouseAdapter() {
388  @Override
389  public void mouseClicked(MouseEvent evt) {
390  if (SwingUtilities.isRightMouseButton(evt)) {
391  contactPopupMenu.show(contactDisplayName, evt.getX(), evt.getY());
392  }
393  }
394  });
395 
396  contactCopyMenuItem.addActionListener(new ActionListener() {
397  @Override
398  public void actionPerformed(ActionEvent e) {
399  Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(contactDisplayName.getText()), null);
400  }
401  });
402 
403  accountLabel.addMouseListener(new MouseAdapter() {
404  @Override
405  public void mouseClicked(MouseEvent evt) {
406  if (SwingUtilities.isRightMouseButton(evt)) {
407  accountPopupMenu.show(accountLabel, evt.getX(), evt.getY());
408  }
409  }
410  });
411 
412  accountCopyMenuItem.addActionListener(new ActionListener() {
413  @Override
414  public void actionPerformed(ActionEvent e) {
415  Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(accountLabel.getText()), null);
416  }
417  });
418 
419  }
420 
421  private String getNameFromContactArtifact(BlackboardArtifact contactArtifact) throws TskCoreException {
422  if (contactArtifact != null) {
423  BlackboardAttribute attribute = contactArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME));
424  if (attribute != null) {
425  return attribute.getValueString();
426  }
427  }
428 
429  return Bundle.MessageAccountPanel_unknown_label();
430  }
431 
437  private void setPersona(Persona persona) {
438  this.persona = persona;
439 
440  // Make sure this runs in EDT
441  SwingUtilities.invokeLater(new Runnable() {
442  @Override
443  public void run() {
444  personaDisplayName.setText(persona != null ? persona.getName() : Bundle.MessageAccountPanel_unknown_label());
445  button.setText(persona != null ? Bundle.MessageAccountPanel_button_view_label() : Bundle.MessageAccountPanel_button_create_label());
446 
447  //This is a bit of a hack to size the JTextPane correctly, but it gets the job done.
448  personaDisplayName.setMaximumSize((new JLabel(personaDisplayName.getText()).getMaximumSize()));
449  revalidate();
450  repaint();
451  }
452  });
453  }
454 
460  private Account getAccount() {
461  return account;
462  }
463 
469  private Persona getPersona() {
470  return persona;
471  }
472 
478  private JTextPane getAccountLabel() {
479  return accountLabel;
480  }
481 
487  private JButton getButton() {
488  return button;
489  }
490 
498  private SequentialGroup getPersonaSequentialGroup(GroupLayout layout) {
499  SequentialGroup group = layout.createSequentialGroup();
500 
501  group
502  .addComponent(personaHeader)
503  .addPreferredGap(ComponentPlacement.RELATED)
504  .addComponent(personaDisplayName);
505 
506  return group;
507  }
508 
509  private SequentialGroup getContactSequentialGroup(GroupLayout layout) {
510  SequentialGroup group = layout.createSequentialGroup();
511 
512  group
513  .addComponent(contactHeader)
514  .addPreferredGap(ComponentPlacement.RELATED)
515  .addComponent(contactDisplayName);
516 
517  return group;
518  }
519 
527  private ParallelGroup getPersonLineVerticalGroup(GroupLayout layout) {
528  return layout.createParallelGroup(Alignment.CENTER)
529  .addComponent(personaHeader)
530  .addComponent(personaDisplayName)
531  .addComponent(button);
532  }
533 
541  private ParallelGroup getContactLineVerticalGroup(GroupLayout layout) {
542  return layout.createParallelGroup(Alignment.CENTER)
543  .addComponent(contactHeader)
544  .addComponent(contactDisplayName);
545  }
546  }
547 
551  private class PersonaButtonListener implements ActionListener {
552 
554 
560  PersonaButtonListener(AccountContainer accountContainer) {
561  this.accountContainer = accountContainer;
562  }
563 
564  @NbBundle.Messages({
565  "MessageAccountPanel.account.justification=Account found in Message artifact",
566  "# {0} - accountIdentifer",
567  "MessageAccountPanel_id_not_found_in_cr=Unable to find an account with identifier {0} in the Central Repository."
568  })
569  @Override
570  public void actionPerformed(ActionEvent e) {
571  Persona persona = accountContainer.getPersona();
572  if (persona == null) {
573  PersonaDetailsDialog createPersonaDialog = new PersonaDetailsDialog(
574  MessageAccountPanel.this,
576  null,
577  new PersonaDialogCallbackImpl(accountContainer),
578  false);
579 
580  // Pre populate the persona name and accounts if we have them.
581  PersonaDetailsPanel personaPanel = createPersonaDialog.getDetailsPanel();
582 
583  // Set a default name
584  personaPanel.setPersonaName(accountContainer.getAccount().getTypeSpecificID());
585 
586  // Set up each matching account. We don't know what type of account we have, so check all the types to
587  // find any matches.
588  try {
589  boolean showErrorMessage = true;
591  try {
592  // Try to load any matching accounts of this type. Throws an InvalidAccountIDException if the account is the
593  // wrong format (i.e., when we try to load email accounts for a phone number-type string).
594  CentralRepoAccount account = CentralRepository.getInstance().getAccount(type, accountContainer.getAccount().getTypeSpecificID());
595  if (account != null) {
596  personaPanel.addAccount(account, Bundle.MessageAccountPanel_account_justification(), Persona.Confidence.HIGH);
597  showErrorMessage = false;
598  }
599  } catch (InvalidAccountIDException ex2) {
600  // These are expected when the account identifier doesn't match the format of the account type.
601  }
602  }
603  if(showErrorMessage) {
604  createPersonaDialog.setStartupPopupMessage(Bundle.MessageAccountPanel_id_not_found_in_cr(accountContainer.getAccount().getTypeSpecificID()));
605  }
606  } catch (CentralRepoException ex) {
607  logger.log(Level.SEVERE, "Error looking up account types in the central repository", ex);
608  }
609 
610  // display the dialog now
611  createPersonaDialog.display();
612  } else {
613  new PersonaDetailsDialog(MessageAccountPanel.this,
614  PersonaDetailsMode.VIEW, persona, new PersonaDialogCallbackImpl(accountContainer));
615  }
616  }
617 
618  }
619 
624 
626 
627  PersonaDialogCallbackImpl(AccountContainer accountContainer) {
628  this.accountContainer = accountContainer;
629  }
630 
631  @Override
632  public void callback(Persona persona) {
633  accountContainer.setPersona(persona);
634  }
635 
636  }
637 }
boolean addAccount(CentralRepoAccount account, String justification, Persona.Confidence confidence)
CentralRepoAccount getAccount(CentralRepoAccount.CentralRepoAccountType crAccountType, String accountUniqueID)

Copyright © 2012-2021 Basis Technology. Generated on: Tue Jan 19 2021
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.