Autopsy 4.22.1
Graphical digital forensics platform for The Sleuth Kit and other tools.
ContactArtifactViewer.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.Component;
22import java.awt.GridBagConstraints;
23import java.awt.GridBagLayout;
24import java.awt.Insets;
25import java.awt.event.ActionListener;
26import java.awt.image.BufferedImage;
27import java.io.File;
28import java.io.IOException;
29import java.util.ArrayList;
30import java.util.Collection;
31import java.util.Collections;
32import java.util.HashMap;
33import java.util.List;
34import java.util.Map;
35import java.util.Optional;
36import java.util.concurrent.CancellationException;
37import java.util.concurrent.ExecutionException;
38import java.util.logging.Level;
39import java.util.stream.Collectors;
40import javax.imageio.ImageIO;
41import javax.swing.ImageIcon;
42import javax.swing.JButton;
43import javax.swing.JLabel;
44import javax.swing.JScrollPane;
45import javax.swing.SwingWorker;
46import javax.swing.border.EmptyBorder;
47import org.apache.commons.lang.StringUtils;
48import org.openide.util.NbBundle;
49import org.openide.util.lookup.ServiceProvider;
50import org.sleuthkit.autopsy.casemodule.Case;
51import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
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.datamodel.AbstractFile;
64import org.sleuthkit.datamodel.Account;
65import org.sleuthkit.datamodel.BlackboardArtifact;
66import org.sleuthkit.datamodel.BlackboardAttribute;
67import org.sleuthkit.datamodel.CommunicationsManager;
68import org.sleuthkit.datamodel.Content;
69import org.sleuthkit.datamodel.DataSource;
70import org.sleuthkit.datamodel.InvalidAccountIDException;
71import org.sleuthkit.datamodel.TskCoreException;
72
76@ServiceProvider(service = ArtifactContentViewer.class)
77public class ContactArtifactViewer extends javax.swing.JPanel implements ArtifactContentViewer {
78
79 private final static Logger logger = Logger.getLogger(ContactArtifactViewer.class.getName());
80 private static final long serialVersionUID = 1L;
81
82 private GridBagLayout m_gridBagLayout = new GridBagLayout();
83 private GridBagConstraints m_constraints = new GridBagConstraints();
84
86
87 private BlackboardArtifact contactArtifact;
88 private String contactName;
89 private String datasourceName;
90 private String hostName;
91
92 private List<BlackboardAttribute> phoneNumList = new ArrayList<>();
93 private List<BlackboardAttribute> emailList = new ArrayList<>();
94 private List<BlackboardAttribute> nameList = new ArrayList<>();
95 private List<BlackboardAttribute> otherList = new ArrayList<>();
96 private List<BlackboardAttribute> accountAttributesList = new ArrayList<>();
97
98 private final static String DEFAULT_IMAGE_PATH = "/org/sleuthkit/autopsy/images/defaultContact.png";
99 private final ImageIcon defaultImage;
100
101 // A list of unique accounts matching the attributes of the contact artifact.
102 private final List<CentralRepoAccount> contactUniqueAccountsList = new ArrayList<>();
103
104 // A list of all unique personas and their account, found by searching on the
105 // account identifier attributes of the Contact artifact.
106 private final Map<Persona, ArrayList<CentralRepoAccount>> contactUniquePersonasMap = new HashMap<>();
107
109
115 this.setBorder(new EmptyBorder(ContentViewerDefaults.getPanelInsets()));
116 defaultImage = new ImageIcon(ContactArtifactViewer.class.getResource(DEFAULT_IMAGE_PATH));
117 }
118
124 @SuppressWarnings("unchecked")
125 // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
126 private void initComponents() {
127
128 setToolTipText(""); // NOI18N
129 setLayout(new java.awt.GridBagLayout());
130 }// </editor-fold>//GEN-END:initComponents
131
132 @Override
133 public void setArtifact(BlackboardArtifact artifact) {
134 // Reset the panel.
136
137 if (artifact != null) {
138 try {
139 extractArtifactData(artifact);
140 } catch (NoCurrentCaseException | TskCoreException ex) {
141 logger.log(Level.SEVERE, String.format("Error getting attributes for artifact (artifact_id=%d, obj_id=%d)", artifact.getArtifactID(), artifact.getObjectID()), ex);
142 return;
143 }
144 updateView();
145 }
146 this.setLayout(this.m_gridBagLayout);
147 this.revalidate();
148 this.repaint();
149 }
150
151 @Override
152 public Component getComponent() {
153 // Slap a vertical scrollbar on the panel.
154 return new JScrollPane(this, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
155 }
156
157 @Override
158 public boolean isSupported(BlackboardArtifact artifact) {
159 return (artifact != null)
160 && (artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT.getTypeID());
161 }
162
170 private void extractArtifactData(BlackboardArtifact artifact) throws NoCurrentCaseException, TskCoreException {
171
172 this.contactArtifact = artifact;
173
174 phoneNumList = new ArrayList<>();
175 emailList = new ArrayList<>();
176 nameList = new ArrayList<>();
177 otherList = new ArrayList<>();
178 accountAttributesList = new ArrayList<>();
179
180 // Get all the attributes and group them by the section panels they go in
181 for (BlackboardAttribute bba : contactArtifact.getAttributes()) {
182 if (bba.getAttributeType().getTypeName().startsWith("TSK_PHONE")) {
183 phoneNumList.add(bba);
184 accountAttributesList.add(bba);
185 } else if (bba.getAttributeType().getTypeName().startsWith("TSK_EMAIL")) {
186 emailList.add(bba);
187 accountAttributesList.add(bba);
188 } else if (bba.getAttributeType().getTypeName().startsWith("TSK_NAME")) {
189 nameList.add(bba);
190 } else {
191 otherList.add(bba);
192 if (bba.getAttributeType().getTypeName().equalsIgnoreCase("TSK_ID")) {
193 accountAttributesList.add(bba);
194 }
195 }
196 }
197
198 datasourceName = contactArtifact.getDataSource().getName();
199
200 hostName = Optional.ofNullable(Case.getCurrentCaseThrows().getSleuthkitCase().getHostManager().getHostByDataSource((DataSource) contactArtifact.getDataSource()))
201 .map(h -> h.getName())
202 .orElse(null);
203 }
204
208 private void updateView() {
209
210 // Update contact name, image, phone numbers
212
213 // update artifact source panel
214 updateSource();
215
216 // show a empty Personas panel and kick off a serch for personas
218
219 }
220
224 @NbBundle.Messages({
225 "ContactArtifactViewer_phones_header=Phone",
226 "ContactArtifactViewer_emails_header=Email",
227 "ContactArtifactViewer_others_header=Other",})
228 private void updateContactDetails() {
229
230 // update image and name.
233
234 // update contact attributes sections
235 updateContactMethodSection(phoneNumList, Bundle.ContactArtifactViewer_phones_header(), m_gridBagLayout, m_constraints);
236 updateContactMethodSection(emailList, Bundle.ContactArtifactViewer_emails_header(), m_gridBagLayout, m_constraints);
237 updateContactMethodSection(otherList, Bundle.ContactArtifactViewer_others_header(), m_gridBagLayout, m_constraints);
238 }
239
247 @NbBundle.Messages({
248 "ContactArtifactViewer.contactImage.text=",})
249 private void updateContactImage(GridBagLayout contactPanelLayout, GridBagConstraints contactPanelConstraints) {
250 // place the image on the top right corner
251 Insets savedInsets = contactPanelConstraints.insets;
252 contactPanelConstraints.gridy = 0;
253 contactPanelConstraints.gridx = 0;
254 contactPanelConstraints.insets = new Insets(0, 0, ContentViewerDefaults.getLineSpacing(), 0);
255 int prevGridWidth = contactPanelConstraints.gridwidth;
256 contactPanelConstraints.gridwidth = 3;
257 contactPanelConstraints.anchor = GridBagConstraints.LINE_START;
258
259 javax.swing.JLabel contactImage = new javax.swing.JLabel();
260 contactImage.setIcon(getImageFromArtifact(contactArtifact));
261 contactImage.setText(Bundle.ContactArtifactViewer_contactImage_text());
262
263 // add image to top left corner of the page.
264 CommunicationArtifactViewerHelper.addComponent(this, contactPanelLayout, contactPanelConstraints, contactImage);
265 CommunicationArtifactViewerHelper.addLineEndGlue(this, contactPanelLayout, contactPanelConstraints);
266 contactPanelConstraints.gridy++;
267
268 contactPanelConstraints.gridwidth = prevGridWidth;
269 contactPanelConstraints.insets = savedInsets;
270 }
271
279 @NbBundle.Messages({
280 "ContactArtifactViewer_contactname_unknown=Unknown",})
281 private void updateContactName(GridBagLayout contactPanelLayout, GridBagConstraints contactPanelConstraints) {
282
283 boolean foundName = false;
284 for (BlackboardAttribute bba : this.nameList) {
285 if (StringUtils.isEmpty(bba.getValueString()) == false) {
286 contactName = bba.getDisplayString();
287
288 CommunicationArtifactViewerHelper.addHeader(this, contactPanelLayout, contactPanelConstraints, 0, contactName);
289 foundName = true;
290 break;
291 }
292 }
293 if (foundName == false) {
294 CommunicationArtifactViewerHelper.addHeader(this, contactPanelLayout, contactPanelConstraints, ContentViewerDefaults.getSectionSpacing(), Bundle.ContactArtifactViewer_contactname_unknown());
295 }
296 }
297
308 private void updateContactMethodSection(List<BlackboardAttribute> sectionAttributesList, String sectionHeader, GridBagLayout contactPanelLayout, GridBagConstraints contactPanelConstraints) {
309
310 // If there are no attributes for this section, do nothing
311 if (sectionAttributesList.isEmpty()) {
312 return;
313 }
314
315 CommunicationArtifactViewerHelper.addHeader(this, contactPanelLayout, contactPanelConstraints, ContentViewerDefaults.getSectionSpacing(), sectionHeader);
316 for (BlackboardAttribute bba : sectionAttributesList) {
317 CommunicationArtifactViewerHelper.addKey(this, contactPanelLayout, contactPanelConstraints, bba.getAttributeType().getDisplayName());
318 CommunicationArtifactViewerHelper.addValue(this, contactPanelLayout, contactPanelConstraints, bba.getDisplayString());
319 }
320 }
321
325 @NbBundle.Messages({
326 "ContactArtifactViewer_heading_Source=Source",
327 "ContactArtifactViewer_label_datasource=Data Source",
328 "ContactArtifactViewer_label_host=Host",})
329 private void updateSource() {
330 CommunicationArtifactViewerHelper.addHeader(this, this.m_gridBagLayout, m_constraints, ContentViewerDefaults.getSectionSpacing(), Bundle.ContactArtifactViewer_heading_Source());
331 CommunicationArtifactViewerHelper.addKey(this, m_gridBagLayout, m_constraints, Bundle.ContactArtifactViewer_label_host());
332 CommunicationArtifactViewerHelper.addValue(this, m_gridBagLayout, m_constraints, StringUtils.defaultString(hostName));
333 CommunicationArtifactViewerHelper.addKey(this, m_gridBagLayout, m_constraints, Bundle.ContactArtifactViewer_label_datasource());
334 CommunicationArtifactViewerHelper.addValue(this, m_gridBagLayout, m_constraints, datasourceName);
335 }
336
342 @NbBundle.Messages({
343 "ContactArtifactViewer_persona_header=Persona",
344 "ContactArtifactViewer_persona_searching=Searching...",
345 "ContactArtifactViewer_cr_disabled_message=Enable Central Repository to view, create and edit personas.",
346 "ContactArtifactViewer_persona_unknown=Unknown"
347 })
348 private void initiatePersonasSearch() {
349
350 // add a section header
351 JLabel personaHeader = CommunicationArtifactViewerHelper.addHeader(this, m_gridBagLayout, m_constraints, ContentViewerDefaults.getSectionSpacing(), Bundle.ContactArtifactViewer_persona_header());
352
353 m_constraints.gridy++;
354
355 // add a status label
356 String personaStatusLabelText = CentralRepository.isEnabled()
357 ? Bundle.ContactArtifactViewer_persona_searching()
358 : Bundle.ContactArtifactViewer_persona_unknown();
359
360 this.personaSearchStatusLabel = new javax.swing.JLabel();
361 personaSearchStatusLabel.setText(personaStatusLabelText);
363
364 m_constraints.gridx = 0;
365 m_constraints.anchor = GridBagConstraints.LINE_START;
366
367 CommunicationArtifactViewerHelper.addComponent(this, m_gridBagLayout, m_constraints, personaSearchStatusLabel);
368
370 // Kick off a background task to serach for personas for the contact
372 personaSearchTask.execute();
373 } else {
374 personaHeader.setEnabled(false);
375 personaSearchStatusLabel.setEnabled(false);
376
377 Insets messageInsets = new Insets(ContentViewerDefaults.getSectionSpacing(), 0, ContentViewerDefaults.getLineSpacing(), 0);
378 CommunicationArtifactViewerHelper.addMessageRow(this, m_gridBagLayout, messageInsets, m_constraints, Bundle.ContactArtifactViewer_cr_disabled_message());
379 m_constraints.gridy++;
380
381 CommunicationArtifactViewerHelper.addPageEndGlue(this, m_gridBagLayout, this.m_constraints);
382 }
383
384 }
385
389 private void updatePersonas() {
390
391 // Remove the "Searching....." label
392 this.remove(personaSearchStatusLabel);
393
394 m_constraints.gridx = 0;
395 if (contactUniquePersonasMap.isEmpty()) {
396 // No persona found - show a button to create one.
397 showPersona(null, 0, Collections.emptyList(), this.m_gridBagLayout, this.m_constraints);
398 } else {
399 int matchCounter = 0;
400 for (Map.Entry<Persona, ArrayList<CentralRepoAccount>> entry : contactUniquePersonasMap.entrySet()) {
401 List<CentralRepoAccount> missingAccounts = new ArrayList<>();
402 ArrayList<CentralRepoAccount> personaAccounts = entry.getValue();
403 matchCounter++;
404
405 // create a list of accounts missing from this persona
407 if (personaAccounts.contains(account) == false) {
408 missingAccounts.add(account);
409 }
410 }
411
412 showPersona(entry.getKey(), matchCounter, missingAccounts, m_gridBagLayout, m_constraints);
413 m_constraints.gridy += 2;
414 }
415 }
416
417 // add veritcal glue at the end
418 CommunicationArtifactViewerHelper.addPageEndGlue(this, m_gridBagLayout, this.m_constraints);
419
420 // redraw the panel
421 this.setLayout(this.m_gridBagLayout);
422 this.revalidate();
423 this.repaint();
424 }
425
438 @NbBundle.Messages({
439 "ContactArtifactViewer_persona_label=Persona ",
440 "ContactArtifactViewer_persona_no_match=No matches found",
441 "ContactArtifactViewer_persona_button_view=View",
442 "ContactArtifactViewer_persona_button_new=Create",
443 "ContactArtifactViewer_persona_match_num=Match ",
444 "ContactArtifactViewer_missing_account_label=Missing contact account",
445 "ContactArtifactViewer_found_all_accounts_label=All accounts found."
446 })
447 private void showPersona(Persona persona, int matchNumber, List<CentralRepoAccount> missingAccountsList, GridBagLayout gridBagLayout, GridBagConstraints constraints) {
448
449 // save the original insets
450 Insets savedInsets = constraints.insets;
451
452 // Add a Match X label in col 0.
453 constraints.gridx = 0;
454 javax.swing.JLabel matchNumberLabel = CommunicationArtifactViewerHelper.addKey(this, gridBagLayout, constraints, String.format("%s %d", Bundle.ContactArtifactViewer_persona_match_num(), matchNumber).trim());
455
456 javax.swing.JLabel personaNameLabel = new javax.swing.JLabel();
457 javax.swing.JButton personaButton = new javax.swing.JButton();
458
459 String personaName;
460 String personaButtonText;
461 ActionListener personaButtonListener;
462 if (persona != null) {
463 personaName = persona.getName();
464 personaButtonText = Bundle.ContactArtifactViewer_persona_button_view();
465 personaButtonListener = new ViewPersonaButtonListener(this, persona);
466 } else {
467 matchNumberLabel.setVisible(false);
468 personaName = Bundle.ContactArtifactViewer_persona_no_match();
469 personaButtonText = Bundle.ContactArtifactViewer_persona_button_new();
470 personaButtonListener = new CreatePersonaButtonListener(this, new PersonaUIComponents(personaNameLabel, personaButton));
471 }
472
473 //constraints.gridwidth = 1; // TBD: this may not be needed if we use single panel
474 constraints.gridx++;
475 constraints.insets = new Insets(0, ContentViewerDefaults.getColumnSpacing(), ContentViewerDefaults.getLineSpacing(), 0);
476 constraints.anchor = GridBagConstraints.LINE_START;
477 personaNameLabel.setText(personaName);
478 gridBagLayout.setConstraints(personaNameLabel, constraints);
479 CommunicationArtifactViewerHelper.addComponent(this, gridBagLayout, constraints, personaNameLabel);
480 //personasPanel.add(personaNameLabel);
481
482 // Add a Persona action button
483 constraints.gridx++;
484 //constraints.gridwidth = 1;
485 personaButton.setText(personaButtonText);
486 personaButton.addActionListener(personaButtonListener);
487
488 // Shirnk the button height.
489 personaButton.setMargin(new Insets(0, 5, 0, 5));
490 constraints.insets = new Insets(0, ContentViewerDefaults.getColumnSpacing(), ContentViewerDefaults.getLineSpacing(), 0);
491 constraints.anchor = GridBagConstraints.LINE_START;
492 gridBagLayout.setConstraints(personaButton, constraints);
493 CommunicationArtifactViewerHelper.addComponent(this, gridBagLayout, constraints, personaButton);
494 CommunicationArtifactViewerHelper.addLineEndGlue(this, gridBagLayout, constraints);
495
496 constraints.insets = savedInsets;
497
498 // if we have a persona, indicate if any of the contact's accounts are missing from it.
499 if (persona != null) {
500 if (missingAccountsList.isEmpty()) {
501 constraints.gridy++;
502 constraints.gridx = 1;
503 //constraints.insets = labelInsets;
504
505 javax.swing.JLabel accountsStatus = new javax.swing.JLabel(Bundle.ContactArtifactViewer_found_all_accounts_label());
506 constraints.insets = new Insets(0, ContentViewerDefaults.getColumnSpacing(), ContentViewerDefaults.getLineSpacing(), 0);
507 constraints.anchor = GridBagConstraints.LINE_START;
508 CommunicationArtifactViewerHelper.addComponent(this, gridBagLayout, constraints, accountsStatus);
509 constraints.insets = savedInsets;
510
511 CommunicationArtifactViewerHelper.addLineEndGlue(this, gridBagLayout, constraints);
512 } else {
513 // show missing accounts.
514 for (CentralRepoAccount missingAccount : missingAccountsList) {
515 //constraints.weightx = 0;
516 constraints.gridx = 0;
517 constraints.gridy++;
518
519 // this needs an extra indent
520 CommunicationArtifactViewerHelper.addKeyAtCol(this, gridBagLayout, constraints, Bundle.ContactArtifactViewer_missing_account_label(), 1);
521 constraints.insets = savedInsets;
522
523 CommunicationArtifactViewerHelper.addValueAtCol(this, gridBagLayout, constraints, missingAccount.getIdentifier(), 2);
524 }
525 }
526 }
527
528 // restore insets
529 constraints.insets = savedInsets;
530 }
531
535 private void resetComponent() {
536
537 contactArtifact = null;
538 contactName = null;
539 datasourceName = null;
540
543
544 phoneNumList.clear();
545 emailList.clear();
546 nameList.clear();
547 otherList.clear();
548 accountAttributesList.clear();
549
550 if (personaSearchTask != null) {
551 personaSearchTask.cancel(Boolean.TRUE);
552 personaSearchTask = null;
553 }
554
555 // clear the panel
556 this.removeAll();
557 this.setLayout(null);
558
559 m_gridBagLayout = new GridBagLayout();
560 m_constraints = new GridBagConstraints();
561
562 m_constraints.anchor = GridBagConstraints.LINE_START;
563 m_constraints.gridy = 0;
564 m_constraints.gridx = 0;
565 m_constraints.weighty = 0.0;
566 m_constraints.weightx = 0.0; // keep components fixed horizontally.
567 m_constraints.insets = new java.awt.Insets(0, ContentViewerDefaults.getSectionIndent(), 0, 0);
568 m_constraints.fill = GridBagConstraints.NONE;
569
570 }
571
580 private ImageIcon getImageFromArtifact(BlackboardArtifact artifact) {
581 ImageIcon imageIcon = defaultImage;
582
583 if (artifact == null) {
584 return imageIcon;
585 }
586
587 BlackboardArtifact.ARTIFACT_TYPE artifactType = BlackboardArtifact.ARTIFACT_TYPE.fromID(artifact.getArtifactTypeID());
588 if (artifactType != BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT) {
589 return imageIcon;
590 }
591
592 try {
593 for (Content content : artifact.getChildren()) {
594 if (content instanceof AbstractFile) {
595 AbstractFile file = (AbstractFile) content;
596
597 try {
598 BufferedImage image = ImageIO.read(new File(file.getLocalAbsPath()));
599 imageIcon = new ImageIcon(image);
600 break;
601 } catch (IOException ex) {
602 // ImageIO.read will throw an IOException if file is not an image
603 // therefore we don't need to report this exception just try
604 // the next file.
605 }
606 }
607 }
608 } catch (TskCoreException ex) {
609 logger.log(Level.WARNING, String.format("Unable to load image for contact: %d", artifact.getId()), ex);
610 }
611
612 return imageIcon;
613 }
614
619 private class ContactPersonaSearcherTask extends SwingWorker<Map<Persona, ArrayList<CentralRepoAccount>>, Void> {
620
621 private final BlackboardArtifact artifact;
622 private final List<CentralRepoAccount> uniqueAccountsList = new ArrayList<>();
623
630 ContactPersonaSearcherTask(BlackboardArtifact artifact) {
631 this.artifact = artifact;
632 }
633
634 @Override
635 protected Map<Persona, ArrayList<CentralRepoAccount>> doInBackground() throws Exception {
636
637 Map<Persona, ArrayList<CentralRepoAccount>> uniquePersonas = new HashMap<>();
638 CommunicationsManager commManager = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager();
639 List<Account> contactAccountsList = commManager.getAccountsRelatedToArtifact(artifact);
640
641 for (Account account : contactAccountsList) {
642 try {
643 if (isCancelled()) {
644 return new HashMap<>();
645 }
646
647 // make a list of all unique accounts for this contact
648 if (!account.getAccountType().equals(Account.Type.DEVICE)) {
649 Optional<CentralRepoAccount.CentralRepoAccountType> optCrAccountType = CentralRepository.getInstance().getAccountTypeByName(account.getAccountType().getTypeName());
650 if (optCrAccountType.isPresent()) {
651 CentralRepoAccount crAccount = CentralRepository.getInstance().getAccount(optCrAccountType.get(), account.getTypeSpecificID());
652
653 if (crAccount != null && uniqueAccountsList.contains(crAccount) == false) {
654 uniqueAccountsList.add(crAccount);
655 }
656 }
657 }
658
659 Collection<PersonaAccount> personaAccounts = PersonaAccount.getPersonaAccountsForAccount(account);
660 if (personaAccounts != null && !personaAccounts.isEmpty()) {
661 // get personas for the account
662 Collection<Persona> personas
663 = personaAccounts
664 .stream()
666 .collect(Collectors.toList());
667
668 // make a list of unique personas, along with all their accounts
669 for (Persona persona : personas) {
670 if (uniquePersonas.containsKey(persona) == false) {
671 Collection<CentralRepoAccount> accounts = persona.getPersonaAccounts()
672 .stream()
674 .collect(Collectors.toList());
675
676 ArrayList<CentralRepoAccount> personaAccountsList = new ArrayList<>(accounts);
677 uniquePersonas.put(persona, personaAccountsList);
678 }
679 }
680 }
681 } catch (InvalidAccountIDException ex) {
682 // Do nothing, the account has an identifier that not an
683 // acceptable format for the cr.
684 }
685 }
686
687 return uniquePersonas;
688 }
689
690 @Override
691 protected void done() {
692
693 Map<Persona, ArrayList<CentralRepoAccount>> personasMap;
694 try {
695 personasMap = super.get();
696
697 if (this.isCancelled()) {
698 return;
699 }
700
702 contactUniquePersonasMap.putAll(personasMap);
705
707
708 } catch (CancellationException ex) {
709 logger.log(Level.INFO, "Persona searching was canceled."); //NON-NLS
710 } catch (InterruptedException ex) {
711 logger.log(Level.INFO, "Persona searching was interrupted."); //NON-NLS
712 } catch (ExecutionException ex) {
713 logger.log(Level.SEVERE, "Fatal error during Persona search.", ex); //NON-NLS
714 }
715
716 }
717 }
718
723 private class PersonaUIComponents {
724
725 private final JLabel personaNameLabel;
726 private final JButton personaActionButton;
727
734 PersonaUIComponents(JLabel personaNameLabel, JButton personaActionButton) {
735 this.personaNameLabel = personaNameLabel;
736 this.personaActionButton = personaActionButton;
737 }
738
744 public JLabel getPersonaNameLabel() {
745 return personaNameLabel;
746 }
747
753 public JButton getPersonaActionButton() {
754 return personaActionButton;
755 }
756 }
757
761 private class CreatePersonaButtonListener implements ActionListener {
762
763 private final Component parentComponent;
765
771 CreatePersonaButtonListener(Component parentComponent, PersonaUIComponents personaUIComponents) {
772 this.personaUIComponents = personaUIComponents;
773 this.parentComponent = parentComponent;
774 }
775
776 @NbBundle.Messages({
777 "ContactArtifactViewer_persona_account_justification=Account found in Contact artifact",
778 "# {0} - accountIdentifer",
779 "ContactArtifactViewer_id_not_found_in_cr=Unable to find account(s) associated with contact {0} in the Central Repository."
780 })
781
782 @Override
783 public void actionPerformed(java.awt.event.ActionEvent evt) {
784 // Launch the Persona Create dialog - do not display immediately
786 PersonaDetailsMode.CREATE, null, new PersonaCreateCallbackImpl(parentComponent, personaUIComponents), false);
787
788 // Pre populate the persona name and accounts if we have them.
789 PersonaDetailsPanel personaPanel = createPersonaDialog.getDetailsPanel();
790
791 if (contactName != null) {
792 personaPanel.setPersonaName(contactName);
793 }
794
795 // pass the list of accounts to the dialog
797 personaPanel.addAccount(account, Bundle.ContactArtifactViewer_persona_account_justification(), Persona.Confidence.HIGH);
798 }
799
800 if (contactName != null && contactUniqueAccountsList.isEmpty()) {
801 createPersonaDialog.setStartupPopupMessage(Bundle.ContactArtifactViewer_id_not_found_in_cr(contactName));
802 }
803
804 // display the dialog now
805 createPersonaDialog.display();
806 }
807 }
808
812 private class ViewPersonaButtonListener implements ActionListener {
813
814 private final Persona persona;
815 private final Component parentComponent;
816
822 ViewPersonaButtonListener(Component parentComponent, Persona persona) {
823 this.persona = persona;
824 this.parentComponent = parentComponent;
825 }
826
827 @Override
828 public void actionPerformed(java.awt.event.ActionEvent evt) {
830 PersonaDetailsMode.VIEW, persona, new PersonaViewCallbackImpl());
831 }
832 }
833
837 class PersonaCreateCallbackImpl implements PersonaDetailsDialogCallback {
838
839 private final Component parentComponent;
840 private final PersonaUIComponents personaUIComponents;
841
847 PersonaCreateCallbackImpl(Component parentComponent, PersonaUIComponents personaUIComponents) {
848 this.parentComponent = parentComponent;
849 this.personaUIComponents = personaUIComponents;
850 }
851
852 @Override
853 public void callback(Persona persona) {
854 JButton personaButton = personaUIComponents.getPersonaActionButton();
855 if (persona != null) {
856 // update the persona name label with newly created persona,
857 // and change the button to a "View" button
858 personaUIComponents.getPersonaNameLabel().setText(persona.getName());
859 personaUIComponents.getPersonaActionButton().setText(Bundle.ContactArtifactViewer_persona_button_view());
860
861 // replace action listener with a View button listener
862 for (ActionListener act : personaButton.getActionListeners()) {
863 personaButton.removeActionListener(act);
864 }
865 personaButton.addActionListener(new ViewPersonaButtonListener(parentComponent, persona));
866
867 }
868
869 personaButton.getParent().revalidate();
870 personaButton.getParent().repaint();
871 }
872 }
873
877 class PersonaViewCallbackImpl implements PersonaDetailsDialogCallback {
878
879 @Override
880 public void callback(Persona persona) {
881 // nothing to do
882 }
883 }
884
885 // Variables declaration - do not modify//GEN-BEGIN:variables
886 // End of variables declaration//GEN-END:variables
887}
static Collection< PersonaAccount > getPersonaAccountsForAccount(long accountId)
boolean addAccount(CentralRepoAccount account, String justification, Persona.Confidence confidence)
void updateContactName(GridBagLayout contactPanelLayout, GridBagConstraints contactPanelConstraints)
final Map< Persona, ArrayList< CentralRepoAccount > > contactUniquePersonasMap
void showPersona(Persona persona, int matchNumber, List< CentralRepoAccount > missingAccountsList, GridBagLayout gridBagLayout, GridBagConstraints constraints)
void updateContactMethodSection(List< BlackboardAttribute > sectionAttributesList, String sectionHeader, GridBagLayout contactPanelLayout, GridBagConstraints contactPanelConstraints)
void updateContactImage(GridBagLayout contactPanelLayout, GridBagConstraints contactPanelConstraints)
synchronized static Logger getLogger(String name)
Definition Logger.java:124
Optional< CentralRepoAccountType > getAccountTypeByName(String accountTypeName)
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.