Autopsy  4.21.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-2021 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.Insets;
23 import java.awt.Toolkit;
24 import java.awt.datatransfer.StringSelection;
25 import java.awt.event.ActionEvent;
26 import java.awt.event.ActionListener;
27 import java.awt.event.MouseAdapter;
28 import java.awt.event.MouseEvent;
29 import java.util.ArrayList;
30 import java.util.Collection;
31 import java.util.List;
32 import java.util.concurrent.CancellationException;
33 import java.util.concurrent.ExecutionException;
34 import java.util.logging.Level;
35 import javax.swing.GroupLayout;
36 import javax.swing.GroupLayout.Alignment;
37 import javax.swing.GroupLayout.ParallelGroup;
38 import javax.swing.GroupLayout.SequentialGroup;
39 import javax.swing.JButton;
40 import javax.swing.JLabel;
41 import javax.swing.JMenuItem;
42 import javax.swing.JPanel;
43 import javax.swing.JPopupMenu;
44 import javax.swing.JTextPane;
45 import javax.swing.LayoutStyle.ComponentPlacement;
46 import javax.swing.SwingUtilities;
47 import javax.swing.SwingWorker;
48 import javax.swing.border.EmptyBorder;
49 import org.openide.util.NbBundle;
50 import org.openide.util.NbBundle.Messages;
64 import org.sleuthkit.datamodel.Account;
65 import org.sleuthkit.datamodel.BlackboardArtifact;
66 import org.sleuthkit.datamodel.BlackboardAttribute;
67 import org.sleuthkit.datamodel.CommunicationsManager;
68 import org.sleuthkit.datamodel.InvalidAccountIDException;
69 import org.sleuthkit.datamodel.DataSource;
70 import org.sleuthkit.datamodel.TskCoreException;
71 
76 final class MessageAccountPanel extends JPanel {
77 
78  private static final long serialVersionUID = 1L;
79  private final static Logger logger = Logger.getLogger(MessageAccountPanel.class.getName());
80 
81  private AccountFetcher currentFetcher = null;
82 
83 
84 
88  MessageAccountPanel() {
89  this.setBorder(new EmptyBorder(ContentViewerDefaults.getPanelInsets()));
90  }
91 
99  void setArtifact(BlackboardArtifact artifact) {
100  removeAll();
101  setLayout(null);
102  repaint();
103 
104  if (artifact == null) {
105  return;
106  }
107 
108  if (currentFetcher != null && !currentFetcher.isDone()) {
109  currentFetcher.cancel(true);
110  }
111 
112  currentFetcher = new AccountFetcher(artifact);
113  currentFetcher.execute();
114  }
115 
119  class AccountFetcher extends SwingWorker<List<AccountContainer>, Void> {
120 
121  private final BlackboardArtifact artifact;
122 
128  AccountFetcher(BlackboardArtifact artifact) {
129  this.artifact = artifact;
130  }
131 
132  @Override
133  protected List<AccountContainer> doInBackground() throws Exception {
134  List<AccountContainer> dataList = new ArrayList<>();
135 
136  CommunicationsManager commManager = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager();
137  List<Account> accountList = commManager.getAccountsRelatedToArtifact(artifact);
138  for (Account account : accountList) {
139  if (isCancelled()) {
140  return new ArrayList<>();
141  }
142 
143  if (!((DataSource) (artifact.getDataSource())).getDeviceId().equals(account.getTypeSpecificID())) {
144  List<BlackboardArtifact> contactList = ContactCache.getContacts(account);
145  BlackboardArtifact contact = null;
146 
147  if (contactList != null && !contactList.isEmpty()) {
148  contact = contactList.get(0);
149  }
150 
151  if (CentralRepository.isEnabled()) {
152  Collection<PersonaAccount> personAccounts = PersonaAccount.getPersonaAccountsForAccount(account);
153  if (personAccounts != null && !personAccounts.isEmpty()) {
154  for (PersonaAccount personaAccount : PersonaAccount.getPersonaAccountsForAccount(account)) {
155  dataList.add(new AccountContainer(account, personaAccount, contact));
156  }
157  } else {
158  dataList.add(new AccountContainer(account, null, contact));
159  }
160  } else {
161  dataList.add(new AccountContainer(account, null, contact));
162  }
163  }
164  }
165 
166  return dataList;
167  }
168 
169  @Messages({
170  "MessageAccountPanel_no_matches=No matches found.",})
171  @Override
172  protected void done() {
173  try {
174  List<AccountContainer> dataList = get();
175 
176  if (!dataList.isEmpty()) {
177  dataList.forEach(container -> {
178  container.initalizeSwingControls();
179  });
180 
181  GroupLayout layout = new GroupLayout(MessageAccountPanel.this);
182  layout.setHorizontalGroup(
183  layout.createParallelGroup(Alignment.LEADING)
184  .addGroup(layout.createSequentialGroup()
185  .addGroup(getMainHorizontalGroup(layout, dataList))));
186 
187  layout.setVerticalGroup(getMainVerticalGroup(layout, dataList));
188  setLayout(layout);
189  repaint();
190  } else {
191  // No match found, display a message.
192  JPanel messagePanel = new javax.swing.JPanel();
193  JLabel messageLabel = new javax.swing.JLabel();
194 
195  messagePanel.setLayout(new java.awt.BorderLayout());
196 
197  messageLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
198  messageLabel.setText(Bundle.MessageAccountPanel_no_matches());
199  messageLabel.setFont(ContentViewerDefaults.getMessageFont());
200  messageLabel.setEnabled(false);
201  messagePanel.add(messageLabel, java.awt.BorderLayout.CENTER);
202 
203  setLayout(new javax.swing.OverlayLayout(MessageAccountPanel.this));
204 
205  add(messagePanel);
206  repaint();
207  }
208  } catch (CancellationException ex) {
209  logger.log(Level.INFO, "MessageAccoutPanel thread cancelled", ex);
210  } catch (InterruptedException | ExecutionException ex) {
211  logger.log(Level.WARNING, "Failed to get account list for MessageAccountPanel", ex);
212  }
213  }
214 
221  private ParallelGroup getMainHorizontalGroup(GroupLayout layout, List<AccountContainer> data) {
222  ParallelGroup group = layout.createParallelGroup(Alignment.LEADING);
223  for (AccountContainer o : data) {
224  group.addComponent(o.getAccountLabel());
225  }
226  group.addGroup(getPersonaHorizontalGroup(layout, data));
227  return group;
228  }
229 
235  private ParallelGroup getMainVerticalGroup(GroupLayout layout, List<AccountContainer> data) {
236  SequentialGroup group = layout.createSequentialGroup();
237  for (AccountContainer o : data) {
238  group.addComponent(o.getAccountLabel())
239  .addGroup(o.getContactLineVerticalGroup(layout))
240  .addGroup(o.getPersonLineVerticalGroup(layout));
241  group.addGap(ContentViewerDefaults.getSectionSpacing());
242  }
243 
244  return layout.createParallelGroup().addGroup(group);
245 
246  }
247 
254  private ParallelGroup getButtonGroup(GroupLayout layout, List<AccountContainer> data) {
255  ParallelGroup group = layout.createParallelGroup(Alignment.LEADING);
256  for (AccountContainer o : data) {
257  group.addComponent(o.getButton());
258  }
259 
260  return group;
261  }
262 
268  private SequentialGroup getPersonaHorizontalGroup(GroupLayout layout, List<AccountContainer> data) {
269  SequentialGroup group = layout.createSequentialGroup();
270  ParallelGroup pgroup = layout.createParallelGroup(Alignment.LEADING);
271  for (AccountContainer o : data) {
272  pgroup.addGroup(o.getPersonaSequentialGroup(layout));
273  pgroup.addGroup(o.getContactSequentialGroup(layout));
274  }
275  group.addGap(ContentViewerDefaults.getSectionIndent())
276  .addGroup(pgroup)
277  .addPreferredGap(ComponentPlacement.RELATED)
278  .addGroup(getButtonGroup(layout, data));
279 
280  return group;
281  }
282 
283  }
284 
289  private class AccountContainer {
290 
291  private final Account account;
292  private Persona persona = null;
293  private final String contactName;
294 
295  private JTextPane accountLabel;
296  private JLabel personaHeader;
297  private JTextPane personaDisplayName;
298  private JLabel contactHeader;
299  private JTextPane contactDisplayName;
300  private JButton button;
301 
302  private JMenuItem contactCopyMenuItem;
303  private JMenuItem personaCopyMenuItem;
304  private JMenuItem accountCopyMenuItem;
305  JPopupMenu contactPopupMenu = new JPopupMenu();
306  JPopupMenu personaPopupMenu = new JPopupMenu();
307  JPopupMenu accountPopupMenu = new JPopupMenu();
308 
315  AccountContainer(Account account, PersonaAccount personaAccount, BlackboardArtifact contactArtifact) throws TskCoreException {
316  if (contactArtifact != null && contactArtifact.getArtifactTypeID() != BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT.getTypeID()) {
317  throw new IllegalArgumentException("Failed to create AccountContainer object, passed in artifact was not a TSK_CONTACT");
318  }
319 
320  this.account = account;
321  this.persona = personaAccount != null ? personaAccount.getPersona() : null;
322  this.contactName = getNameFromContactArtifact(contactArtifact);
323  }
324 
325  @Messages({
326  "MessageAccountPanel_persona_label=Persona:",
327  "MessageAccountPanel_unknown_label=Unknown",
328  "MessageAccountPanel_button_view_label=View",
329  "MessageAccountPanel_button_create_label=Create",
330  "MessageAccountPanel_contact_label=Contact:",
331  "MessageAccountPanel_copy_label=Copy"
332  })
336  private void initalizeSwingControls() {
337  accountLabel = new JTextPane();
338  accountLabel.setEditable(false);
339  accountLabel.setOpaque(false);
340  personaHeader = new JLabel(Bundle.MessageAccountPanel_persona_label());
341  contactHeader = new JLabel(Bundle.MessageAccountPanel_contact_label());
342  personaDisplayName = new JTextPane();
343  personaDisplayName.setOpaque(false);
344  personaDisplayName.setEditable(false);
345  personaDisplayName.setPreferredSize(new Dimension(100, 26));
346  personaDisplayName.setMaximumSize(new Dimension(100, 26));
347  contactDisplayName = new JTextPane();
348  contactDisplayName.setOpaque(false);
349  contactDisplayName.setEditable(false);
350  contactDisplayName.setPreferredSize(new Dimension(100, 26));
351  button = new JButton();
352  button.addActionListener(new PersonaButtonListener(this));
353 
354  accountLabel.setMargin(new Insets(0, 0, 0, 0));
355  accountLabel.setText(account.getTypeSpecificID());
356  accountLabel.setFont(ContentViewerDefaults.getHeaderFont());
357  contactDisplayName.setText(contactName);
358  personaDisplayName.setText(persona != null ? persona.getName() : Bundle.MessageAccountPanel_unknown_label());
359 
360  //This is a bit of a hack to size the JTextPane correctly, but it gets the job done.
361  personaDisplayName.setMaximumSize((new JLabel(personaDisplayName.getText()).getMaximumSize()));
362  contactDisplayName.setMaximumSize((new JLabel(contactDisplayName.getText()).getMaximumSize()));
363  accountLabel.setMaximumSize((new JLabel(accountLabel.getText()).getMaximumSize()));
364 
365  button.setText(persona != null ? Bundle.MessageAccountPanel_button_view_label() : Bundle.MessageAccountPanel_button_create_label());
366 
368  }
369 
373  private void initalizePopupMenus() {
374  contactCopyMenuItem = new JMenuItem(Bundle.MessageAccountPanel_copy_label());
375  personaCopyMenuItem = new JMenuItem(Bundle.MessageAccountPanel_copy_label());
376  accountCopyMenuItem = new JMenuItem(Bundle.MessageAccountPanel_copy_label());
377  personaPopupMenu.add(personaCopyMenuItem);
378  contactPopupMenu.add(contactCopyMenuItem);
379  accountPopupMenu.add(accountCopyMenuItem);
380 
381  personaDisplayName.addMouseListener(new MouseAdapter() {
382  @Override
383  public void mouseClicked(MouseEvent evt) {
384  if (SwingUtilities.isRightMouseButton(evt)) {
385  personaPopupMenu.show(personaDisplayName, evt.getX(), evt.getY());
386  }
387  }
388  });
389 
390  personaCopyMenuItem.addActionListener(new ActionListener() {
391  @Override
392  public void actionPerformed(ActionEvent e) {
393  Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(personaDisplayName.getText()), null);
394  }
395  });
396 
397  contactDisplayName.addMouseListener(new MouseAdapter() {
398  @Override
399  public void mouseClicked(MouseEvent evt) {
400  if (SwingUtilities.isRightMouseButton(evt)) {
401  contactPopupMenu.show(contactDisplayName, evt.getX(), evt.getY());
402  }
403  }
404  });
405 
406  contactCopyMenuItem.addActionListener(new ActionListener() {
407  @Override
408  public void actionPerformed(ActionEvent e) {
409  Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(contactDisplayName.getText()), null);
410  }
411  });
412 
413  accountLabel.addMouseListener(new MouseAdapter() {
414  @Override
415  public void mouseClicked(MouseEvent evt) {
416  if (SwingUtilities.isRightMouseButton(evt)) {
417  accountPopupMenu.show(accountLabel, evt.getX(), evt.getY());
418  }
419  }
420  });
421 
422  accountCopyMenuItem.addActionListener(new ActionListener() {
423  @Override
424  public void actionPerformed(ActionEvent e) {
425  Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(accountLabel.getText()), null);
426  }
427  });
428 
429  }
430 
431  private String getNameFromContactArtifact(BlackboardArtifact contactArtifact) throws TskCoreException {
432  if (contactArtifact != null) {
433  BlackboardAttribute attribute = contactArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME));
434  if (attribute != null) {
435  return attribute.getValueString();
436  }
437  }
438 
439  return Bundle.MessageAccountPanel_unknown_label();
440  }
441 
447  private void setPersona(Persona persona) {
448  this.persona = persona;
449 
450  // Make sure this runs in EDT
451  SwingUtilities.invokeLater(new Runnable() {
452  @Override
453  public void run() {
454  personaDisplayName.setText(persona != null ? persona.getName() : Bundle.MessageAccountPanel_unknown_label());
455  button.setText(persona != null ? Bundle.MessageAccountPanel_button_view_label() : Bundle.MessageAccountPanel_button_create_label());
456 
457  //This is a bit of a hack to size the JTextPane correctly, but it gets the job done.
458  personaDisplayName.setMaximumSize((new JLabel(personaDisplayName.getText()).getMaximumSize()));
459  revalidate();
460  repaint();
461  }
462  });
463  }
464 
470  private Account getAccount() {
471  return account;
472  }
473 
479  private Persona getPersona() {
480  return persona;
481  }
482 
488  private JTextPane getAccountLabel() {
489  return accountLabel;
490  }
491 
497  private JButton getButton() {
498  return button;
499  }
500 
508  private SequentialGroup getPersonaSequentialGroup(GroupLayout layout) {
509  SequentialGroup group = layout.createSequentialGroup();
510 
511  group
512  .addComponent(personaHeader)
513  .addPreferredGap(ComponentPlacement.RELATED)
514  .addComponent(personaDisplayName);
515 
516  return group;
517  }
518 
519  private SequentialGroup getContactSequentialGroup(GroupLayout layout) {
520  SequentialGroup group = layout.createSequentialGroup();
521 
522  group
523  .addComponent(contactHeader)
524  .addPreferredGap(ComponentPlacement.RELATED)
525  .addComponent(contactDisplayName);
526 
527  return group;
528  }
529 
537  private ParallelGroup getPersonLineVerticalGroup(GroupLayout layout) {
538  return layout.createParallelGroup(Alignment.CENTER)
539  .addComponent(personaHeader)
540  .addComponent(personaDisplayName)
541  .addComponent(button);
542  }
543 
551  private ParallelGroup getContactLineVerticalGroup(GroupLayout layout) {
552  return layout.createParallelGroup(Alignment.CENTER)
553  .addComponent(contactHeader)
554  .addComponent(contactDisplayName);
555  }
556  }
557 
561  private class PersonaButtonListener implements ActionListener {
562 
564 
570  PersonaButtonListener(AccountContainer accountContainer) {
571  this.accountContainer = accountContainer;
572  }
573 
574  @NbBundle.Messages({
575  "MessageAccountPanel.account.justification=Account found in Message artifact",
576  "# {0} - accountIdentifer",
577  "MessageAccountPanel_id_not_found_in_cr=Unable to find an account with identifier {0} in the Central Repository."
578  })
579  @Override
580  public void actionPerformed(ActionEvent e) {
581  Persona persona = accountContainer.getPersona();
582  if (persona == null) {
583  PersonaDetailsDialog createPersonaDialog = new PersonaDetailsDialog(
584  MessageAccountPanel.this,
586  null,
587  new PersonaDialogCallbackImpl(accountContainer),
588  false);
589 
590  // Pre populate the persona name and accounts if we have them.
591  PersonaDetailsPanel personaPanel = createPersonaDialog.getDetailsPanel();
592 
593  // Set a default name
594  personaPanel.setPersonaName(accountContainer.getAccount().getTypeSpecificID());
595 
596  // Set up each matching account. We don't know what type of account we have, so check all the types to
597  // find any matches.
598  try {
599  boolean showErrorMessage = true;
601  try {
602  // Try to load any matching accounts of this type. Throws an InvalidAccountIDException if the account is the
603  // wrong format (i.e., when we try to load email accounts for a phone number-type string).
604  CentralRepoAccount account = CentralRepository.getInstance().getAccount(type, accountContainer.getAccount().getTypeSpecificID());
605  if (account != null) {
606  personaPanel.addAccount(account, Bundle.MessageAccountPanel_account_justification(), Persona.Confidence.HIGH);
607  showErrorMessage = false;
608  }
609  } catch (InvalidAccountIDException ex2) {
610  // These are expected when the account identifier doesn't match the format of the account type.
611  }
612  }
613  if(showErrorMessage) {
614  createPersonaDialog.setStartupPopupMessage(Bundle.MessageAccountPanel_id_not_found_in_cr(accountContainer.getAccount().getTypeSpecificID()));
615  }
616  } catch (CentralRepoException ex) {
617  logger.log(Level.SEVERE, "Error looking up account types in the central repository", ex);
618  }
619 
620  // display the dialog now
621  createPersonaDialog.display();
622  } else {
623  new PersonaDetailsDialog(MessageAccountPanel.this,
624  PersonaDetailsMode.VIEW, persona, new PersonaDialogCallbackImpl(accountContainer));
625  }
626  }
627 
628  }
629 
634 
636 
637  PersonaDialogCallbackImpl(AccountContainer accountContainer) {
638  this.accountContainer = accountContainer;
639  }
640 
641  @Override
642  public void callback(Persona persona) {
643  accountContainer.setPersona(persona);
644  }
645 
646  }
647 }
boolean addAccount(CentralRepoAccount account, String justification, Persona.Confidence confidence)
CentralRepoAccount getAccount(CentralRepoAccount.CentralRepoAccountType crAccountType, String accountUniqueID)

Copyright © 2012-2022 Basis Technology. Generated on: Tue Feb 6 2024
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.