Autopsy 4.22.1
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 */
19package org.sleuthkit.autopsy.contentviewers.artifactviewers;
20
21import java.awt.Dimension;
22import java.awt.Insets;
23import java.awt.Toolkit;
24import java.awt.datatransfer.StringSelection;
25import java.awt.event.ActionEvent;
26import java.awt.event.ActionListener;
27import java.awt.event.MouseAdapter;
28import java.awt.event.MouseEvent;
29import java.util.ArrayList;
30import java.util.Collection;
31import java.util.List;
32import java.util.concurrent.CancellationException;
33import java.util.concurrent.ExecutionException;
34import java.util.logging.Level;
35import javax.swing.GroupLayout;
36import javax.swing.GroupLayout.Alignment;
37import javax.swing.GroupLayout.ParallelGroup;
38import javax.swing.GroupLayout.SequentialGroup;
39import javax.swing.JButton;
40import javax.swing.JLabel;
41import javax.swing.JMenuItem;
42import javax.swing.JPanel;
43import javax.swing.JPopupMenu;
44import javax.swing.JTextPane;
45import javax.swing.LayoutStyle.ComponentPlacement;
46import javax.swing.SwingUtilities;
47import javax.swing.SwingWorker;
48import javax.swing.border.EmptyBorder;
49import org.openide.util.NbBundle;
50import org.openide.util.NbBundle.Messages;
51import org.sleuthkit.autopsy.casemodule.Case;
52import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoAccount;
53import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException;
54import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository;
55import org.sleuthkit.autopsy.centralrepository.datamodel.Persona;
56import org.sleuthkit.autopsy.centralrepository.datamodel.PersonaAccount;
57import org.sleuthkit.autopsy.centralrepository.persona.PersonaDetailsDialog;
58import org.sleuthkit.autopsy.centralrepository.persona.PersonaDetailsDialogCallback;
59import org.sleuthkit.autopsy.centralrepository.persona.PersonaDetailsMode;
60import org.sleuthkit.autopsy.centralrepository.persona.PersonaDetailsPanel;
61import org.sleuthkit.autopsy.contentviewers.layout.ContentViewerDefaults;
62import org.sleuthkit.autopsy.coreutils.Logger;
63import org.sleuthkit.autopsy.guiutils.ContactCache;
64import org.sleuthkit.datamodel.Account;
65import org.sleuthkit.datamodel.BlackboardArtifact;
66import org.sleuthkit.datamodel.BlackboardAttribute;
67import org.sleuthkit.datamodel.CommunicationsManager;
68import org.sleuthkit.datamodel.InvalidAccountIDException;
69import org.sleuthkit.datamodel.DataSource;
70import org.sleuthkit.datamodel.TskCoreException;
71
76final 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());
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,
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,
625 }
626 }
627
628 }
629
633 private class PersonaDialogCallbackImpl implements PersonaDetailsDialogCallback {
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-2024 Sleuth Kit Labs. Generated on:
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.